Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
ac7ff4f
Add the -X frozen_modules CLI option and PyConfig.use_frozen_modules.
ericsnowcurrently Aug 31, 2021
7d2a470
Ignore frozen modules depending on "-X frozen_modules".
ericsnowcurrently Aug 31, 2021
aacaf24
Explicitly control PyConfig.use_frozen_modules during tests.
ericsnowcurrently Sep 1, 2021
5a6e40c
Factor out is_essential_frozen_module().
ericsnowcurrently Sep 13, 2021
4da6302
Treat __main__ as an essential frozen module.
ericsnowcurrently Sep 7, 2021
26469e5
Look up $_PYTHONTESTFROZENMODULES using getenv() instead of in os.env…
ericsnowcurrently Sep 7, 2021
f274b1c
Add zipimport to the list of essential frozen modules.
ericsnowcurrently Sep 7, 2021
6881cb8
Flip around the arg to the "frozen_modules" test helper.
ericsnowcurrently Sep 8, 2021
785addf
Disable frozen modules if $_PYTHONTESTFROZENMODULES is 0.
ericsnowcurrently Sep 8, 2021
a8cb984
Add the "usefrozen" arg to CleanImport.__init__().
ericsnowcurrently Sep 8, 2021
6d9d469
Ignore decode errors in find_frozen().
ericsnowcurrently Sep 8, 2021
df19f79
Fix test_ctypes.
ericsnowcurrently Sep 8, 2021
abfef0b
Ensure we get the frozen module.
ericsnowcurrently Sep 13, 2021
e0258cf
Fix docstrings for the import test helpers.
ericsnowcurrently Sep 13, 2021
0fd66d4
Add a NEWS entry.
ericsnowcurrently Aug 31, 2021
30e8cd1
Remember the stdlib dir during startup (adding PyConfig.stdlib_dir).
ericsnowcurrently Jun 12, 2021
1a83ef6
Add _Py_GetMainConfig().
ericsnowcurrently Aug 31, 2021
3b57bca
Let _Py_GetStdlibDir() fall back to a config.
ericsnowcurrently Aug 31, 2021
b45e5f7
Add _PyConfig_InitImportConfig().
ericsnowcurrently Aug 31, 2021
2298dc0
Identify whether or not the executable is running installed (adding _…
ericsnowcurrently Aug 31, 2021
2b67c44
Default to "off" if in development.
ericsnowcurrently Aug 31, 2021
0933e4d
Add a NEWS entry.
ericsnowcurrently Aug 31, 2021
4823ad6
Fix test_embed for PyConfig.stdlib_dir.
ericsnowcurrently Sep 7, 2021
0e5c617
In _Py_GetStdlibDir(), treat "" as though it were NULL.
ericsnowcurrently Sep 7, 2021
d427bae
Fix test_embed for "Default to "off" if in development.".
ericsnowcurrently Sep 7, 2021
f6bd2fd
Fix test_cmd_line_script for "Default to "off" if in development.".
ericsnowcurrently Sep 7, 2021
965c7fe
_Py_IsInstalled -> _Py_IsDevelopmentEnv.
ericsnowcurrently Sep 7, 2021
4f49adc
Stop using the frozen helper in test_cmd_line_script.
ericsnowcurrently Sep 7, 2021
5297edc
Allow for a .exe suffix on the executable.
ericsnowcurrently Sep 9, 2021
2b6f978
Drop _Py_IsDevelopmentEnv().
ericsnowcurrently Sep 10, 2021
dc2aa34
Drop -_Py_GetStdlibDir() and PyConfig.stdlib_dir.
ericsnowcurrently Sep 10, 2021
218ba84
Default to "-X frozen_modules=off" if built with --with-debug.
ericsnowcurrently Sep 10, 2021
81b66c4
Fix test_embed.
ericsnowcurrently Sep 10, 2021
8a0e2d6
Fix the ASAN job.
ericsnowcurrently Sep 11, 2021
015035d
Fix the docs.
ericsnowcurrently Sep 13, 2021
7e2ce41
Drop unused changes.
ericsnowcurrently Sep 13, 2021
b73486a
Fix the Windows CI jobs.
ericsnowcurrently Sep 13, 2021
fc2123b
Fix test_embed on non-debug builds.
ericsnowcurrently Sep 13, 2021
c3ed104
Fix test_embed on non-debug builds (on Windows).
ericsnowcurrently Sep 14, 2021
9b110fd
Drop parse_env_var_flag().
ericsnowcurrently Sep 14, 2021
9df64c1
Don't use env var _PYTHONTESTFROZENMODULES when running _testembed.
ericsnowcurrently Sep 14, 2021
ccd468e
Do not use an env var to override PyConfig.use_frozen_modules.
ericsnowcurrently Sep 14, 2021
5bc6730
For now, always default to "-X frozen_modules=off".
ericsnowcurrently Sep 14, 2021
f50476c
Change PyConfig.use_frozen_modules from bool to int.
ericsnowcurrently Sep 14, 2021
0dcdb44
Fix use of _PyConfig_InitImportConfig().
ericsnowcurrently Sep 14, 2021
2ec9909
Drop a superfluous comment.
ericsnowcurrently Sep 14, 2021
80d8fcd
Fix a typo.
ericsnowcurrently Sep 14, 2021
aff01e6
Simplify a comment.
ericsnowcurrently Sep 14, 2021
7476d65
Simplify use_frozen().
ericsnowcurrently Sep 14, 2021
e3e5744
Fix a comment.
ericsnowcurrently Sep 14, 2021
669beac
Collapse some lines.
ericsnowcurrently Sep 14, 2021
c644012
Drop _Py_GetMainConfig().
ericsnowcurrently Sep 14, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Explicitly control PyConfig.use_frozen_modules during tests.
  • Loading branch information
ericsnowcurrently committed Sep 13, 2021
commit aacaf24fe8622aec29e1478f84b0b7a8082e31bb
18 changes: 15 additions & 3 deletions Lib/test/support/import_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import unittest
import warnings

from .os_helper import unlink
from .os_helper import unlink, EnvironmentVarGuard


@contextlib.contextmanager
Expand Down Expand Up @@ -109,7 +109,18 @@ def _save_and_block_module(name, orig_modules):
return saved


def import_fresh_module(name, fresh=(), blocked=(), deprecated=False):
@contextlib.contextmanager
def frozen_modules(*, disabled=False):
with EnvironmentVarGuard() as env:
os.environ = env
os.environ['_PYTHONTESTFROZENMODULES'] = '' if disabled else '1'
yield


def import_fresh_module(name, fresh=(), blocked=(), *,
deprecated=False,
usefrozen=False,
):
"""Import and return a module, deliberately bypassing sys.modules.

This function imports and returns a fresh copy of the named Python module
Expand Down Expand Up @@ -148,7 +159,8 @@ def import_fresh_module(name, fresh=(), blocked=(), deprecated=False):
for blocked_name in blocked:
if not _save_and_block_module(blocked_name, orig_modules):
names_to_remove.append(blocked_name)
fresh_module = importlib.import_module(name)
with frozen_modules(disabled=not usefrozen):
fresh_module = importlib.import_module(name)
except ImportError:
fresh_module = None
finally:
Expand Down
7 changes: 4 additions & 3 deletions Lib/test/test_frozen.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,17 @@

import sys
import unittest
from test.support import captured_stdout
from test.support import captured_stdout, import_helper


class TestFrozen(unittest.TestCase):
def test_frozen(self):
name = '__hello__'
if name in sys.modules:
del sys.modules[name]
with captured_stdout() as out:
import __hello__
with import_helper.frozen_modules():
with captured_stdout() as out:
import __hello__
self.assertEqual(out.getvalue(), 'Hello world!\n')


Expand Down
8 changes: 6 additions & 2 deletions Lib/test/test_importlib/frozen/test_finder.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@
import unittest
import warnings

from test.support import import_helper


class FindSpecTests(abc.FinderTests):

"""Test finding frozen modules."""

def find(self, name, path=None):
finder = self.machinery.FrozenImporter
return finder.find_spec(name, path)
with import_helper.frozen_modules():
return finder.find_spec(name, path)

def test_module(self):
name = '__hello__'
Expand Down Expand Up @@ -52,7 +55,8 @@ def find(self, name, path=None):
finder = self.machinery.FrozenImporter
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
return finder.find_module(name, path)
with import_helper.frozen_modules():
return finder.find_module(name, path)

def test_module(self):
name = '__hello__'
Expand Down
211 changes: 117 additions & 94 deletions Lib/test/test_importlib/frozen/test_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,54 @@

machinery = util.import_importlib('importlib.machinery')

from test.support import captured_stdout
from test.support import captured_stdout, import_helper
import contextlib
import types
import unittest
import warnings


@contextlib.contextmanager
def deprecated():
with warnings.catch_warnings():
warnings.simplefilter('ignore', DeprecationWarning)
yield


@contextlib.contextmanager
def fresh(name, *, oldapi=False):
with util.uncache(name):
with import_helper.frozen_modules():
with captured_stdout() as stdout:
if oldapi:
with deprecated():
yield stdout
else:
yield stdout


class ExecModuleTests(abc.LoaderTests):

def exec_module(self, name):
with util.uncache(name), captured_stdout() as stdout:
spec = self.machinery.ModuleSpec(
name, self.machinery.FrozenImporter, origin='frozen',
is_package=self.machinery.FrozenImporter.is_package(name))
module = types.ModuleType(name)
module.__spec__ = spec
assert not hasattr(module, 'initialized')
with import_helper.frozen_modules():
is_package = self.machinery.FrozenImporter.is_package(name)
spec = self.machinery.ModuleSpec(
name,
self.machinery.FrozenImporter,
origin='frozen',
is_package=is_package,
)
module = types.ModuleType(name)
module.__spec__ = spec
assert not hasattr(module, 'initialized')

with fresh(name) as stdout:
self.machinery.FrozenImporter.exec_module(module)
self.assertTrue(module.initialized)
self.assertTrue(hasattr(module, '__spec__'))
self.assertEqual(module.__spec__.origin, 'frozen')
return module, stdout.getvalue()

self.assertTrue(module.initialized)
self.assertTrue(hasattr(module, '__spec__'))
self.assertEqual(module.__spec__.origin, 'frozen')
return module, stdout.getvalue()

def test_module(self):
name = '__hello__'
Expand All @@ -50,20 +77,19 @@ def test_lacking_parent(self):
name = '__phello__.spam'
with util.uncache('__phello__'):
module, output = self.exec_module(name)
check = {'__name__': name}
for attr, value in check.items():
attr_value = getattr(module, attr)
self.assertEqual(attr_value, value,
'for {name}.{attr}, {given} != {expected!r}'.format(
name=name, attr=attr, given=attr_value,
expected=value))
self.assertEqual(output, 'Hello world!\n')
check = {'__name__': name}
for attr, value in check.items():
attr_value = getattr(module, attr)
self.assertEqual(attr_value, value,
'for {name}.{attr}, {given} != {expected!r}'.format(
name=name, attr=attr, given=attr_value,
expected=value))
self.assertEqual(output, 'Hello world!\n')

def test_module_repr(self):
name = '__hello__'
module, output = self.exec_module(name)
with warnings.catch_warnings():
warnings.simplefilter('ignore', DeprecationWarning)
with deprecated():
repr_str = self.machinery.FrozenImporter.module_repr(module)
self.assertEqual(repr_str,
"<module '__hello__' (frozen)>")
Expand All @@ -78,7 +104,8 @@ def test_module_repr_indirect(self):
test_state_after_failure = None

def test_unloadable(self):
assert self.machinery.FrozenImporter.find_spec('_not_real') is None
with import_helper.frozen_modules():
assert self.machinery.FrozenImporter.find_spec('_not_real') is None
with self.assertRaises(ImportError) as cm:
self.exec_module('_not_real')
self.assertEqual(cm.exception.name, '_not_real')
Expand All @@ -91,84 +118,76 @@ def test_unloadable(self):

class LoaderTests(abc.LoaderTests):

def load_module(self, name):
with fresh(name, oldapi=True) as stdout:
module = self.machinery.FrozenImporter.load_module(name)
return module, stdout

def test_module(self):
with util.uncache('__hello__'), captured_stdout() as stdout:
with warnings.catch_warnings():
warnings.simplefilter('ignore', DeprecationWarning)
module = self.machinery.FrozenImporter.load_module('__hello__')
check = {'__name__': '__hello__',
'__package__': '',
'__loader__': self.machinery.FrozenImporter,
}
for attr, value in check.items():
self.assertEqual(getattr(module, attr), value)
self.assertEqual(stdout.getvalue(), 'Hello world!\n')
self.assertFalse(hasattr(module, '__file__'))
module, stdout = self.load_module('__hello__')
check = {'__name__': '__hello__',
'__package__': '',
'__loader__': self.machinery.FrozenImporter,
}
for attr, value in check.items():
self.assertEqual(getattr(module, attr), value)
self.assertEqual(stdout.getvalue(), 'Hello world!\n')
self.assertFalse(hasattr(module, '__file__'))

def test_package(self):
with util.uncache('__phello__'), captured_stdout() as stdout:
with warnings.catch_warnings():
warnings.simplefilter('ignore', DeprecationWarning)
module = self.machinery.FrozenImporter.load_module('__phello__')
check = {'__name__': '__phello__',
'__package__': '__phello__',
'__path__': [],
'__loader__': self.machinery.FrozenImporter,
}
for attr, value in check.items():
attr_value = getattr(module, attr)
self.assertEqual(attr_value, value,
"for __phello__.%s, %r != %r" %
(attr, attr_value, value))
self.assertEqual(stdout.getvalue(), 'Hello world!\n')
self.assertFalse(hasattr(module, '__file__'))
module, stdout = self.load_module('__phello__')
check = {'__name__': '__phello__',
'__package__': '__phello__',
'__path__': [],
'__loader__': self.machinery.FrozenImporter,
}
for attr, value in check.items():
attr_value = getattr(module, attr)
self.assertEqual(attr_value, value,
"for __phello__.%s, %r != %r" %
(attr, attr_value, value))
self.assertEqual(stdout.getvalue(), 'Hello world!\n')
self.assertFalse(hasattr(module, '__file__'))

def test_lacking_parent(self):
with util.uncache('__phello__', '__phello__.spam'), \
captured_stdout() as stdout:
with warnings.catch_warnings():
warnings.simplefilter('ignore', DeprecationWarning)
module = self.machinery.FrozenImporter.load_module('__phello__.spam')
check = {'__name__': '__phello__.spam',
'__package__': '__phello__',
'__loader__': self.machinery.FrozenImporter,
}
for attr, value in check.items():
attr_value = getattr(module, attr)
self.assertEqual(attr_value, value,
"for __phello__.spam.%s, %r != %r" %
(attr, attr_value, value))
self.assertEqual(stdout.getvalue(), 'Hello world!\n')
self.assertFalse(hasattr(module, '__file__'))
with util.uncache('__phello__'):
module, stdout = self.load_module('__phello__.spam')
check = {'__name__': '__phello__.spam',
'__package__': '__phello__',
'__loader__': self.machinery.FrozenImporter,
}
for attr, value in check.items():
attr_value = getattr(module, attr)
self.assertEqual(attr_value, value,
"for __phello__.spam.%s, %r != %r" %
(attr, attr_value, value))
self.assertEqual(stdout.getvalue(), 'Hello world!\n')
self.assertFalse(hasattr(module, '__file__'))

def test_module_reuse(self):
with util.uncache('__hello__'), captured_stdout() as stdout:
with warnings.catch_warnings():
warnings.simplefilter('ignore', DeprecationWarning)
module1 = self.machinery.FrozenImporter.load_module('__hello__')
module2 = self.machinery.FrozenImporter.load_module('__hello__')
self.assertIs(module1, module2)
self.assertEqual(stdout.getvalue(),
'Hello world!\nHello world!\n')
with fresh('__hello__', oldapi=True) as stdout:
module1 = self.machinery.FrozenImporter.load_module('__hello__')
module2 = self.machinery.FrozenImporter.load_module('__hello__')
self.assertIs(module1, module2)
self.assertEqual(stdout.getvalue(),
'Hello world!\nHello world!\n')

def test_module_repr(self):
with util.uncache('__hello__'), captured_stdout():
with warnings.catch_warnings():
warnings.simplefilter('ignore', DeprecationWarning)
module = self.machinery.FrozenImporter.load_module('__hello__')
repr_str = self.machinery.FrozenImporter.module_repr(module)
self.assertEqual(repr_str,
"<module '__hello__' (frozen)>")
with fresh('__hello__', oldapi=True) as stdout:
module = self.machinery.FrozenImporter.load_module('__hello__')
repr_str = self.machinery.FrozenImporter.module_repr(module)
self.assertEqual(repr_str,
"<module '__hello__' (frozen)>")

# No way to trigger an error in a frozen module.
test_state_after_failure = None

def test_unloadable(self):
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
assert self.machinery.FrozenImporter.find_module('_not_real') is None
with import_helper.frozen_modules():
with deprecated():
assert self.machinery.FrozenImporter.find_module('_not_real') is None
with self.assertRaises(ImportError) as cm:
self.machinery.FrozenImporter.load_module('_not_real')
self.load_module('_not_real')
self.assertEqual(cm.exception.name, '_not_real')


Expand All @@ -185,31 +204,35 @@ def test_get_code(self):
# Make sure that the code object is good.
name = '__hello__'
with captured_stdout() as stdout:
code = self.machinery.FrozenImporter.get_code(name)
mod = types.ModuleType(name)
exec(code, mod.__dict__)
self.assertTrue(hasattr(mod, 'initialized'))
self.assertEqual(stdout.getvalue(), 'Hello world!\n')
with import_helper.frozen_modules():
code = self.machinery.FrozenImporter.get_code(name)
mod = types.ModuleType(name)
exec(code, mod.__dict__)
self.assertTrue(hasattr(mod, 'initialized'))
self.assertEqual(stdout.getvalue(), 'Hello world!\n')

def test_get_source(self):
# Should always return None.
result = self.machinery.FrozenImporter.get_source('__hello__')
with import_helper.frozen_modules():
result = self.machinery.FrozenImporter.get_source('__hello__')
self.assertIsNone(result)

def test_is_package(self):
# Should be able to tell what is a package.
test_for = (('__hello__', False), ('__phello__', True),
('__phello__.spam', False))
for name, is_package in test_for:
result = self.machinery.FrozenImporter.is_package(name)
with import_helper.frozen_modules():
result = self.machinery.FrozenImporter.is_package(name)
self.assertEqual(bool(result), is_package)

def test_failure(self):
# Raise ImportError for modules that are not frozen.
for meth_name in ('get_code', 'get_source', 'is_package'):
method = getattr(self.machinery.FrozenImporter, meth_name)
with self.assertRaises(ImportError) as cm:
method('importlib')
with import_helper.frozen_modules():
method('importlib')
self.assertEqual(cm.exception.name, 'importlib')

(Frozen_ILTests,
Expand Down
Loading