diff options
Diffstat (limited to 'Lib/test/test_importlib')
34 files changed, 1354 insertions, 951 deletions
diff --git a/Lib/test/test_importlib/builtin/test_finder.py b/Lib/test/test_importlib/builtin/test_finder.py index 934562f..a2e6e1e 100644 --- a/Lib/test/test_importlib/builtin/test_finder.py +++ b/Lib/test/test_importlib/builtin/test_finder.py @@ -1,21 +1,21 @@ from .. import abc from .. import util -from . import util as builtin_util -frozen_machinery, source_machinery = util.import_importlib('importlib.machinery') +machinery = util.import_importlib('importlib.machinery') import sys import unittest +@unittest.skipIf(util.BUILTINS.good_name is None, 'no reasonable builtin module') class FindSpecTests(abc.FinderTests): """Test find_spec() for built-in modules.""" def test_module(self): # Common case. - with util.uncache(builtin_util.NAME): - found = self.machinery.BuiltinImporter.find_spec(builtin_util.NAME) + with util.uncache(util.BUILTINS.good_name): + found = self.machinery.BuiltinImporter.find_spec(util.BUILTINS.good_name) self.assertTrue(found) self.assertEqual(found.origin, 'built-in') @@ -39,23 +39,26 @@ class FindSpecTests(abc.FinderTests): def test_ignore_path(self): # The value for 'path' should always trigger a failed import. - with util.uncache(builtin_util.NAME): - spec = self.machinery.BuiltinImporter.find_spec(builtin_util.NAME, + with util.uncache(util.BUILTINS.good_name): + spec = self.machinery.BuiltinImporter.find_spec(util.BUILTINS.good_name, ['pkg']) self.assertIsNone(spec) -Frozen_FindSpecTests, Source_FindSpecTests = util.test_both(FindSpecTests, - machinery=[frozen_machinery, source_machinery]) +(Frozen_FindSpecTests, + Source_FindSpecTests + ) = util.test_both(FindSpecTests, machinery=machinery) + +@unittest.skipIf(util.BUILTINS.good_name is None, 'no reasonable builtin module') class FinderTests(abc.FinderTests): """Test find_module() for built-in modules.""" def test_module(self): # Common case. - with util.uncache(builtin_util.NAME): - found = self.machinery.BuiltinImporter.find_module(builtin_util.NAME) + with util.uncache(util.BUILTINS.good_name): + found = self.machinery.BuiltinImporter.find_module(util.BUILTINS.good_name) self.assertTrue(found) self.assertTrue(hasattr(found, 'load_module')) @@ -72,13 +75,15 @@ class FinderTests(abc.FinderTests): def test_ignore_path(self): # The value for 'path' should always trigger a failed import. - with util.uncache(builtin_util.NAME): - loader = self.machinery.BuiltinImporter.find_module(builtin_util.NAME, + with util.uncache(util.BUILTINS.good_name): + loader = self.machinery.BuiltinImporter.find_module(util.BUILTINS.good_name, ['pkg']) self.assertIsNone(loader) -Frozen_FinderTests, Source_FinderTests = util.test_both(FinderTests, - machinery=[frozen_machinery, source_machinery]) + +(Frozen_FinderTests, + Source_FinderTests + ) = util.test_both(FinderTests, machinery=machinery) if __name__ == '__main__': diff --git a/Lib/test/test_importlib/builtin/test_loader.py b/Lib/test/test_importlib/builtin/test_loader.py index 1f83574..1684ab6 100644 --- a/Lib/test/test_importlib/builtin/test_loader.py +++ b/Lib/test/test_importlib/builtin/test_loader.py @@ -1,14 +1,13 @@ from .. import abc from .. import util -from . import util as builtin_util -frozen_machinery, source_machinery = util.import_importlib('importlib.machinery') +machinery = util.import_importlib('importlib.machinery') import sys import types import unittest - +@unittest.skipIf(util.BUILTINS.good_name is None, 'no reasonable builtin module') class LoaderTests(abc.LoaderTests): """Test load_module() for built-in modules.""" @@ -29,8 +28,8 @@ class LoaderTests(abc.LoaderTests): def test_module(self): # Common case. - with util.uncache(builtin_util.NAME): - module = self.load_module(builtin_util.NAME) + with util.uncache(util.BUILTINS.good_name): + module = self.load_module(util.BUILTINS.good_name) self.verify(module) # Built-in modules cannot be a package. @@ -41,9 +40,9 @@ class LoaderTests(abc.LoaderTests): def test_module_reuse(self): # Test that the same module is used in a reload. - with util.uncache(builtin_util.NAME): - module1 = self.load_module(builtin_util.NAME) - module2 = self.load_module(builtin_util.NAME) + with util.uncache(util.BUILTINS.good_name): + module1 = self.load_module(util.BUILTINS.good_name) + module2 = self.load_module(util.BUILTINS.good_name) self.assertIs(module1, module2) def test_unloadable(self): @@ -66,40 +65,44 @@ class LoaderTests(abc.LoaderTests): self.assertEqual(cm.exception.name, module_name) -Frozen_LoaderTests, Source_LoaderTests = util.test_both(LoaderTests, - machinery=[frozen_machinery, source_machinery]) +(Frozen_LoaderTests, + Source_LoaderTests + ) = util.test_both(LoaderTests, machinery=machinery) +@unittest.skipIf(util.BUILTINS.good_name is None, 'no reasonable builtin module') class InspectLoaderTests: """Tests for InspectLoader methods for BuiltinImporter.""" def test_get_code(self): # There is no code object. - result = self.machinery.BuiltinImporter.get_code(builtin_util.NAME) + result = self.machinery.BuiltinImporter.get_code(util.BUILTINS.good_name) self.assertIsNone(result) def test_get_source(self): # There is no source. - result = self.machinery.BuiltinImporter.get_source(builtin_util.NAME) + result = self.machinery.BuiltinImporter.get_source(util.BUILTINS.good_name) self.assertIsNone(result) def test_is_package(self): # Cannot be a package. - result = self.machinery.BuiltinImporter.is_package(builtin_util.NAME) + result = self.machinery.BuiltinImporter.is_package(util.BUILTINS.good_name) self.assertFalse(result) + @unittest.skipIf(util.BUILTINS.bad_name is None, 'all modules are built in') def test_not_builtin(self): # Modules not built-in should raise ImportError. for meth_name in ('get_code', 'get_source', 'is_package'): method = getattr(self.machinery.BuiltinImporter, meth_name) with self.assertRaises(ImportError) as cm: - method(builtin_util.BAD_NAME) - self.assertRaises(builtin_util.BAD_NAME) + method(util.BUILTINS.bad_name) + self.assertRaises(util.BUILTINS.bad_name) + -Frozen_InspectLoaderTests, Source_InspectLoaderTests = util.test_both( - InspectLoaderTests, - machinery=[frozen_machinery, source_machinery]) +(Frozen_InspectLoaderTests, + Source_InspectLoaderTests + ) = util.test_both(InspectLoaderTests, machinery=machinery) if __name__ == '__main__': diff --git a/Lib/test/test_importlib/builtin/util.py b/Lib/test/test_importlib/builtin/util.py deleted file mode 100644 index 5704699..0000000 --- a/Lib/test/test_importlib/builtin/util.py +++ /dev/null @@ -1,7 +0,0 @@ -import sys - -assert 'errno' in sys.builtin_module_names -NAME = 'errno' - -assert 'importlib' not in sys.builtin_module_names -BAD_NAME = 'importlib' diff --git a/Lib/test/test_importlib/extension/test_case_sensitivity.py b/Lib/test/test_importlib/extension/test_case_sensitivity.py index bb2528e..706c3e4 100644 --- a/Lib/test/test_importlib/extension/test_case_sensitivity.py +++ b/Lib/test/test_importlib/extension/test_case_sensitivity.py @@ -1,25 +1,24 @@ -from importlib import _bootstrap +from importlib import _bootstrap_external import sys from test import support import unittest from .. import util -from . import util as ext_util -frozen_machinery, source_machinery = util.import_importlib('importlib.machinery') +machinery = util.import_importlib('importlib.machinery') # XXX find_spec tests -@unittest.skipIf(ext_util.FILENAME is None, '_testcapi not available') +@unittest.skipIf(util.EXTENSIONS.filename is None, '_testcapi not available') @util.case_insensitive_tests class ExtensionModuleCaseSensitivityTest: def find_module(self): - good_name = ext_util.NAME + good_name = util.EXTENSIONS.name bad_name = good_name.upper() assert good_name != bad_name - finder = self.machinery.FileFinder(ext_util.PATH, + finder = self.machinery.FileFinder(util.EXTENSIONS.path, (self.machinery.ExtensionFileLoader, self.machinery.EXTENSION_SUFFIXES)) return finder.find_module(bad_name) @@ -27,7 +26,7 @@ class ExtensionModuleCaseSensitivityTest: def test_case_sensitive(self): with support.EnvironmentVarGuard() as env: env.unset('PYTHONCASEOK') - if b'PYTHONCASEOK' in _bootstrap._os.environ: + if b'PYTHONCASEOK' in _bootstrap_external._os.environ: self.skipTest('os.environ changes not reflected in ' '_os.environ') loader = self.find_module() @@ -36,15 +35,16 @@ class ExtensionModuleCaseSensitivityTest: def test_case_insensitivity(self): with support.EnvironmentVarGuard() as env: env.set('PYTHONCASEOK', '1') - if b'PYTHONCASEOK' not in _bootstrap._os.environ: + if b'PYTHONCASEOK' not in _bootstrap_external._os.environ: self.skipTest('os.environ changes not reflected in ' '_os.environ') loader = self.find_module() self.assertTrue(hasattr(loader, 'load_module')) -Frozen_ExtensionCaseSensitivity, Source_ExtensionCaseSensitivity = util.test_both( - ExtensionModuleCaseSensitivityTest, - machinery=[frozen_machinery, source_machinery]) + +(Frozen_ExtensionCaseSensitivity, + Source_ExtensionCaseSensitivity + ) = util.test_both(ExtensionModuleCaseSensitivityTest, machinery=machinery) if __name__ == '__main__': diff --git a/Lib/test/test_importlib/extension/test_finder.py b/Lib/test/test_importlib/extension/test_finder.py index 990f29c..71bf67f 100644 --- a/Lib/test/test_importlib/extension/test_finder.py +++ b/Lib/test/test_importlib/extension/test_finder.py @@ -1,8 +1,7 @@ from .. import abc -from .. import util as test_util -from . import util +from .. import util -machinery = test_util.import_importlib('importlib.machinery') +machinery = util.import_importlib('importlib.machinery') import unittest import warnings @@ -14,7 +13,7 @@ class FinderTests(abc.FinderTests): """Test the finder for extension modules.""" def find_module(self, fullname): - importer = self.machinery.FileFinder(util.PATH, + importer = self.machinery.FileFinder(util.EXTENSIONS.path, (self.machinery.ExtensionFileLoader, self.machinery.EXTENSION_SUFFIXES)) with warnings.catch_warnings(): @@ -22,7 +21,7 @@ class FinderTests(abc.FinderTests): return importer.find_module(fullname) def test_module(self): - self.assertTrue(self.find_module(util.NAME)) + self.assertTrue(self.find_module(util.EXTENSIONS.name)) # No extension module as an __init__ available for testing. test_package = test_package_in_package = None @@ -36,8 +35,10 @@ class FinderTests(abc.FinderTests): def test_failure(self): self.assertIsNone(self.find_module('asdfjkl;')) -Frozen_FinderTests, Source_FinderTests = test_util.test_both( - FinderTests, machinery=machinery) + +(Frozen_FinderTests, + Source_FinderTests + ) = util.test_both(FinderTests, machinery=machinery) if __name__ == '__main__': diff --git a/Lib/test/test_importlib/extension/test_loader.py b/Lib/test/test_importlib/extension/test_loader.py index fd9abf2..aefd050 100644 --- a/Lib/test/test_importlib/extension/test_loader.py +++ b/Lib/test/test_importlib/extension/test_loader.py @@ -1,4 +1,3 @@ -from . import util as ext_util from .. import abc from .. import util @@ -15,8 +14,8 @@ class LoaderTests(abc.LoaderTests): """Test load_module() for extension modules.""" def setUp(self): - self.loader = self.machinery.ExtensionFileLoader(ext_util.NAME, - ext_util.FILEPATH) + self.loader = self.machinery.ExtensionFileLoader(util.EXTENSIONS.name, + util.EXTENSIONS.file_path) def load_module(self, fullname): return self.loader.load_module(fullname) @@ -29,23 +28,23 @@ class LoaderTests(abc.LoaderTests): self.load_module('XXX') def test_equality(self): - other = self.machinery.ExtensionFileLoader(ext_util.NAME, - ext_util.FILEPATH) + other = self.machinery.ExtensionFileLoader(util.EXTENSIONS.name, + util.EXTENSIONS.file_path) self.assertEqual(self.loader, other) def test_inequality(self): - other = self.machinery.ExtensionFileLoader('_' + ext_util.NAME, - ext_util.FILEPATH) + other = self.machinery.ExtensionFileLoader('_' + util.EXTENSIONS.name, + util.EXTENSIONS.file_path) self.assertNotEqual(self.loader, other) def test_module(self): - with util.uncache(ext_util.NAME): - module = self.load_module(ext_util.NAME) - for attr, value in [('__name__', ext_util.NAME), - ('__file__', ext_util.FILEPATH), + with util.uncache(util.EXTENSIONS.name): + module = self.load_module(util.EXTENSIONS.name) + for attr, value in [('__name__', util.EXTENSIONS.name), + ('__file__', util.EXTENSIONS.file_path), ('__package__', '')]: self.assertEqual(getattr(module, attr), value) - self.assertIn(ext_util.NAME, sys.modules) + self.assertIn(util.EXTENSIONS.name, sys.modules) self.assertIsInstance(module.__loader__, self.machinery.ExtensionFileLoader) @@ -56,9 +55,9 @@ class LoaderTests(abc.LoaderTests): test_lacking_parent = None def test_module_reuse(self): - with util.uncache(ext_util.NAME): - module1 = self.load_module(ext_util.NAME) - module2 = self.load_module(ext_util.NAME) + with util.uncache(util.EXTENSIONS.name): + module1 = self.load_module(util.EXTENSIONS.name) + module2 = self.load_module(util.EXTENSIONS.name) self.assertIs(module1, module2) # No easy way to trigger a failure after a successful import. @@ -71,14 +70,15 @@ class LoaderTests(abc.LoaderTests): self.assertEqual(cm.exception.name, name) def test_is_package(self): - self.assertFalse(self.loader.is_package(ext_util.NAME)) + self.assertFalse(self.loader.is_package(util.EXTENSIONS.name)) for suffix in self.machinery.EXTENSION_SUFFIXES: path = os.path.join('some', 'path', 'pkg', '__init__' + suffix) loader = self.machinery.ExtensionFileLoader('pkg', path) self.assertTrue(loader.is_package('pkg')) -Frozen_LoaderTests, Source_LoaderTests = util.test_both( - LoaderTests, machinery=machinery) +(Frozen_LoaderTests, + Source_LoaderTests + ) = util.test_both(LoaderTests, machinery=machinery) diff --git a/Lib/test/test_importlib/extension/test_path_hook.py b/Lib/test/test_importlib/extension/test_path_hook.py index 49d6734..8f4b8bb 100644 --- a/Lib/test/test_importlib/extension/test_path_hook.py +++ b/Lib/test/test_importlib/extension/test_path_hook.py @@ -1,7 +1,6 @@ -from .. import util as test_util -from . import util +from .. import util -machinery = test_util.import_importlib('importlib.machinery') +machinery = util.import_importlib('importlib.machinery') import collections import sys @@ -22,10 +21,12 @@ class PathHookTests: def test_success(self): # Path hook should handle a directory where a known extension module # exists. - self.assertTrue(hasattr(self.hook(util.PATH), 'find_module')) + self.assertTrue(hasattr(self.hook(util.EXTENSIONS.path), 'find_module')) -Frozen_PathHooksTests, Source_PathHooksTests = test_util.test_both( - PathHookTests, machinery=machinery) + +(Frozen_PathHooksTests, + Source_PathHooksTests + ) = util.test_both(PathHookTests, machinery=machinery) if __name__ == '__main__': diff --git a/Lib/test/test_importlib/extension/util.py b/Lib/test/test_importlib/extension/util.py deleted file mode 100644 index 8d089f0..0000000 --- a/Lib/test/test_importlib/extension/util.py +++ /dev/null @@ -1,19 +0,0 @@ -from importlib import machinery -import os -import sys - -PATH = None -EXT = None -FILENAME = None -NAME = '_testcapi' -try: - for PATH in sys.path: - for EXT in machinery.EXTENSION_SUFFIXES: - FILENAME = NAME + EXT - FILEPATH = os.path.join(PATH, FILENAME) - if os.path.exists(os.path.join(PATH, FILENAME)): - raise StopIteration - else: - PATH = EXT = FILENAME = FILEPATH = None -except StopIteration: - pass diff --git a/Lib/test/test_importlib/frozen/test_finder.py b/Lib/test/test_importlib/frozen/test_finder.py index f9f97f3..519aa02 100644 --- a/Lib/test/test_importlib/frozen/test_finder.py +++ b/Lib/test/test_importlib/frozen/test_finder.py @@ -37,8 +37,10 @@ class FindSpecTests(abc.FinderTests): spec = self.find('<not real>') self.assertIsNone(spec) -Frozen_FindSpecTests, Source_FindSpecTests = util.test_both(FindSpecTests, - machinery=machinery) + +(Frozen_FindSpecTests, + Source_FindSpecTests + ) = util.test_both(FindSpecTests, machinery=machinery) class FinderTests(abc.FinderTests): @@ -72,8 +74,10 @@ class FinderTests(abc.FinderTests): loader = self.find('<not real>') self.assertIsNone(loader) -Frozen_FinderTests, Source_FinderTests = util.test_both(FinderTests, - machinery=machinery) + +(Frozen_FinderTests, + Source_FinderTests + ) = util.test_both(FinderTests, machinery=machinery) if __name__ == '__main__': diff --git a/Lib/test/test_importlib/frozen/test_loader.py b/Lib/test/test_importlib/frozen/test_loader.py index 7c01464..603c7d7 100644 --- a/Lib/test/test_importlib/frozen/test_loader.py +++ b/Lib/test/test_importlib/frozen/test_loader.py @@ -85,8 +85,10 @@ class ExecModuleTests(abc.LoaderTests): self.exec_module('_not_real') self.assertEqual(cm.exception.name, '_not_real') -Frozen_ExecModuleTests, Source_ExecModuleTests = util.test_both(ExecModuleTests, - machinery=machinery) + +(Frozen_ExecModuleTests, + Source_ExecModuleTests + ) = util.test_both(ExecModuleTests, machinery=machinery) class LoaderTests(abc.LoaderTests): @@ -175,8 +177,10 @@ class LoaderTests(abc.LoaderTests): self.machinery.FrozenImporter.load_module('_not_real') self.assertEqual(cm.exception.name, '_not_real') -Frozen_LoaderTests, Source_LoaderTests = util.test_both(LoaderTests, - machinery=machinery) + +(Frozen_LoaderTests, + Source_LoaderTests + ) = util.test_both(LoaderTests, machinery=machinery) class InspectLoaderTests: @@ -214,8 +218,9 @@ class InspectLoaderTests: method('importlib') self.assertEqual(cm.exception.name, 'importlib') -Frozen_ILTests, Source_ILTests = util.test_both(InspectLoaderTests, - machinery=machinery) +(Frozen_ILTests, + Source_ILTests + ) = util.test_both(InspectLoaderTests, machinery=machinery) if __name__ == '__main__': diff --git a/Lib/test/test_importlib/import_/test___loader__.py b/Lib/test/test_importlib/import_/test___loader__.py index 6df8010..4b18093 100644 --- a/Lib/test/test_importlib/import_/test___loader__.py +++ b/Lib/test/test_importlib/import_/test___loader__.py @@ -4,7 +4,6 @@ import types import unittest from .. import util -from . import util as import_util class SpecLoaderMock: @@ -12,6 +11,9 @@ class SpecLoaderMock: def find_spec(self, fullname, path=None, target=None): return machinery.ModuleSpec(fullname, self) + def create_module(self, spec): + return None + def exec_module(self, module): pass @@ -24,8 +26,10 @@ class SpecLoaderAttributeTests: module = self.__import__('blah') self.assertEqual(loader, module.__loader__) -Frozen_SpecTests, Source_SpecTests = util.test_both( - SpecLoaderAttributeTests, __import__=import_util.__import__) + +(Frozen_SpecTests, + Source_SpecTests + ) = util.test_both(SpecLoaderAttributeTests, __import__=util.__import__) class LoaderMock: @@ -62,8 +66,9 @@ class LoaderAttributeTests: self.assertEqual(loader, module.__loader__) -Frozen_Tests, Source_Tests = util.test_both(LoaderAttributeTests, - __import__=import_util.__import__) +(Frozen_Tests, + Source_Tests + ) = util.test_both(LoaderAttributeTests, __import__=util.__import__) if __name__ == '__main__': diff --git a/Lib/test/test_importlib/import_/test___package__.py b/Lib/test/test_importlib/import_/test___package__.py index 2e19725..c7d3a2a 100644 --- a/Lib/test/test_importlib/import_/test___package__.py +++ b/Lib/test/test_importlib/import_/test___package__.py @@ -6,7 +6,6 @@ of using the typical __path__/__name__ test). """ import unittest from .. import util -from . import util as import_util class Using__package__: @@ -70,17 +69,23 @@ class Using__package__: with self.assertRaises(TypeError): self.__import__('', globals, {}, ['relimport'], 1) + class Using__package__PEP302(Using__package__): mock_modules = util.mock_modules -Frozen_UsingPackagePEP302, Source_UsingPackagePEP302 = util.test_both( - Using__package__PEP302, __import__=import_util.__import__) -class Using__package__PEP302(Using__package__): +(Frozen_UsingPackagePEP302, + Source_UsingPackagePEP302 + ) = util.test_both(Using__package__PEP302, __import__=util.__import__) + + +class Using__package__PEP451(Using__package__): mock_modules = util.mock_spec -Frozen_UsingPackagePEP451, Source_UsingPackagePEP451 = util.test_both( - Using__package__PEP302, __import__=import_util.__import__) + +(Frozen_UsingPackagePEP451, + Source_UsingPackagePEP451 + ) = util.test_both(Using__package__PEP451, __import__=util.__import__) class Setting__package__: @@ -95,7 +100,7 @@ class Setting__package__: """ - __import__ = import_util.__import__[1] + __import__ = util.__import__['Source'] # [top-level] def test_top_level(self): diff --git a/Lib/test/test_importlib/import_/test_api.py b/Lib/test/test_importlib/import_/test_api.py index 439c105..7069d9e 100644 --- a/Lib/test/test_importlib/import_/test_api.py +++ b/Lib/test/test_importlib/import_/test_api.py @@ -1,5 +1,4 @@ from .. import util -from . import util as import_util from importlib import machinery import sys @@ -18,6 +17,10 @@ class BadSpecFinderLoader: return spec @staticmethod + def create_module(spec): + return None + + @staticmethod def exec_module(module): if module.__name__ == SUBMOD_NAME: raise ImportError('I cannot be loaded!') @@ -79,15 +82,19 @@ class APITest: class OldAPITests(APITest): bad_finder_loader = BadLoaderFinder -Frozen_OldAPITests, Source_OldAPITests = util.test_both( - OldAPITests, __import__=import_util.__import__) + +(Frozen_OldAPITests, + Source_OldAPITests + ) = util.test_both(OldAPITests, __import__=util.__import__) class SpecAPITests(APITest): bad_finder_loader = BadSpecFinderLoader -Frozen_SpecAPITests, Source_SpecAPITests = util.test_both( - SpecAPITests, __import__=import_util.__import__) + +(Frozen_SpecAPITests, + Source_SpecAPITests + ) = util.test_both(SpecAPITests, __import__=util.__import__) if __name__ == '__main__': diff --git a/Lib/test/test_importlib/import_/test_caching.py b/Lib/test/test_importlib/import_/test_caching.py index c292ee4..8079add 100644 --- a/Lib/test/test_importlib/import_/test_caching.py +++ b/Lib/test/test_importlib/import_/test_caching.py @@ -1,6 +1,5 @@ """Test that sys.modules is used properly by import.""" from .. import util -from . import util as import_util import sys from types import MethodType import unittest @@ -39,15 +38,17 @@ class UseCache: self.__import__(name) self.assertEqual(cm.exception.name, name) -Frozen_UseCache, Source_UseCache = util.test_both( - UseCache, __import__=import_util.__import__) + +(Frozen_UseCache, + Source_UseCache + ) = util.test_both(UseCache, __import__=util.__import__) class ImportlibUseCache(UseCache, unittest.TestCase): # Pertinent only to PEP 302; exec_module() doesn't return a module. - __import__ = import_util.__import__[1] + __import__ = util.__import__['Source'] def create_mock(self, *names, return_=None): mock = util.mock_modules(*names) diff --git a/Lib/test/test_importlib/import_/test_fromlist.py b/Lib/test/test_importlib/import_/test_fromlist.py index a755b75..8045465 100644 --- a/Lib/test/test_importlib/import_/test_fromlist.py +++ b/Lib/test/test_importlib/import_/test_fromlist.py @@ -1,6 +1,5 @@ """Test that the semantics relating to the 'fromlist' argument are correct.""" from .. import util -from . import util as import_util import unittest @@ -29,8 +28,10 @@ class ReturnValue: module = self.__import__('pkg.module', fromlist=['attr']) self.assertEqual(module.__name__, 'pkg.module') -Frozen_ReturnValue, Source_ReturnValue = util.test_both( - ReturnValue, __import__=import_util.__import__) + +(Frozen_ReturnValue, + Source_ReturnValue + ) = util.test_both(ReturnValue, __import__=util.__import__) class HandlingFromlist: @@ -121,8 +122,10 @@ class HandlingFromlist: self.assertEqual(module.module1.__name__, 'pkg.module1') self.assertEqual(module.module2.__name__, 'pkg.module2') -Frozen_FromList, Source_FromList = util.test_both( - HandlingFromlist, __import__=import_util.__import__) + +(Frozen_FromList, + Source_FromList + ) = util.test_both(HandlingFromlist, __import__=util.__import__) if __name__ == '__main__': diff --git a/Lib/test/test_importlib/import_/test_meta_path.py b/Lib/test/test_importlib/import_/test_meta_path.py index 5eeb145..c452cdd 100644 --- a/Lib/test/test_importlib/import_/test_meta_path.py +++ b/Lib/test/test_importlib/import_/test_meta_path.py @@ -1,5 +1,4 @@ from .. import util -from . import util as import_util import importlib._bootstrap import sys from types import MethodType @@ -46,8 +45,10 @@ class CallingOrder: self.assertEqual(len(w), 1) self.assertTrue(issubclass(w[-1].category, ImportWarning)) -Frozen_CallingOrder, Source_CallingOrder = util.test_both( - CallingOrder, __import__=import_util.__import__) + +(Frozen_CallingOrder, + Source_CallingOrder + ) = util.test_both(CallingOrder, __import__=util.__import__) class CallSignature: @@ -100,19 +101,25 @@ class CallSignature: self.assertEqual(args[0], mod_name) self.assertIs(args[1], path) + class CallSignaturePEP302(CallSignature): mock_modules = util.mock_modules finder_name = 'find_module' -Frozen_CallSignaturePEP302, Source_CallSignaturePEP302 = util.test_both( - CallSignaturePEP302, __import__=import_util.__import__) + +(Frozen_CallSignaturePEP302, + Source_CallSignaturePEP302 + ) = util.test_both(CallSignaturePEP302, __import__=util.__import__) + class CallSignaturePEP451(CallSignature): mock_modules = util.mock_spec finder_name = 'find_spec' -Frozen_CallSignaturePEP451, Source_CallSignaturePEP451 = util.test_both( - CallSignaturePEP451, __import__=import_util.__import__) + +(Frozen_CallSignaturePEP451, + Source_CallSignaturePEP451 + ) = util.test_both(CallSignaturePEP451, __import__=util.__import__) if __name__ == '__main__': diff --git a/Lib/test/test_importlib/import_/test_packages.py b/Lib/test/test_importlib/import_/test_packages.py index 55a5d14..3755b84 100644 --- a/Lib/test/test_importlib/import_/test_packages.py +++ b/Lib/test/test_importlib/import_/test_packages.py @@ -1,5 +1,4 @@ from .. import util -from . import util as import_util import sys import unittest import importlib @@ -102,8 +101,10 @@ class ParentModuleTests: finally: support.unload(subname) -Frozen_ParentTests, Source_ParentTests = util.test_both( - ParentModuleTests, __import__=import_util.__import__) + +(Frozen_ParentTests, + Source_ParentTests + ) = util.test_both(ParentModuleTests, __import__=util.__import__) if __name__ == '__main__': diff --git a/Lib/test/test_importlib/import_/test_path.py b/Lib/test/test_importlib/import_/test_path.py index 1274f8c..4359dd9 100644 --- a/Lib/test/test_importlib/import_/test_path.py +++ b/Lib/test/test_importlib/import_/test_path.py @@ -1,11 +1,12 @@ from .. import util -from . import util as import_util importlib = util.import_importlib('importlib') machinery = util.import_importlib('importlib.machinery') +import errno import os import sys +import tempfile from types import ModuleType import unittest import warnings @@ -58,7 +59,7 @@ class FinderTests: module = '<test module>' path = '<test path>' importer = util.mock_spec(module) - hook = import_util.mock_path_hook(path, importer=importer) + hook = util.mock_path_hook(path, importer=importer) with util.import_state(path_hooks=[hook]): loader = self.machinery.PathFinder.find_module(module, [path]) self.assertIs(loader, importer) @@ -83,7 +84,7 @@ class FinderTests: path = '' module = '<test module>' importer = util.mock_spec(module) - hook = import_util.mock_path_hook(os.getcwd(), importer=importer) + hook = util.mock_path_hook(os.getcwd(), importer=importer) with util.import_state(path=[path], path_hooks=[hook]): loader = self.machinery.PathFinder.find_module(module) self.assertIs(loader, importer) @@ -98,7 +99,7 @@ class FinderTests: new_path_importer_cache.pop(None, None) new_path_hooks = [zipimport.zipimporter, self.machinery.FileFinder.path_hook( - *self.importlib._bootstrap._get_supported_file_loaders())] + *self.importlib._bootstrap_external._get_supported_file_loaders())] missing = object() email = sys.modules.pop('email', missing) try: @@ -112,8 +113,74 @@ class FinderTests: if email is not missing: sys.modules['email'] = email -Frozen_FinderTests, Source_FinderTests = util.test_both( - FinderTests, importlib=importlib, machinery=machinery) + def test_finder_with_find_module(self): + class TestFinder: + def find_module(self, fullname): + return self.to_return + failing_finder = TestFinder() + failing_finder.to_return = None + path = 'testing path' + with util.import_state(path_importer_cache={path: failing_finder}): + self.assertIsNone( + self.machinery.PathFinder.find_spec('whatever', [path])) + success_finder = TestFinder() + success_finder.to_return = __loader__ + with util.import_state(path_importer_cache={path: success_finder}): + spec = self.machinery.PathFinder.find_spec('whatever', [path]) + self.assertEqual(spec.loader, __loader__) + + def test_finder_with_find_loader(self): + class TestFinder: + loader = None + portions = [] + def find_loader(self, fullname): + return self.loader, self.portions + path = 'testing path' + with util.import_state(path_importer_cache={path: TestFinder()}): + self.assertIsNone( + self.machinery.PathFinder.find_spec('whatever', [path])) + success_finder = TestFinder() + success_finder.loader = __loader__ + with util.import_state(path_importer_cache={path: success_finder}): + spec = self.machinery.PathFinder.find_spec('whatever', [path]) + self.assertEqual(spec.loader, __loader__) + + def test_finder_with_find_spec(self): + class TestFinder: + spec = None + def find_spec(self, fullname, target=None): + return self.spec + path = 'testing path' + with util.import_state(path_importer_cache={path: TestFinder()}): + self.assertIsNone( + self.machinery.PathFinder.find_spec('whatever', [path])) + success_finder = TestFinder() + success_finder.spec = self.machinery.ModuleSpec('whatever', __loader__) + with util.import_state(path_importer_cache={path: success_finder}): + got = self.machinery.PathFinder.find_spec('whatever', [path]) + self.assertEqual(got, success_finder.spec) + + @unittest.skipIf(sys.platform == 'win32', "cwd can't not exist on Windows") + def test_deleted_cwd(self): + # Issue #22834 + self.addCleanup(os.chdir, os.getcwd()) + try: + with tempfile.TemporaryDirectory() as path: + os.chdir(path) + except OSError as exc: + if exc.errno == errno.EINVAL: + self.skipTest("platform does not allow the deletion of the cwd") + raise + with util.import_state(path=['']): + # Do not want FileNotFoundError raised. + self.assertIsNone(self.machinery.PathFinder.find_spec('whatever')) + + + + +(Frozen_FinderTests, + Source_FinderTests + ) = util.test_both(FinderTests, importlib=importlib, machinery=machinery) class PathEntryFinderTests: @@ -136,8 +203,10 @@ class PathEntryFinderTests: path_hooks=[Finder]): self.machinery.PathFinder.find_spec('importlib') -Frozen_PEFTests, Source_PEFTests = util.test_both( - PathEntryFinderTests, machinery=machinery) + +(Frozen_PEFTests, + Source_PEFTests + ) = util.test_both(PathEntryFinderTests, machinery=machinery) if __name__ == '__main__': diff --git a/Lib/test/test_importlib/import_/test_relative_imports.py b/Lib/test/test_importlib/import_/test_relative_imports.py index b216e9c..28bb6f7 100644 --- a/Lib/test/test_importlib/import_/test_relative_imports.py +++ b/Lib/test/test_importlib/import_/test_relative_imports.py @@ -1,6 +1,5 @@ """Test relative imports (PEP 328).""" from .. import util -from . import util as import_util import sys import unittest @@ -208,8 +207,10 @@ class RelativeImports: with self.assertRaises(KeyError): self.__import__('sys', level=1) -Frozen_RelativeImports, Source_RelativeImports = util.test_both( - RelativeImports, __import__=import_util.__import__) + +(Frozen_RelativeImports, + Source_RelativeImports + ) = util.test_both(RelativeImports, __import__=util.__import__) if __name__ == '__main__': diff --git a/Lib/test/test_importlib/import_/util.py b/Lib/test/test_importlib/import_/util.py deleted file mode 100644 index dcb490f..0000000 --- a/Lib/test/test_importlib/import_/util.py +++ /dev/null @@ -1,20 +0,0 @@ -from .. import util - -frozen_importlib, source_importlib = util.import_importlib('importlib') - -import builtins -import functools -import importlib -import unittest - - -__import__ = staticmethod(builtins.__import__), staticmethod(source_importlib.__import__) - - -def mock_path_hook(*entries, importer): - """A mock sys.path_hooks entry.""" - def hook(entry): - if entry not in entries: - raise ImportError - return importer - return hook diff --git a/Lib/test/test_importlib/source/test_case_sensitivity.py b/Lib/test/test_importlib/source/test_case_sensitivity.py index efd3146..c274b38 100644 --- a/Lib/test/test_importlib/source/test_case_sensitivity.py +++ b/Lib/test/test_importlib/source/test_case_sensitivity.py @@ -1,6 +1,5 @@ """Test case-sensitivity (PEP 235).""" from .. import util -from . import util as source_util importlib = util.import_importlib('importlib') machinery = util.import_importlib('importlib.machinery') @@ -32,7 +31,7 @@ class CaseSensitivityTest: """Look for a module with matching and non-matching sensitivity.""" sensitive_pkg = 'sensitive.{0}'.format(self.name) insensitive_pkg = 'insensitive.{0}'.format(self.name.lower()) - context = source_util.create_modules(insensitive_pkg, sensitive_pkg) + context = util.create_modules(insensitive_pkg, sensitive_pkg) with context as mapping: sensitive_path = os.path.join(mapping['.root'], 'sensitive') insensitive_path = os.path.join(mapping['.root'], 'insensitive') @@ -43,7 +42,7 @@ class CaseSensitivityTest: def test_sensitive(self): with test_support.EnvironmentVarGuard() as env: env.unset('PYTHONCASEOK') - if b'PYTHONCASEOK' in self.importlib._bootstrap._os.environ: + if b'PYTHONCASEOK' in self.importlib._bootstrap_external._os.environ: self.skipTest('os.environ changes not reflected in ' '_os.environ') sensitive, insensitive = self.sensitivity_test() @@ -54,7 +53,7 @@ class CaseSensitivityTest: def test_insensitive(self): with test_support.EnvironmentVarGuard() as env: env.set('PYTHONCASEOK', '1') - if b'PYTHONCASEOK' not in self.importlib._bootstrap._os.environ: + if b'PYTHONCASEOK' not in self.importlib._bootstrap_external._os.environ: self.skipTest('os.environ changes not reflected in ' '_os.environ') sensitive, insensitive = self.sensitivity_test() @@ -63,20 +62,28 @@ class CaseSensitivityTest: self.assertIsNotNone(insensitive) self.assertIn(self.name, insensitive.get_filename(self.name)) + class CaseSensitivityTestPEP302(CaseSensitivityTest): def find(self, finder): return finder.find_module(self.name) -Frozen_CaseSensitivityTestPEP302, Source_CaseSensitivityTestPEP302 = util.test_both( - CaseSensitivityTestPEP302, importlib=importlib, machinery=machinery) + +(Frozen_CaseSensitivityTestPEP302, + Source_CaseSensitivityTestPEP302 + ) = util.test_both(CaseSensitivityTestPEP302, importlib=importlib, + machinery=machinery) + class CaseSensitivityTestPEP451(CaseSensitivityTest): def find(self, finder): found = finder.find_spec(self.name) return found.loader if found is not None else found -Frozen_CaseSensitivityTestPEP451, Source_CaseSensitivityTestPEP451 = util.test_both( - CaseSensitivityTestPEP451, importlib=importlib, machinery=machinery) + +(Frozen_CaseSensitivityTestPEP451, + Source_CaseSensitivityTestPEP451 + ) = util.test_both(CaseSensitivityTestPEP451, importlib=importlib, + machinery=machinery) if __name__ == '__main__': diff --git a/Lib/test/test_importlib/source/test_file_loader.py b/Lib/test/test_importlib/source/test_file_loader.py index 2d415f9..73f4c62 100644 --- a/Lib/test/test_importlib/source/test_file_loader.py +++ b/Lib/test/test_importlib/source/test_file_loader.py @@ -1,6 +1,5 @@ from .. import abc from .. import util -from . import util as source_util importlib = util.import_importlib('importlib') importlib_abc = util.import_importlib('importlib.abc') @@ -71,7 +70,7 @@ class SimpleTest(abc.LoaderTests): # [basic] def test_module(self): - with source_util.create_modules('_temp') as mapping: + with util.create_modules('_temp') as mapping: loader = self.machinery.SourceFileLoader('_temp', mapping['_temp']) with warnings.catch_warnings(): warnings.simplefilter('ignore', DeprecationWarning) @@ -83,7 +82,7 @@ class SimpleTest(abc.LoaderTests): self.assertEqual(getattr(module, attr), value) def test_package(self): - with source_util.create_modules('_pkg.__init__') as mapping: + with util.create_modules('_pkg.__init__') as mapping: loader = self.machinery.SourceFileLoader('_pkg', mapping['_pkg.__init__']) with warnings.catch_warnings(): @@ -98,7 +97,7 @@ class SimpleTest(abc.LoaderTests): def test_lacking_parent(self): - with source_util.create_modules('_pkg.__init__', '_pkg.mod')as mapping: + with util.create_modules('_pkg.__init__', '_pkg.mod')as mapping: loader = self.machinery.SourceFileLoader('_pkg.mod', mapping['_pkg.mod']) with warnings.catch_warnings(): @@ -115,7 +114,7 @@ class SimpleTest(abc.LoaderTests): return lambda name: fxn(name) + 1 def test_module_reuse(self): - with source_util.create_modules('_temp') as mapping: + with util.create_modules('_temp') as mapping: loader = self.machinery.SourceFileLoader('_temp', mapping['_temp']) with warnings.catch_warnings(): warnings.simplefilter('ignore', DeprecationWarning) @@ -139,7 +138,7 @@ class SimpleTest(abc.LoaderTests): attributes = ('__file__', '__path__', '__package__') value = '<test>' name = '_temp' - with source_util.create_modules(name) as mapping: + with util.create_modules(name) as mapping: orig_module = types.ModuleType(name) for attr in attributes: setattr(orig_module, attr, value) @@ -159,7 +158,7 @@ class SimpleTest(abc.LoaderTests): # [syntax error] def test_bad_syntax(self): - with source_util.create_modules('_temp') as mapping: + with util.create_modules('_temp') as mapping: with open(mapping['_temp'], 'w') as file: file.write('=') loader = self.machinery.SourceFileLoader('_temp', mapping['_temp']) @@ -190,11 +189,11 @@ class SimpleTest(abc.LoaderTests): if os.path.exists(pycache): shutil.rmtree(pycache) - @source_util.writes_bytecode_files + @util.writes_bytecode_files def test_timestamp_overflow(self): # When a modification timestamp is larger than 2**32, it should be # truncated rather than raise an OverflowError. - with source_util.create_modules('_temp') as mapping: + with util.create_modules('_temp') as mapping: source = mapping['_temp'] compiled = self.util.cache_from_source(source) with open(source, 'w') as f: @@ -236,9 +235,11 @@ class SimpleTest(abc.LoaderTests): warnings.simplefilter('ignore', DeprecationWarning) loader.load_module('bad name') -Frozen_SimpleTest, Source_SimpleTest = util.test_both( - SimpleTest, importlib=importlib, machinery=machinery, abc=importlib_abc, - util=importlib_util) + +(Frozen_SimpleTest, + Source_SimpleTest + ) = util.test_both(SimpleTest, importlib=importlib, machinery=machinery, + abc=importlib_abc, util=importlib_util) class BadBytecodeTest: @@ -275,45 +276,45 @@ class BadBytecodeTest: return bytecode_path def _test_empty_file(self, test, *, del_source=False): - with source_util.create_modules('_temp') as mapping: + with util.create_modules('_temp') as mapping: bc_path = self.manipulate_bytecode('_temp', mapping, lambda bc: b'', del_source=del_source) test('_temp', mapping, bc_path) - @source_util.writes_bytecode_files + @util.writes_bytecode_files def _test_partial_magic(self, test, *, del_source=False): # When their are less than 4 bytes to a .pyc, regenerate it if # possible, else raise ImportError. - with source_util.create_modules('_temp') as mapping: + with util.create_modules('_temp') as mapping: bc_path = self.manipulate_bytecode('_temp', mapping, lambda bc: bc[:3], del_source=del_source) test('_temp', mapping, bc_path) def _test_magic_only(self, test, *, del_source=False): - with source_util.create_modules('_temp') as mapping: + with util.create_modules('_temp') as mapping: bc_path = self.manipulate_bytecode('_temp', mapping, lambda bc: bc[:4], del_source=del_source) test('_temp', mapping, bc_path) def _test_partial_timestamp(self, test, *, del_source=False): - with source_util.create_modules('_temp') as mapping: + with util.create_modules('_temp') as mapping: bc_path = self.manipulate_bytecode('_temp', mapping, lambda bc: bc[:7], del_source=del_source) test('_temp', mapping, bc_path) def _test_partial_size(self, test, *, del_source=False): - with source_util.create_modules('_temp') as mapping: + with util.create_modules('_temp') as mapping: bc_path = self.manipulate_bytecode('_temp', mapping, lambda bc: bc[:11], del_source=del_source) test('_temp', mapping, bc_path) def _test_no_marshal(self, *, del_source=False): - with source_util.create_modules('_temp') as mapping: + with util.create_modules('_temp') as mapping: bc_path = self.manipulate_bytecode('_temp', mapping, lambda bc: bc[:12], del_source=del_source) @@ -322,7 +323,7 @@ class BadBytecodeTest: self.import_(file_path, '_temp') def _test_non_code_marshal(self, *, del_source=False): - with source_util.create_modules('_temp') as mapping: + with util.create_modules('_temp') as mapping: bytecode_path = self.manipulate_bytecode('_temp', mapping, lambda bc: bc[:12] + marshal.dumps(b'abcd'), del_source=del_source) @@ -333,7 +334,7 @@ class BadBytecodeTest: self.assertEqual(cm.exception.path, bytecode_path) def _test_bad_marshal(self, *, del_source=False): - with source_util.create_modules('_temp') as mapping: + with util.create_modules('_temp') as mapping: bytecode_path = self.manipulate_bytecode('_temp', mapping, lambda bc: bc[:12] + b'<test>', del_source=del_source) @@ -342,11 +343,12 @@ class BadBytecodeTest: self.import_(file_path, '_temp') def _test_bad_magic(self, test, *, del_source=False): - with source_util.create_modules('_temp') as mapping: + with util.create_modules('_temp') as mapping: bc_path = self.manipulate_bytecode('_temp', mapping, lambda bc: b'\x00\x00\x00\x00' + bc[4:]) test('_temp', mapping, bc_path) + class BadBytecodeTestPEP451(BadBytecodeTest): def import_(self, file, module_name): @@ -355,6 +357,7 @@ class BadBytecodeTestPEP451(BadBytecodeTest): module.__spec__ = self.util.spec_from_loader(module_name, loader) loader.exec_module(module) + class BadBytecodeTestPEP302(BadBytecodeTest): def import_(self, file, module_name): @@ -371,7 +374,7 @@ class SourceLoaderBadBytecodeTest: def setUpClass(cls): cls.loader = cls.machinery.SourceFileLoader - @source_util.writes_bytecode_files + @util.writes_bytecode_files def test_empty_file(self): # When a .pyc is empty, regenerate it if possible, else raise # ImportError. @@ -390,7 +393,7 @@ class SourceLoaderBadBytecodeTest: self._test_partial_magic(test) - @source_util.writes_bytecode_files + @util.writes_bytecode_files def test_magic_only(self): # When there is only the magic number, regenerate the .pyc if possible, # else raise EOFError. @@ -401,7 +404,7 @@ class SourceLoaderBadBytecodeTest: self._test_magic_only(test) - @source_util.writes_bytecode_files + @util.writes_bytecode_files def test_bad_magic(self): # When the magic number is different, the bytecode should be # regenerated. @@ -413,7 +416,7 @@ class SourceLoaderBadBytecodeTest: self._test_bad_magic(test) - @source_util.writes_bytecode_files + @util.writes_bytecode_files def test_partial_timestamp(self): # When the timestamp is partial, regenerate the .pyc, else # raise EOFError. @@ -424,7 +427,7 @@ class SourceLoaderBadBytecodeTest: self._test_partial_timestamp(test) - @source_util.writes_bytecode_files + @util.writes_bytecode_files def test_partial_size(self): # When the size is partial, regenerate the .pyc, else # raise EOFError. @@ -435,29 +438,29 @@ class SourceLoaderBadBytecodeTest: self._test_partial_size(test) - @source_util.writes_bytecode_files + @util.writes_bytecode_files def test_no_marshal(self): # When there is only the magic number and timestamp, raise EOFError. self._test_no_marshal() - @source_util.writes_bytecode_files + @util.writes_bytecode_files def test_non_code_marshal(self): self._test_non_code_marshal() # XXX ImportError when sourceless # [bad marshal] - @source_util.writes_bytecode_files + @util.writes_bytecode_files def test_bad_marshal(self): # Bad marshal data should raise a ValueError. self._test_bad_marshal() # [bad timestamp] - @source_util.writes_bytecode_files + @util.writes_bytecode_files def test_old_timestamp(self): # When the timestamp is older than the source, bytecode should be # regenerated. zeros = b'\x00\x00\x00\x00' - with source_util.create_modules('_temp') as mapping: + with util.create_modules('_temp') as mapping: py_compile.compile(mapping['_temp']) bytecode_path = self.util.cache_from_source(mapping['_temp']) with open(bytecode_path, 'r+b') as bytecode_file: @@ -471,10 +474,10 @@ class SourceLoaderBadBytecodeTest: self.assertEqual(bytecode_file.read(4), source_timestamp) # [bytecode read-only] - @source_util.writes_bytecode_files + @util.writes_bytecode_files def test_read_only_bytecode(self): # When bytecode is read-only but should be rewritten, fail silently. - with source_util.create_modules('_temp') as mapping: + with util.create_modules('_temp') as mapping: # Create bytecode that will need to be re-created. py_compile.compile(mapping['_temp']) bytecode_path = self.util.cache_from_source(mapping['_temp']) @@ -491,21 +494,29 @@ class SourceLoaderBadBytecodeTest: # Make writable for eventual clean-up. os.chmod(bytecode_path, stat.S_IWUSR) + class SourceLoaderBadBytecodeTestPEP451( SourceLoaderBadBytecodeTest, BadBytecodeTestPEP451): pass -Frozen_SourceBadBytecodePEP451, Source_SourceBadBytecodePEP451 = util.test_both( - SourceLoaderBadBytecodeTestPEP451, importlib=importlib, machinery=machinery, - abc=importlib_abc, util=importlib_util) + +(Frozen_SourceBadBytecodePEP451, + Source_SourceBadBytecodePEP451 + ) = util.test_both(SourceLoaderBadBytecodeTestPEP451, importlib=importlib, + machinery=machinery, abc=importlib_abc, + util=importlib_util) + class SourceLoaderBadBytecodeTestPEP302( SourceLoaderBadBytecodeTest, BadBytecodeTestPEP302): pass -Frozen_SourceBadBytecodePEP302, Source_SourceBadBytecodePEP302 = util.test_both( - SourceLoaderBadBytecodeTestPEP302, importlib=importlib, machinery=machinery, - abc=importlib_abc, util=importlib_util) + +(Frozen_SourceBadBytecodePEP302, + Source_SourceBadBytecodePEP302 + ) = util.test_both(SourceLoaderBadBytecodeTestPEP302, importlib=importlib, + machinery=machinery, abc=importlib_abc, + util=importlib_util) class SourcelessLoaderBadBytecodeTest: @@ -567,21 +578,29 @@ class SourcelessLoaderBadBytecodeTest: def test_non_code_marshal(self): self._test_non_code_marshal(del_source=True) + class SourcelessLoaderBadBytecodeTestPEP451(SourcelessLoaderBadBytecodeTest, BadBytecodeTestPEP451): pass -Frozen_SourcelessBadBytecodePEP451, Source_SourcelessBadBytecodePEP451 = util.test_both( - SourcelessLoaderBadBytecodeTestPEP451, importlib=importlib, - machinery=machinery, abc=importlib_abc, util=importlib_util) + +(Frozen_SourcelessBadBytecodePEP451, + Source_SourcelessBadBytecodePEP451 + ) = util.test_both(SourcelessLoaderBadBytecodeTestPEP451, importlib=importlib, + machinery=machinery, abc=importlib_abc, + util=importlib_util) + class SourcelessLoaderBadBytecodeTestPEP302(SourcelessLoaderBadBytecodeTest, BadBytecodeTestPEP302): pass -Frozen_SourcelessBadBytecodePEP302, Source_SourcelessBadBytecodePEP302 = util.test_both( - SourcelessLoaderBadBytecodeTestPEP302, importlib=importlib, - machinery=machinery, abc=importlib_abc, util=importlib_util) + +(Frozen_SourcelessBadBytecodePEP302, + Source_SourcelessBadBytecodePEP302 + ) = util.test_both(SourcelessLoaderBadBytecodeTestPEP302, importlib=importlib, + machinery=machinery, abc=importlib_abc, + util=importlib_util) if __name__ == '__main__': diff --git a/Lib/test/test_importlib/source/test_finder.py b/Lib/test/test_importlib/source/test_finder.py index 473297b..f372b85 100644 --- a/Lib/test/test_importlib/source/test_finder.py +++ b/Lib/test/test_importlib/source/test_finder.py @@ -1,6 +1,5 @@ from .. import abc from .. import util -from . import util as source_util machinery = util.import_importlib('importlib.machinery') @@ -60,7 +59,7 @@ class FinderTests(abc.FinderTests): """ if create is None: create = {test} - with source_util.create_modules(*create) as mapping: + with util.create_modules(*create) as mapping: if compile_: for name in compile_: py_compile.compile(mapping[name]) @@ -100,14 +99,14 @@ class FinderTests(abc.FinderTests): # [sub module] def test_module_in_package(self): - with source_util.create_modules('pkg.__init__', 'pkg.sub') as mapping: + with util.create_modules('pkg.__init__', 'pkg.sub') as mapping: pkg_dir = os.path.dirname(mapping['pkg.__init__']) loader = self.import_(pkg_dir, 'pkg.sub') self.assertTrue(hasattr(loader, 'load_module')) # [sub package] def test_package_in_package(self): - context = source_util.create_modules('pkg.__init__', 'pkg.sub.__init__') + context = util.create_modules('pkg.__init__', 'pkg.sub.__init__') with context as mapping: pkg_dir = os.path.dirname(mapping['pkg.__init__']) loader = self.import_(pkg_dir, 'pkg.sub') @@ -120,7 +119,7 @@ class FinderTests(abc.FinderTests): self.assertIn('__init__', loader.get_filename(name)) def test_failure(self): - with source_util.create_modules('blah') as mapping: + with util.create_modules('blah') as mapping: nothing = self.import_(mapping['.root'], 'sdfsadsadf') self.assertIsNone(nothing) @@ -147,7 +146,7 @@ class FinderTests(abc.FinderTests): # Regression test for http://bugs.python.org/issue14846 def test_dir_removal_handling(self): mod = 'mod' - with source_util.create_modules(mod) as mapping: + with util.create_modules(mod) as mapping: finder = self.get_finder(mapping['.root']) found = self._find(finder, 'mod', loader_only=True) self.assertIsNotNone(found) @@ -196,8 +195,10 @@ class FinderTestsPEP451(FinderTests): spec = finder.find_spec(name) return spec.loader if spec is not None else spec -Frozen_FinderTestsPEP451, Source_FinderTestsPEP451 = util.test_both( - FinderTestsPEP451, machinery=machinery) + +(Frozen_FinderTestsPEP451, + Source_FinderTestsPEP451 + ) = util.test_both(FinderTestsPEP451, machinery=machinery) class FinderTestsPEP420(FinderTests): @@ -210,8 +211,10 @@ class FinderTestsPEP420(FinderTests): loader_portions = finder.find_loader(name) return loader_portions[0] if loader_only else loader_portions -Frozen_FinderTestsPEP420, Source_FinderTestsPEP420 = util.test_both( - FinderTestsPEP420, machinery=machinery) + +(Frozen_FinderTestsPEP420, + Source_FinderTestsPEP420 + ) = util.test_both(FinderTestsPEP420, machinery=machinery) class FinderTestsPEP302(FinderTests): @@ -223,9 +226,10 @@ class FinderTestsPEP302(FinderTests): warnings.simplefilter("ignore", DeprecationWarning) return finder.find_module(name) -Frozen_FinderTestsPEP302, Source_FinderTestsPEP302 = util.test_both( - FinderTestsPEP302, machinery=machinery) +(Frozen_FinderTestsPEP302, + Source_FinderTestsPEP302 + ) = util.test_both(FinderTestsPEP302, machinery=machinery) if __name__ == '__main__': diff --git a/Lib/test/test_importlib/source/test_path_hook.py b/Lib/test/test_importlib/source/test_path_hook.py index 92da772..e6a2415 100644 --- a/Lib/test/test_importlib/source/test_path_hook.py +++ b/Lib/test/test_importlib/source/test_path_hook.py @@ -1,5 +1,4 @@ from .. import util -from . import util as source_util machinery = util.import_importlib('importlib.machinery') @@ -15,7 +14,7 @@ class PathHookTest: self.machinery.SOURCE_SUFFIXES)) def test_success(self): - with source_util.create_modules('dummy') as mapping: + with util.create_modules('dummy') as mapping: self.assertTrue(hasattr(self.path_hook()(mapping['.root']), 'find_module')) @@ -23,7 +22,10 @@ class PathHookTest: # The empty string represents the cwd. self.assertTrue(hasattr(self.path_hook()(''), 'find_module')) -Frozen_PathHookTest, Source_PathHooktest = util.test_both(PathHookTest, machinery=machinery) + +(Frozen_PathHookTest, + Source_PathHooktest + ) = util.test_both(PathHookTest, machinery=machinery) if __name__ == '__main__': diff --git a/Lib/test/test_importlib/source/test_source_encoding.py b/Lib/test/test_importlib/source/test_source_encoding.py index c62dfa1..b604afb 100644 --- a/Lib/test/test_importlib/source/test_source_encoding.py +++ b/Lib/test/test_importlib/source/test_source_encoding.py @@ -1,5 +1,4 @@ from .. import util -from . import util as source_util machinery = util.import_importlib('importlib.machinery') @@ -37,7 +36,7 @@ class EncodingTest: module_name = '_temp' def run_test(self, source): - with source_util.create_modules(self.module_name) as mapping: + with util.create_modules(self.module_name) as mapping: with open(mapping[self.module_name], 'wb') as file: file.write(source) loader = self.machinery.SourceFileLoader(self.module_name, @@ -89,6 +88,7 @@ class EncodingTest: with self.assertRaises(SyntaxError): self.run_test(source) + class EncodingTestPEP451(EncodingTest): def load(self, loader): @@ -97,8 +97,11 @@ class EncodingTestPEP451(EncodingTest): loader.exec_module(module) return module -Frozen_EncodingTestPEP451, Source_EncodingTestPEP451 = util.test_both( - EncodingTestPEP451, machinery=machinery) + +(Frozen_EncodingTestPEP451, + Source_EncodingTestPEP451 + ) = util.test_both(EncodingTestPEP451, machinery=machinery) + class EncodingTestPEP302(EncodingTest): @@ -107,8 +110,10 @@ class EncodingTestPEP302(EncodingTest): warnings.simplefilter('ignore', DeprecationWarning) return loader.load_module(self.module_name) -Frozen_EncodingTestPEP302, Source_EncodingTestPEP302 = util.test_both( - EncodingTestPEP302, machinery=machinery) + +(Frozen_EncodingTestPEP302, + Source_EncodingTestPEP302 + ) = util.test_both(EncodingTestPEP302, machinery=machinery) class LineEndingTest: @@ -120,7 +125,7 @@ class LineEndingTest: module_name = '_temp' source_lines = [b"a = 42", b"b = -13", b''] source = line_ending.join(source_lines) - with source_util.create_modules(module_name) as mapping: + with util.create_modules(module_name) as mapping: with open(mapping[module_name], 'wb') as file: file.write(source) loader = self.machinery.SourceFileLoader(module_name, @@ -139,6 +144,7 @@ class LineEndingTest: def test_lf(self): self.run_test(b'\n') + class LineEndingTestPEP451(LineEndingTest): def load(self, loader, module_name): @@ -147,8 +153,11 @@ class LineEndingTestPEP451(LineEndingTest): loader.exec_module(module) return module -Frozen_LineEndingTestPEP451, Source_LineEndingTestPEP451 = util.test_both( - LineEndingTestPEP451, machinery=machinery) + +(Frozen_LineEndingTestPEP451, + Source_LineEndingTestPEP451 + ) = util.test_both(LineEndingTestPEP451, machinery=machinery) + class LineEndingTestPEP302(LineEndingTest): @@ -157,8 +166,10 @@ class LineEndingTestPEP302(LineEndingTest): warnings.simplefilter('ignore', DeprecationWarning) return loader.load_module(module_name) -Frozen_LineEndingTestPEP302, Source_LineEndingTestPEP302 = util.test_both( - LineEndingTestPEP302, machinery=machinery) + +(Frozen_LineEndingTestPEP302, + Source_LineEndingTestPEP302 + ) = util.test_both(LineEndingTestPEP302, machinery=machinery) if __name__ == '__main__': diff --git a/Lib/test/test_importlib/source/util.py b/Lib/test/test_importlib/source/util.py deleted file mode 100644 index 63cd25a..0000000 --- a/Lib/test/test_importlib/source/util.py +++ /dev/null @@ -1,96 +0,0 @@ -from .. import util -import contextlib -import errno -import functools -import os -import os.path -import sys -import tempfile -from test import support - - -def writes_bytecode_files(fxn): - """Decorator to protect sys.dont_write_bytecode from mutation and to skip - tests that require it to be set to False.""" - if sys.dont_write_bytecode: - return lambda *args, **kwargs: None - @functools.wraps(fxn) - def wrapper(*args, **kwargs): - original = sys.dont_write_bytecode - sys.dont_write_bytecode = False - try: - to_return = fxn(*args, **kwargs) - finally: - sys.dont_write_bytecode = original - return to_return - return wrapper - - -def ensure_bytecode_path(bytecode_path): - """Ensure that the __pycache__ directory for PEP 3147 pyc file exists. - - :param bytecode_path: File system path to PEP 3147 pyc file. - """ - try: - os.mkdir(os.path.dirname(bytecode_path)) - except OSError as error: - if error.errno != errno.EEXIST: - raise - - -@contextlib.contextmanager -def create_modules(*names): - """Temporarily create each named module with an attribute (named 'attr') - that contains the name passed into the context manager that caused the - creation of the module. - - All files are created in a temporary directory returned by - tempfile.mkdtemp(). This directory is inserted at the beginning of - sys.path. When the context manager exits all created files (source and - bytecode) are explicitly deleted. - - No magic is performed when creating packages! This means that if you create - a module within a package you must also create the package's __init__ as - well. - - """ - source = 'attr = {0!r}' - created_paths = [] - mapping = {} - state_manager = None - uncache_manager = None - try: - temp_dir = tempfile.mkdtemp() - mapping['.root'] = temp_dir - import_names = set() - for name in names: - if not name.endswith('__init__'): - import_name = name - else: - import_name = name[:-len('.__init__')] - import_names.add(import_name) - if import_name in sys.modules: - del sys.modules[import_name] - name_parts = name.split('.') - file_path = temp_dir - for directory in name_parts[:-1]: - file_path = os.path.join(file_path, directory) - if not os.path.exists(file_path): - os.mkdir(file_path) - created_paths.append(file_path) - file_path = os.path.join(file_path, name_parts[-1] + '.py') - with open(file_path, 'w') as file: - file.write(source.format(name)) - created_paths.append(file_path) - mapping[name] = file_path - uncache_manager = util.uncache(*import_names) - uncache_manager.__enter__() - state_manager = util.import_state(path=[temp_dir]) - state_manager.__enter__() - yield mapping - finally: - if state_manager is not None: - state_manager.__exit__(None, None, None) - if uncache_manager is not None: - uncache_manager.__exit__(None, None, None) - support.rmtree(temp_dir) diff --git a/Lib/test/test_importlib/test_abc.py b/Lib/test/test_importlib/test_abc.py index a1f8e76..d4bf915 100644 --- a/Lib/test/test_importlib/test_abc.py +++ b/Lib/test/test_importlib/test_abc.py @@ -10,12 +10,13 @@ import unittest from unittest import mock import warnings -from . import util +from . import util as test_util + +init = test_util.import_importlib('importlib') +abc = test_util.import_importlib('importlib.abc') +machinery = test_util.import_importlib('importlib.machinery') +util = test_util.import_importlib('importlib.util') -frozen_init, source_init = util.import_importlib('importlib') -frozen_abc, source_abc = util.import_importlib('importlib.abc') -machinery = util.import_importlib('importlib.machinery') -frozen_util, source_util = util.import_importlib('importlib.util') ##### Inheritance ############################################################## class InheritanceTests: @@ -26,8 +27,7 @@ class InheritanceTests: subclasses = [] superclasses = [] - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + def setUp(self): self.superclasses = [getattr(self.abc, class_name) for class_name in self.superclass_names] if hasattr(self, 'subclass_names'): @@ -36,11 +36,11 @@ class InheritanceTests: # checking across module boundaries (i.e. the _bootstrap in abc is # not the same as the one in machinery). That means stealing one of # the modules from the other to make sure the same instance is used. - self.subclasses = [getattr(self.abc.machinery, class_name) - for class_name in self.subclass_names] + machinery = self.abc.machinery + self.subclasses = [getattr(machinery, class_name) + for class_name in self.subclass_names] assert self.subclasses or self.superclasses, self.__class__ - testing = self.__class__.__name__.partition('_')[2] - self.__test = getattr(self.abc, testing) + self.__test = getattr(self.abc, self._NAME) def test_subclasses(self): # Test that the expected subclasses inherit. @@ -54,94 +54,97 @@ class InheritanceTests: self.assertTrue(issubclass(self.__test, superclass), "{0} is not a superclass of {1}".format(superclass, self.__test)) -def create_inheritance_tests(base_class): - def set_frozen(ns): - ns['abc'] = frozen_abc - def set_source(ns): - ns['abc'] = source_abc - - classes = [] - for prefix, ns_set in [('Frozen', set_frozen), ('Source', set_source)]: - classes.append(types.new_class('_'.join([prefix, base_class.__name__]), - (base_class, unittest.TestCase), - exec_body=ns_set)) - return classes - class MetaPathFinder(InheritanceTests): superclass_names = ['Finder'] subclass_names = ['BuiltinImporter', 'FrozenImporter', 'PathFinder', 'WindowsRegistryFinder'] -tests = create_inheritance_tests(MetaPathFinder) -Frozen_MetaPathFinderInheritanceTests, Source_MetaPathFinderInheritanceTests = tests + +(Frozen_MetaPathFinderInheritanceTests, + Source_MetaPathFinderInheritanceTests + ) = test_util.test_both(MetaPathFinder, abc=abc) class PathEntryFinder(InheritanceTests): superclass_names = ['Finder'] subclass_names = ['FileFinder'] -tests = create_inheritance_tests(PathEntryFinder) -Frozen_PathEntryFinderInheritanceTests, Source_PathEntryFinderInheritanceTests = tests + +(Frozen_PathEntryFinderInheritanceTests, + Source_PathEntryFinderInheritanceTests + ) = test_util.test_both(PathEntryFinder, abc=abc) class ResourceLoader(InheritanceTests): superclass_names = ['Loader'] -tests = create_inheritance_tests(ResourceLoader) -Frozen_ResourceLoaderInheritanceTests, Source_ResourceLoaderInheritanceTests = tests + +(Frozen_ResourceLoaderInheritanceTests, + Source_ResourceLoaderInheritanceTests + ) = test_util.test_both(ResourceLoader, abc=abc) class InspectLoader(InheritanceTests): superclass_names = ['Loader'] subclass_names = ['BuiltinImporter', 'FrozenImporter', 'ExtensionFileLoader'] -tests = create_inheritance_tests(InspectLoader) -Frozen_InspectLoaderInheritanceTests, Source_InspectLoaderInheritanceTests = tests + +(Frozen_InspectLoaderInheritanceTests, + Source_InspectLoaderInheritanceTests + ) = test_util.test_both(InspectLoader, abc=abc) class ExecutionLoader(InheritanceTests): superclass_names = ['InspectLoader'] subclass_names = ['ExtensionFileLoader'] -tests = create_inheritance_tests(ExecutionLoader) -Frozen_ExecutionLoaderInheritanceTests, Source_ExecutionLoaderInheritanceTests = tests + +(Frozen_ExecutionLoaderInheritanceTests, + Source_ExecutionLoaderInheritanceTests + ) = test_util.test_both(ExecutionLoader, abc=abc) class FileLoader(InheritanceTests): superclass_names = ['ResourceLoader', 'ExecutionLoader'] subclass_names = ['SourceFileLoader', 'SourcelessFileLoader'] -tests = create_inheritance_tests(FileLoader) -Frozen_FileLoaderInheritanceTests, Source_FileLoaderInheritanceTests = tests + +(Frozen_FileLoaderInheritanceTests, + Source_FileLoaderInheritanceTests + ) = test_util.test_both(FileLoader, abc=abc) class SourceLoader(InheritanceTests): superclass_names = ['ResourceLoader', 'ExecutionLoader'] subclass_names = ['SourceFileLoader'] -tests = create_inheritance_tests(SourceLoader) -Frozen_SourceLoaderInheritanceTests, Source_SourceLoaderInheritanceTests = tests + +(Frozen_SourceLoaderInheritanceTests, + Source_SourceLoaderInheritanceTests + ) = test_util.test_both(SourceLoader, abc=abc) + ##### Default return values #################################################### -def make_abc_subclasses(base_class): - classes = [] - for kind, abc in [('Frozen', frozen_abc), ('Source', source_abc)]: - name = '_'.join([kind, base_class.__name__]) - base_classes = base_class, getattr(abc, base_class.__name__) - classes.append(types.new_class(name, base_classes)) - return classes - -def make_return_value_tests(base_class, test_class): - frozen_class, source_class = make_abc_subclasses(base_class) - tests = [] - for prefix, class_in_test in [('Frozen', frozen_class), ('Source', source_class)]: - def set_ns(ns): - ns['ins'] = class_in_test() - tests.append(types.new_class('_'.join([prefix, test_class.__name__]), - (test_class, unittest.TestCase), - exec_body=set_ns)) - return tests + +def make_abc_subclasses(base_class, name=None, inst=False, **kwargs): + if name is None: + name = base_class.__name__ + base = {kind: getattr(splitabc, name) + for kind, splitabc in abc.items()} + return {cls._KIND: cls() if inst else cls + for cls in test_util.split_frozen(base_class, base, **kwargs)} + + +class ABCTestHarness: + + @property + def ins(self): + # Lazily set ins on the class. + cls = self.SPLIT[self._KIND] + ins = cls() + self.__class__.ins = ins + return ins class MetaPathFinder: @@ -149,10 +152,10 @@ class MetaPathFinder: def find_module(self, fullname, path): return super().find_module(fullname, path) -Frozen_MPF, Source_MPF = make_abc_subclasses(MetaPathFinder) +class MetaPathFinderDefaultsTests(ABCTestHarness): -class MetaPathFinderDefaultsTests: + SPLIT = make_abc_subclasses(MetaPathFinder) def test_find_module(self): # Default should return None. @@ -163,8 +166,9 @@ class MetaPathFinderDefaultsTests: self.ins.invalidate_caches() -tests = make_return_value_tests(MetaPathFinder, MetaPathFinderDefaultsTests) -Frozen_MPFDefaultTests, Source_MPFDefaultTests = tests +(Frozen_MPFDefaultTests, + Source_MPFDefaultTests + ) = test_util.test_both(MetaPathFinderDefaultsTests) class PathEntryFinder: @@ -172,10 +176,10 @@ class PathEntryFinder: def find_loader(self, fullname): return super().find_loader(fullname) -Frozen_PEF, Source_PEF = make_abc_subclasses(PathEntryFinder) +class PathEntryFinderDefaultsTests(ABCTestHarness): -class PathEntryFinderDefaultsTests: + SPLIT = make_abc_subclasses(PathEntryFinder) def test_find_loader(self): self.assertEqual((None, []), self.ins.find_loader('something')) @@ -188,8 +192,9 @@ class PathEntryFinderDefaultsTests: self.ins.invalidate_caches() -tests = make_return_value_tests(PathEntryFinder, PathEntryFinderDefaultsTests) -Frozen_PEFDefaultTests, Source_PEFDefaultTests = tests +(Frozen_PEFDefaultTests, + Source_PEFDefaultTests + ) = test_util.test_both(PathEntryFinderDefaultsTests) class Loader: @@ -198,10 +203,9 @@ class Loader: return super().load_module(fullname) -Frozen_L, Source_L = make_abc_subclasses(Loader) +class LoaderDefaultsTests(ABCTestHarness): - -class LoaderDefaultsTests: + SPLIT = make_abc_subclasses(Loader) def test_load_module(self): with self.assertRaises(ImportError): @@ -217,8 +221,9 @@ class LoaderDefaultsTests: self.assertTrue(repr(mod)) -tests = make_return_value_tests(Loader, LoaderDefaultsTests) -Frozen_LDefaultTests, SourceLDefaultTests = tests +(Frozen_LDefaultTests, + SourceLDefaultTests + ) = test_util.test_both(LoaderDefaultsTests) class ResourceLoader(Loader): @@ -227,18 +232,18 @@ class ResourceLoader(Loader): return super().get_data(path) -Frozen_RL, Source_RL = make_abc_subclasses(ResourceLoader) - +class ResourceLoaderDefaultsTests(ABCTestHarness): -class ResourceLoaderDefaultsTests: + SPLIT = make_abc_subclasses(ResourceLoader) def test_get_data(self): with self.assertRaises(IOError): self.ins.get_data('/some/path') -tests = make_return_value_tests(ResourceLoader, ResourceLoaderDefaultsTests) -Frozen_RLDefaultTests, Source_RLDefaultTests = tests +(Frozen_RLDefaultTests, + Source_RLDefaultTests + ) = test_util.test_both(ResourceLoaderDefaultsTests) class InspectLoader(Loader): @@ -250,10 +255,12 @@ class InspectLoader(Loader): return super().get_source(fullname) -Frozen_IL, Source_IL = make_abc_subclasses(InspectLoader) +SPLIT_IL = make_abc_subclasses(InspectLoader) -class InspectLoaderDefaultsTests: +class InspectLoaderDefaultsTests(ABCTestHarness): + + SPLIT = SPLIT_IL def test_is_package(self): with self.assertRaises(ImportError): @@ -264,8 +271,9 @@ class InspectLoaderDefaultsTests: self.ins.get_source('blah') -tests = make_return_value_tests(InspectLoader, InspectLoaderDefaultsTests) -Frozen_ILDefaultTests, Source_ILDefaultTests = tests +(Frozen_ILDefaultTests, + Source_ILDefaultTests + ) = test_util.test_both(InspectLoaderDefaultsTests) class ExecutionLoader(InspectLoader): @@ -273,21 +281,25 @@ class ExecutionLoader(InspectLoader): def get_filename(self, fullname): return super().get_filename(fullname) -Frozen_EL, Source_EL = make_abc_subclasses(ExecutionLoader) + +SPLIT_EL = make_abc_subclasses(ExecutionLoader) -class ExecutionLoaderDefaultsTests: +class ExecutionLoaderDefaultsTests(ABCTestHarness): + + SPLIT = SPLIT_EL def test_get_filename(self): with self.assertRaises(ImportError): self.ins.get_filename('blah') -tests = make_return_value_tests(ExecutionLoader, InspectLoaderDefaultsTests) -Frozen_ELDefaultTests, Source_ELDefaultsTests = tests +(Frozen_ELDefaultTests, + Source_ELDefaultsTests + ) = test_util.test_both(InspectLoaderDefaultsTests) -##### MetaPathFinder concrete methods ########################################## +##### MetaPathFinder concrete methods ########################################## class MetaPathFinderFindModuleTests: @classmethod @@ -317,13 +329,12 @@ class MetaPathFinderFindModuleTests: self.assertIs(found, spec.loader) -Frozen_MPFFindModuleTests, Source_MPFFindModuleTests = util.test_both( - MetaPathFinderFindModuleTests, - abc=(frozen_abc, source_abc), - util=(frozen_util, source_util)) +(Frozen_MPFFindModuleTests, + Source_MPFFindModuleTests + ) = test_util.test_both(MetaPathFinderFindModuleTests, abc=abc, util=util) -##### PathEntryFinder concrete methods ######################################### +##### PathEntryFinder concrete methods ######################################### class PathEntryFinderFindLoaderTests: @classmethod @@ -361,11 +372,10 @@ class PathEntryFinderFindLoaderTests: self.assertEqual(paths, found[1]) -Frozen_PEFFindLoaderTests, Source_PEFFindLoaderTests = util.test_both( - PathEntryFinderFindLoaderTests, - abc=(frozen_abc, source_abc), - machinery=machinery, - util=(frozen_util, source_util)) +(Frozen_PEFFindLoaderTests, + Source_PEFFindLoaderTests + ) = test_util.test_both(PathEntryFinderFindLoaderTests, abc=abc, util=util, + machinery=machinery) ##### Loader concrete methods ################################################## @@ -386,7 +396,7 @@ class LoaderLoadModuleTests: def test_fresh(self): loader = self.loader() name = 'blah' - with util.uncache(name): + with test_util.uncache(name): loader.load_module(name) module = loader.found self.assertIs(sys.modules[name], module) @@ -404,7 +414,7 @@ class LoaderLoadModuleTests: module = types.ModuleType(name) module.__spec__ = self.util.spec_from_loader(name, loader) module.__loader__ = loader - with util.uncache(name): + with test_util.uncache(name): sys.modules[name] = module loader.load_module(name) found = loader.found @@ -412,10 +422,9 @@ class LoaderLoadModuleTests: self.assertIs(module, sys.modules[name]) -Frozen_LoaderLoadModuleTests, Source_LoaderLoadModuleTests = util.test_both( - LoaderLoadModuleTests, - abc=(frozen_abc, source_abc), - util=(frozen_util, source_util)) +(Frozen_LoaderLoadModuleTests, + Source_LoaderLoadModuleTests + ) = test_util.test_both(LoaderLoadModuleTests, abc=abc, util=util) ##### InspectLoader concrete methods ########################################### @@ -461,11 +470,10 @@ class InspectLoaderSourceToCodeTests: self.assertEqual(code.co_filename, '<string>') -class Frozen_ILSourceToCodeTests(InspectLoaderSourceToCodeTests, unittest.TestCase): - InspectLoaderSubclass = Frozen_IL - -class Source_ILSourceToCodeTests(InspectLoaderSourceToCodeTests, unittest.TestCase): - InspectLoaderSubclass = Source_IL +(Frozen_ILSourceToCodeTests, + Source_ILSourceToCodeTests + ) = test_util.test_both(InspectLoaderSourceToCodeTests, + InspectLoaderSubclass=SPLIT_IL) class InspectLoaderGetCodeTests: @@ -495,11 +503,10 @@ class InspectLoaderGetCodeTests: loader.get_code('blah') -class Frozen_ILGetCodeTests(InspectLoaderGetCodeTests, unittest.TestCase): - InspectLoaderSubclass = Frozen_IL - -class Source_ILGetCodeTests(InspectLoaderGetCodeTests, unittest.TestCase): - InspectLoaderSubclass = Source_IL +(Frozen_ILGetCodeTests, + Source_ILGetCodeTests + ) = test_util.test_both(InspectLoaderGetCodeTests, + InspectLoaderSubclass=SPLIT_IL) class InspectLoaderLoadModuleTests: @@ -543,11 +550,10 @@ class InspectLoaderLoadModuleTests: self.assertEqual(module, sys.modules[self.module_name]) -class Frozen_ILLoadModuleTests(InspectLoaderLoadModuleTests, unittest.TestCase): - InspectLoaderSubclass = Frozen_IL - -class Source_ILLoadModuleTests(InspectLoaderLoadModuleTests, unittest.TestCase): - InspectLoaderSubclass = Source_IL +(Frozen_ILLoadModuleTests, + Source_ILLoadModuleTests + ) = test_util.test_both(InspectLoaderLoadModuleTests, + InspectLoaderSubclass=SPLIT_IL) ##### ExecutionLoader concrete methods ######################################### @@ -608,15 +614,14 @@ class ExecutionLoaderGetCodeTests: self.assertEqual(module.attr, 42) -class Frozen_ELGetCodeTests(ExecutionLoaderGetCodeTests, unittest.TestCase): - ExecutionLoaderSubclass = Frozen_EL - -class Source_ELGetCodeTests(ExecutionLoaderGetCodeTests, unittest.TestCase): - ExecutionLoaderSubclass = Source_EL +(Frozen_ELGetCodeTests, + Source_ELGetCodeTests + ) = test_util.test_both(ExecutionLoaderGetCodeTests, + ExecutionLoaderSubclass=SPLIT_EL) ##### SourceLoader concrete methods ############################################ -class SourceLoader: +class SourceOnlyLoader: # Globals that should be defined for all modules. source = (b"_ = '::'.join([__name__, __file__, __cached__, __package__, " @@ -637,10 +642,10 @@ class SourceLoader: return '<module>' -Frozen_SourceOnlyL, Source_SourceOnlyL = make_abc_subclasses(SourceLoader) +SPLIT_SOL = make_abc_subclasses(SourceOnlyLoader, 'SourceLoader') -class SourceLoader(SourceLoader): +class SourceLoader(SourceOnlyLoader): source_mtime = 1 @@ -677,11 +682,7 @@ class SourceLoader(SourceLoader): return path == self.bytecode_path -Frozen_SL, Source_SL = make_abc_subclasses(SourceLoader) -Frozen_SL.util = frozen_util -Source_SL.util = source_util -Frozen_SL.init = frozen_init -Source_SL.init = source_init +SPLIT_SL = make_abc_subclasses(SourceLoader, util=util, init=init) class SourceLoaderTestHarness: @@ -765,7 +766,7 @@ class SourceOnlyLoaderTests(SourceLoaderTestHarness): # Loading a module should set __name__, __loader__, __package__, # __path__ (for packages), __file__, and __cached__. # The module should also be put into sys.modules. - with util.uncache(self.name): + with test_util.uncache(self.name): with warnings.catch_warnings(): warnings.simplefilter('ignore', DeprecationWarning) module = self.loader.load_module(self.name) @@ -778,7 +779,7 @@ class SourceOnlyLoaderTests(SourceLoaderTestHarness): # is a package. # Testing the values for a package are covered by test_load_module. self.setUp(is_package=False) - with util.uncache(self.name): + with test_util.uncache(self.name): with warnings.catch_warnings(): warnings.simplefilter('ignore', DeprecationWarning) module = self.loader.load_module(self.name) @@ -798,13 +799,10 @@ class SourceOnlyLoaderTests(SourceLoaderTestHarness): self.assertEqual(returned_source, source) -class Frozen_SourceOnlyLTests(SourceOnlyLoaderTests, unittest.TestCase): - loader_mock = Frozen_SourceOnlyL - util = frozen_util - -class Source_SourceOnlyLTests(SourceOnlyLoaderTests, unittest.TestCase): - loader_mock = Source_SourceOnlyL - util = source_util +(Frozen_SourceOnlyLoaderTests, + Source_SourceOnlyLoaderTests + ) = test_util.test_both(SourceOnlyLoaderTests, util=util, + loader_mock=SPLIT_SOL) @unittest.skipIf(sys.dont_write_bytecode, "sys.dont_write_bytecode is true") @@ -896,15 +894,10 @@ class SourceLoaderBytecodeTests(SourceLoaderTestHarness): self.verify_code(code_object) -class Frozen_SLBytecodeTests(SourceLoaderBytecodeTests, unittest.TestCase): - loader_mock = Frozen_SL - init = frozen_init - util = frozen_util - -class SourceSLBytecodeTests(SourceLoaderBytecodeTests, unittest.TestCase): - loader_mock = Source_SL - init = source_init - util = source_util +(Frozen_SLBytecodeTests, + SourceSLBytecodeTests + ) = test_util.test_both(SourceLoaderBytecodeTests, init=init, util=util, + loader_mock=SPLIT_SL) class SourceLoaderGetSourceTests: @@ -940,11 +933,10 @@ class SourceLoaderGetSourceTests: self.assertEqual(mock.get_source(name), expect) -class Frozen_SourceOnlyLGetSourceTests(SourceLoaderGetSourceTests, unittest.TestCase): - SourceOnlyLoaderMock = Frozen_SourceOnlyL - -class Source_SourceOnlyLGetSourceTests(SourceLoaderGetSourceTests, unittest.TestCase): - SourceOnlyLoaderMock = Source_SourceOnlyL +(Frozen_SourceOnlyLoaderGetSourceTests, + Source_SourceOnlyLoaderGetSourceTests + ) = test_util.test_both(SourceLoaderGetSourceTests, + SourceOnlyLoaderMock=SPLIT_SOL) if __name__ == '__main__': diff --git a/Lib/test/test_importlib/test_api.py b/Lib/test/test_importlib/test_api.py index 2a2d42b..6bc3c56 100644 --- a/Lib/test/test_importlib/test_api.py +++ b/Lib/test/test_importlib/test_api.py @@ -1,8 +1,8 @@ -from . import util +from . import util as test_util -frozen_init, source_init = util.import_importlib('importlib') -frozen_util, source_util = util.import_importlib('importlib.util') -frozen_machinery, source_machinery = util.import_importlib('importlib.machinery') +init = test_util.import_importlib('importlib') +util = test_util.import_importlib('importlib.util') +machinery = test_util.import_importlib('importlib.machinery') import os.path import sys @@ -18,8 +18,8 @@ class ImportModuleTests: def test_module_import(self): # Test importing a top-level module. - with util.mock_modules('top_level') as mock: - with util.import_state(meta_path=[mock]): + with test_util.mock_modules('top_level') as mock: + with test_util.import_state(meta_path=[mock]): module = self.init.import_module('top_level') self.assertEqual(module.__name__, 'top_level') @@ -28,8 +28,8 @@ class ImportModuleTests: pkg_name = 'pkg' pkg_long_name = '{0}.__init__'.format(pkg_name) name = '{0}.mod'.format(pkg_name) - with util.mock_modules(pkg_long_name, name) as mock: - with util.import_state(meta_path=[mock]): + with test_util.mock_modules(pkg_long_name, name) as mock: + with test_util.import_state(meta_path=[mock]): module = self.init.import_module(name) self.assertEqual(module.__name__, name) @@ -40,16 +40,16 @@ class ImportModuleTests: module_name = 'mod' absolute_name = '{0}.{1}'.format(pkg_name, module_name) relative_name = '.{0}'.format(module_name) - with util.mock_modules(pkg_long_name, absolute_name) as mock: - with util.import_state(meta_path=[mock]): + with test_util.mock_modules(pkg_long_name, absolute_name) as mock: + with test_util.import_state(meta_path=[mock]): self.init.import_module(pkg_name) module = self.init.import_module(relative_name, pkg_name) self.assertEqual(module.__name__, absolute_name) def test_deep_relative_package_import(self): modules = ['a.__init__', 'a.b.__init__', 'a.c'] - with util.mock_modules(*modules) as mock: - with util.import_state(meta_path=[mock]): + with test_util.mock_modules(*modules) as mock: + with test_util.import_state(meta_path=[mock]): self.init.import_module('a') self.init.import_module('a.b') module = self.init.import_module('..c', 'a.b') @@ -61,8 +61,8 @@ class ImportModuleTests: pkg_name = 'pkg' pkg_long_name = '{0}.__init__'.format(pkg_name) name = '{0}.mod'.format(pkg_name) - with util.mock_modules(pkg_long_name, name) as mock: - with util.import_state(meta_path=[mock]): + with test_util.mock_modules(pkg_long_name, name) as mock: + with test_util.import_state(meta_path=[mock]): self.init.import_module(pkg_name) module = self.init.import_module(name, pkg_name) self.assertEqual(module.__name__, name) @@ -86,16 +86,15 @@ class ImportModuleTests: b_load_count += 1 code = {'a': load_a, 'a.b': load_b} modules = ['a.__init__', 'a.b'] - with util.mock_modules(*modules, module_code=code) as mock: - with util.import_state(meta_path=[mock]): + with test_util.mock_modules(*modules, module_code=code) as mock: + with test_util.import_state(meta_path=[mock]): self.init.import_module('a.b') self.assertEqual(b_load_count, 1) -class Frozen_ImportModuleTests(ImportModuleTests, unittest.TestCase): - init = frozen_init -class Source_ImportModuleTests(ImportModuleTests, unittest.TestCase): - init = source_init +(Frozen_ImportModuleTests, + Source_ImportModuleTests + ) = test_util.test_both(ImportModuleTests, init=init) class FindLoaderTests: @@ -107,7 +106,7 @@ class FindLoaderTests: def test_sys_modules(self): # If a module with __loader__ is in sys.modules, then return it. name = 'some_mod' - with util.uncache(name): + with test_util.uncache(name): module = types.ModuleType(name) loader = 'a loader!' module.__loader__ = loader @@ -120,7 +119,7 @@ class FindLoaderTests: def test_sys_modules_loader_is_None(self): # If sys.modules[name].__loader__ is None, raise ValueError. name = 'some_mod' - with util.uncache(name): + with test_util.uncache(name): module = types.ModuleType(name) module.__loader__ = None sys.modules[name] = module @@ -133,7 +132,7 @@ class FindLoaderTests: # Should raise ValueError # Issue #17099 name = 'some_mod' - with util.uncache(name): + with test_util.uncache(name): module = types.ModuleType(name) try: del module.__loader__ @@ -148,8 +147,8 @@ class FindLoaderTests: def test_success(self): # Return the loader found on sys.meta_path. name = 'some_mod' - with util.uncache(name): - with util.import_state(meta_path=[self.FakeMetaFinder]): + with test_util.uncache(name): + with test_util.import_state(meta_path=[self.FakeMetaFinder]): with warnings.catch_warnings(): warnings.simplefilter('ignore', DeprecationWarning) self.assertEqual((name, None), self.init.find_loader(name)) @@ -158,8 +157,8 @@ class FindLoaderTests: # Searching on a path should work. name = 'some_mod' path = 'path to some place' - with util.uncache(name): - with util.import_state(meta_path=[self.FakeMetaFinder]): + with test_util.uncache(name): + with test_util.import_state(meta_path=[self.FakeMetaFinder]): with warnings.catch_warnings(): warnings.simplefilter('ignore', DeprecationWarning) self.assertEqual((name, path), @@ -171,11 +170,10 @@ class FindLoaderTests: warnings.simplefilter('ignore', DeprecationWarning) self.assertIsNone(self.init.find_loader('nevergoingtofindthismodule')) -class Frozen_FindLoaderTests(FindLoaderTests, unittest.TestCase): - init = frozen_init -class Source_FindLoaderTests(FindLoaderTests, unittest.TestCase): - init = source_init +(Frozen_FindLoaderTests, + Source_FindLoaderTests + ) = test_util.test_both(FindLoaderTests, init=init) class ReloadTests: @@ -195,10 +193,10 @@ class ReloadTests: module = type(sys)('top_level') module.spam = 3 sys.modules['top_level'] = module - mock = util.mock_modules('top_level', - module_code={'top_level': code}) + mock = test_util.mock_modules('top_level', + module_code={'top_level': code}) with mock: - with util.import_state(meta_path=[mock]): + with test_util.import_state(meta_path=[mock]): module = self.init.import_module('top_level') reloaded = self.init.reload(module) actual = sys.modules['top_level'] @@ -230,7 +228,7 @@ class ReloadTests: def test_reload_location_changed(self): name = 'spam' with support.temp_cwd(None) as cwd: - with util.uncache('spam'): + with test_util.uncache('spam'): with support.DirsOnSysPath(cwd): # Start as a plain module. self.init.invalidate_caches() @@ -281,7 +279,7 @@ class ReloadTests: def test_reload_namespace_changed(self): name = 'spam' with support.temp_cwd(None) as cwd: - with util.uncache('spam'): + with test_util.uncache('spam'): with support.DirsOnSysPath(cwd): # Start as a namespace package. self.init.invalidate_caches() @@ -338,20 +336,16 @@ class ReloadTests: # See #19851. name = 'spam' subname = 'ham' - with util.temp_module(name, pkg=True) as pkg_dir: - fullname, _ = util.submodule(name, subname, pkg_dir) + with test_util.temp_module(name, pkg=True) as pkg_dir: + fullname, _ = test_util.submodule(name, subname, pkg_dir) ham = self.init.import_module(fullname) reloaded = self.init.reload(ham) self.assertIs(reloaded, ham) -class Frozen_ReloadTests(ReloadTests, unittest.TestCase): - init = frozen_init - util = frozen_util - -class Source_ReloadTests(ReloadTests, unittest.TestCase): - init = source_init - util = source_util +(Frozen_ReloadTests, + Source_ReloadTests + ) = test_util.test_both(ReloadTests, init=init, util=util) class InvalidateCacheTests: @@ -384,11 +378,10 @@ class InvalidateCacheTests: self.addCleanup(lambda: sys.path_importer_cache.__delitem__(key)) self.init.invalidate_caches() # Shouldn't trigger an exception. -class Frozen_InvalidateCacheTests(InvalidateCacheTests, unittest.TestCase): - init = frozen_init -class Source_InvalidateCacheTests(InvalidateCacheTests, unittest.TestCase): - init = source_init +(Frozen_InvalidateCacheTests, + Source_InvalidateCacheTests + ) = test_util.test_both(InvalidateCacheTests, init=init) class FrozenImportlibTests(unittest.TestCase): @@ -398,6 +391,7 @@ class FrozenImportlibTests(unittest.TestCase): # Can't do an isinstance() check since separate copies of importlib # may have been used for import, so just check the name is not for the # frozen loader. + source_init = init['Source'] self.assertNotEqual(source_init.__loader__.__class__.__name__, 'FrozenImporter') @@ -426,11 +420,10 @@ class StartupTests: elif self.machinery.FrozenImporter.find_module(name): self.assertIsNot(module.__spec__, None) -class Frozen_StartupTests(StartupTests, unittest.TestCase): - machinery = frozen_machinery -class Source_StartupTests(StartupTests, unittest.TestCase): - machinery = source_machinery +(Frozen_StartupTests, + Source_StartupTests + ) = test_util.test_both(StartupTests, machinery=machinery) if __name__ == '__main__': diff --git a/Lib/test/test_importlib/test_lazy.py b/Lib/test/test_importlib/test_lazy.py new file mode 100644 index 0000000..2e191bb --- /dev/null +++ b/Lib/test/test_importlib/test_lazy.py @@ -0,0 +1,132 @@ +import importlib +from importlib import abc +from importlib import util +import unittest + +from . import util as test_util + + +class CollectInit: + + def __init__(self, *args, **kwargs): + self.args = args + self.kwargs = kwargs + + def exec_module(self, module): + return self + + +class LazyLoaderFactoryTests(unittest.TestCase): + + def test_init(self): + factory = util.LazyLoader.factory(CollectInit) + # E.g. what importlib.machinery.FileFinder instantiates loaders with + # plus keyword arguments. + lazy_loader = factory('module name', 'module path', kw='kw') + loader = lazy_loader.loader + self.assertEqual(('module name', 'module path'), loader.args) + self.assertEqual({'kw': 'kw'}, loader.kwargs) + + def test_validation(self): + # No exec_module(), no lazy loading. + with self.assertRaises(TypeError): + util.LazyLoader.factory(object) + + +class TestingImporter(abc.MetaPathFinder, abc.Loader): + + module_name = 'lazy_loader_test' + mutated_name = 'changed' + loaded = None + source_code = 'attr = 42; __name__ = {!r}'.format(mutated_name) + + def find_spec(self, name, path, target=None): + if name != self.module_name: + return None + return util.spec_from_loader(name, util.LazyLoader(self)) + + def exec_module(self, module): + exec(self.source_code, module.__dict__) + self.loaded = module + + +class LazyLoaderTests(unittest.TestCase): + + def test_init(self): + with self.assertRaises(TypeError): + util.LazyLoader(object) + + def new_module(self, source_code=None): + loader = TestingImporter() + if source_code is not None: + loader.source_code = source_code + spec = util.spec_from_loader(TestingImporter.module_name, + util.LazyLoader(loader)) + module = spec.loader.create_module(spec) + module.__spec__ = spec + module.__loader__ = spec.loader + spec.loader.exec_module(module) + # Module is now lazy. + self.assertIsNone(loader.loaded) + return module + + def test_e2e(self): + # End-to-end test to verify the load is in fact lazy. + importer = TestingImporter() + assert importer.loaded is None + with test_util.uncache(importer.module_name): + with test_util.import_state(meta_path=[importer]): + module = importlib.import_module(importer.module_name) + self.assertIsNone(importer.loaded) + # Trigger load. + self.assertEqual(module.__loader__, importer) + self.assertIsNotNone(importer.loaded) + self.assertEqual(module, importer.loaded) + + def test_attr_unchanged(self): + # An attribute only mutated as a side-effect of import should not be + # changed needlessly. + module = self.new_module() + self.assertEqual(TestingImporter.mutated_name, module.__name__) + + def test_new_attr(self): + # A new attribute should persist. + module = self.new_module() + module.new_attr = 42 + self.assertEqual(42, module.new_attr) + + def test_mutated_preexisting_attr(self): + # Changing an attribute that already existed on the module -- + # e.g. __name__ -- should persist. + module = self.new_module() + module.__name__ = 'bogus' + self.assertEqual('bogus', module.__name__) + + def test_mutated_attr(self): + # Changing an attribute that comes into existence after an import + # should persist. + module = self.new_module() + module.attr = 6 + self.assertEqual(6, module.attr) + + def test_delete_eventual_attr(self): + # Deleting an attribute should stay deleted. + module = self.new_module() + del module.attr + self.assertFalse(hasattr(module, 'attr')) + + def test_delete_preexisting_attr(self): + module = self.new_module() + del module.__name__ + self.assertFalse(hasattr(module, '__name__')) + + def test_module_substitution_error(self): + source_code = 'import sys; sys.modules[__name__] = 42' + module = self.new_module(source_code) + with test_util.uncache(TestingImporter.module_name): + with self.assertRaises(ValueError): + module.__name__ + + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/test/test_importlib/test_locks.py b/Lib/test/test_importlib/test_locks.py index dc97ba1..df0af12 100644 --- a/Lib/test/test_importlib/test_locks.py +++ b/Lib/test/test_importlib/test_locks.py @@ -1,7 +1,6 @@ -from . import util -frozen_init, source_init = util.import_importlib('importlib') -frozen_bootstrap = frozen_init._bootstrap -source_bootstrap = source_init._bootstrap +from . import util as test_util + +init = test_util.import_importlib('importlib') import sys import time @@ -32,14 +31,20 @@ if threading is not None: test_timeout = None # _release_save() unsupported test_release_save_unacquired = None + # lock status in repr unsupported + test_repr = None + test_locked_repr = None - class Frozen_ModuleLockAsRLockTests(ModuleLockAsRLockTests, lock_tests.RLockTests): - LockType = frozen_bootstrap._ModuleLock - - class Source_ModuleLockAsRLockTests(ModuleLockAsRLockTests, lock_tests.RLockTests): - LockType = source_bootstrap._ModuleLock + LOCK_TYPES = {kind: splitinit._bootstrap._ModuleLock + for kind, splitinit in init.items()} + (Frozen_ModuleLockAsRLockTests, + Source_ModuleLockAsRLockTests + ) = test_util.test_both(ModuleLockAsRLockTests, lock_tests.RLockTests, + LockType=LOCK_TYPES) else: + LOCK_TYPES = {} + class Frozen_ModuleLockAsRLockTests(unittest.TestCase): pass @@ -47,78 +52,94 @@ else: pass -class DeadlockAvoidanceTests: - - def setUp(self): - try: - self.old_switchinterval = sys.getswitchinterval() - sys.setswitchinterval(0.000001) - except AttributeError: - self.old_switchinterval = None - - def tearDown(self): - if self.old_switchinterval is not None: - sys.setswitchinterval(self.old_switchinterval) - - def run_deadlock_avoidance_test(self, create_deadlock): - NLOCKS = 10 - locks = [self.LockType(str(i)) for i in range(NLOCKS)] - pairs = [(locks[i], locks[(i+1)%NLOCKS]) for i in range(NLOCKS)] - if create_deadlock: - NTHREADS = NLOCKS - else: - NTHREADS = NLOCKS - 1 - barrier = threading.Barrier(NTHREADS) - results = [] - def _acquire(lock): - """Try to acquire the lock. Return True on success, False on deadlock.""" +if threading is not None: + class DeadlockAvoidanceTests: + + def setUp(self): try: - lock.acquire() - except self.DeadlockError: - return False + self.old_switchinterval = sys.getswitchinterval() + sys.setswitchinterval(0.000001) + except AttributeError: + self.old_switchinterval = None + + def tearDown(self): + if self.old_switchinterval is not None: + sys.setswitchinterval(self.old_switchinterval) + + def run_deadlock_avoidance_test(self, create_deadlock): + NLOCKS = 10 + locks = [self.LockType(str(i)) for i in range(NLOCKS)] + pairs = [(locks[i], locks[(i+1)%NLOCKS]) for i in range(NLOCKS)] + if create_deadlock: + NTHREADS = NLOCKS else: - return True - def f(): - a, b = pairs.pop() - ra = _acquire(a) - barrier.wait() - rb = _acquire(b) - results.append((ra, rb)) - if rb: - b.release() - if ra: - a.release() - lock_tests.Bunch(f, NTHREADS).wait_for_finished() - self.assertEqual(len(results), NTHREADS) - return results - - def test_deadlock(self): - results = self.run_deadlock_avoidance_test(True) - # At least one of the threads detected a potential deadlock on its - # second acquire() call. It may be several of them, because the - # deadlock avoidance mechanism is conservative. - nb_deadlocks = results.count((True, False)) - self.assertGreaterEqual(nb_deadlocks, 1) - self.assertEqual(results.count((True, True)), len(results) - nb_deadlocks) - - def test_no_deadlock(self): - results = self.run_deadlock_avoidance_test(False) - self.assertEqual(results.count((True, False)), 0) - self.assertEqual(results.count((True, True)), len(results)) - -@unittest.skipUnless(threading, "threads needed for this test") -class Frozen_DeadlockAvoidanceTests(DeadlockAvoidanceTests, unittest.TestCase): - LockType = frozen_bootstrap._ModuleLock - DeadlockError = frozen_bootstrap._DeadlockError - -@unittest.skipUnless(threading, "threads needed for this test") -class Source_DeadlockAvoidanceTests(DeadlockAvoidanceTests, unittest.TestCase): - LockType = source_bootstrap._ModuleLock - DeadlockError = source_bootstrap._DeadlockError + NTHREADS = NLOCKS - 1 + barrier = threading.Barrier(NTHREADS) + results = [] + + def _acquire(lock): + """Try to acquire the lock. Return True on success, + False on deadlock.""" + try: + lock.acquire() + except self.DeadlockError: + return False + else: + return True + + def f(): + a, b = pairs.pop() + ra = _acquire(a) + barrier.wait() + rb = _acquire(b) + results.append((ra, rb)) + if rb: + b.release() + if ra: + a.release() + lock_tests.Bunch(f, NTHREADS).wait_for_finished() + self.assertEqual(len(results), NTHREADS) + return results + + def test_deadlock(self): + results = self.run_deadlock_avoidance_test(True) + # At least one of the threads detected a potential deadlock on its + # second acquire() call. It may be several of them, because the + # deadlock avoidance mechanism is conservative. + nb_deadlocks = results.count((True, False)) + self.assertGreaterEqual(nb_deadlocks, 1) + self.assertEqual(results.count((True, True)), len(results) - nb_deadlocks) + + def test_no_deadlock(self): + results = self.run_deadlock_avoidance_test(False) + self.assertEqual(results.count((True, False)), 0) + self.assertEqual(results.count((True, True)), len(results)) + + + DEADLOCK_ERRORS = {kind: splitinit._bootstrap._DeadlockError + for kind, splitinit in init.items()} + + (Frozen_DeadlockAvoidanceTests, + Source_DeadlockAvoidanceTests + ) = test_util.test_both(DeadlockAvoidanceTests, + LockType=LOCK_TYPES, + DeadlockError=DEADLOCK_ERRORS) +else: + DEADLOCK_ERRORS = {} + + class Frozen_DeadlockAvoidanceTests(unittest.TestCase): + pass + + class Source_DeadlockAvoidanceTests(unittest.TestCase): + pass class LifetimeTests: + @property + def bootstrap(self): + return self.init._bootstrap + def test_lock_lifetime(self): name = "xyzzy" self.assertNotIn(name, self.bootstrap._module_locks) @@ -135,11 +156,10 @@ class LifetimeTests: self.assertEqual(0, len(self.bootstrap._module_locks), self.bootstrap._module_locks) -class Frozen_LifetimeTests(LifetimeTests, unittest.TestCase): - bootstrap = frozen_bootstrap -class Source_LifetimeTests(LifetimeTests, unittest.TestCase): - bootstrap = source_bootstrap +(Frozen_LifetimeTests, + Source_LifetimeTests + ) = test_util.test_both(LifetimeTests, init=init) @support.reap_threads diff --git a/Lib/test/test_importlib/test_spec.py b/Lib/test/test_importlib/test_spec.py index 71541f6..8b333e8 100644 --- a/Lib/test/test_importlib/test_spec.py +++ b/Lib/test/test_importlib/test_spec.py @@ -1,10 +1,8 @@ -from . import util +from . import util as test_util -frozen_init, source_init = util.import_importlib('importlib') -frozen_bootstrap = frozen_init._bootstrap -source_bootstrap = source_init._bootstrap -frozen_machinery, source_machinery = util.import_importlib('importlib.machinery') -frozen_util, source_util = util.import_importlib('importlib.util') +init = test_util.import_importlib('importlib') +machinery = test_util.import_importlib('importlib.machinery') +util = test_util.import_importlib('importlib.util') import os.path from test.support import CleanImport @@ -36,6 +34,9 @@ class TestLoader: def _is_package(self, name): return self.package + def create_module(self, spec): + return None + class NewLoader(TestLoader): @@ -52,6 +53,8 @@ class LegacyLoader(TestLoader): with warnings.catch_warnings(): warnings.simplefilter("ignore", DeprecationWarning) + frozen_util = util['Frozen'] + @frozen_util.module_for_loader def load_module(self, module): module.ham = self.HAM @@ -221,18 +224,17 @@ class ModuleSpecTests: self.assertEqual(self.loc_spec.cached, 'spam.pyc') -class Frozen_ModuleSpecTests(ModuleSpecTests, unittest.TestCase): - util = frozen_util - machinery = frozen_machinery - - -class Source_ModuleSpecTests(ModuleSpecTests, unittest.TestCase): - util = source_util - machinery = source_machinery +(Frozen_ModuleSpecTests, + Source_ModuleSpecTests + ) = test_util.test_both(ModuleSpecTests, util=util, machinery=machinery) class ModuleSpecMethodsTests: + @property + def bootstrap(self): + return self.init._bootstrap + def setUp(self): self.name = 'spam' self.path = 'spam.py' @@ -243,152 +245,14 @@ class ModuleSpecMethodsTests: origin=self.path) self.loc_spec._set_fileattr = True - # init_module_attrs - - def test_init_module_attrs(self): - module = type(sys)(self.name) - spec = self.machinery.ModuleSpec(self.name, self.loader) - self.bootstrap._SpecMethods(spec).init_module_attrs(module) - - self.assertEqual(module.__name__, spec.name) - self.assertIs(module.__loader__, spec.loader) - self.assertEqual(module.__package__, spec.parent) - self.assertIs(module.__spec__, spec) - self.assertFalse(hasattr(module, '__path__')) - self.assertFalse(hasattr(module, '__file__')) - self.assertFalse(hasattr(module, '__cached__')) - - def test_init_module_attrs_package(self): - module = type(sys)(self.name) - spec = self.machinery.ModuleSpec(self.name, self.loader) - spec.submodule_search_locations = ['spam', 'ham'] - self.bootstrap._SpecMethods(spec).init_module_attrs(module) - - self.assertEqual(module.__name__, spec.name) - self.assertIs(module.__loader__, spec.loader) - self.assertEqual(module.__package__, spec.parent) - self.assertIs(module.__spec__, spec) - self.assertIs(module.__path__, spec.submodule_search_locations) - self.assertFalse(hasattr(module, '__file__')) - self.assertFalse(hasattr(module, '__cached__')) - - def test_init_module_attrs_location(self): - module = type(sys)(self.name) - spec = self.loc_spec - self.bootstrap._SpecMethods(spec).init_module_attrs(module) - - self.assertEqual(module.__name__, spec.name) - self.assertIs(module.__loader__, spec.loader) - self.assertEqual(module.__package__, spec.parent) - self.assertIs(module.__spec__, spec) - self.assertFalse(hasattr(module, '__path__')) - self.assertEqual(module.__file__, spec.origin) - self.assertEqual(module.__cached__, - self.util.cache_from_source(spec.origin)) - - def test_init_module_attrs_different_name(self): - module = type(sys)('eggs') - spec = self.machinery.ModuleSpec(self.name, self.loader) - self.bootstrap._SpecMethods(spec).init_module_attrs(module) - - self.assertEqual(module.__name__, spec.name) - - def test_init_module_attrs_different_spec(self): - module = type(sys)(self.name) - module.__spec__ = self.machinery.ModuleSpec('eggs', object()) - spec = self.machinery.ModuleSpec(self.name, self.loader) - self.bootstrap._SpecMethods(spec).init_module_attrs(module) - - self.assertEqual(module.__name__, spec.name) - self.assertIs(module.__loader__, spec.loader) - self.assertEqual(module.__package__, spec.parent) - self.assertIs(module.__spec__, spec) - - def test_init_module_attrs_already_set(self): - module = type(sys)('ham.eggs') - module.__loader__ = object() - module.__package__ = 'ham' - module.__path__ = ['eggs'] - module.__file__ = 'ham/eggs/__init__.py' - module.__cached__ = self.util.cache_from_source(module.__file__) - original = vars(module).copy() - spec = self.loc_spec - spec.submodule_search_locations = [''] - self.bootstrap._SpecMethods(spec).init_module_attrs(module) - - self.assertIs(module.__loader__, original['__loader__']) - self.assertEqual(module.__package__, original['__package__']) - self.assertIs(module.__path__, original['__path__']) - self.assertEqual(module.__file__, original['__file__']) - self.assertEqual(module.__cached__, original['__cached__']) - - def test_init_module_attrs_immutable(self): - module = object() - spec = self.loc_spec - spec.submodule_search_locations = [''] - self.bootstrap._SpecMethods(spec).init_module_attrs(module) - - self.assertFalse(hasattr(module, '__name__')) - self.assertFalse(hasattr(module, '__loader__')) - self.assertFalse(hasattr(module, '__package__')) - self.assertFalse(hasattr(module, '__spec__')) - self.assertFalse(hasattr(module, '__path__')) - self.assertFalse(hasattr(module, '__file__')) - self.assertFalse(hasattr(module, '__cached__')) - - # create() - - def test_create(self): - created = self.bootstrap._SpecMethods(self.spec).create() - - self.assertEqual(created.__name__, self.spec.name) - self.assertIs(created.__loader__, self.spec.loader) - self.assertEqual(created.__package__, self.spec.parent) - self.assertIs(created.__spec__, self.spec) - self.assertFalse(hasattr(created, '__path__')) - self.assertFalse(hasattr(created, '__file__')) - self.assertFalse(hasattr(created, '__cached__')) - - def test_create_from_loader(self): - module = type(sys.implementation)() - class CreatingLoader(TestLoader): - def create_module(self, spec): - return module - self.spec.loader = CreatingLoader() - created = self.bootstrap._SpecMethods(self.spec).create() - - self.assertIs(created, module) - self.assertEqual(created.__name__, self.spec.name) - self.assertIs(created.__loader__, self.spec.loader) - self.assertEqual(created.__package__, self.spec.parent) - self.assertIs(created.__spec__, self.spec) - self.assertFalse(hasattr(created, '__path__')) - self.assertFalse(hasattr(created, '__file__')) - self.assertFalse(hasattr(created, '__cached__')) - - def test_create_from_loader_not_handled(self): - class CreatingLoader(TestLoader): - def create_module(self, spec): - return None - self.spec.loader = CreatingLoader() - created = self.bootstrap._SpecMethods(self.spec).create() - - self.assertEqual(created.__name__, self.spec.name) - self.assertIs(created.__loader__, self.spec.loader) - self.assertEqual(created.__package__, self.spec.parent) - self.assertIs(created.__spec__, self.spec) - self.assertFalse(hasattr(created, '__path__')) - self.assertFalse(hasattr(created, '__file__')) - self.assertFalse(hasattr(created, '__cached__')) - # exec() def test_exec(self): self.spec.loader = NewLoader() - module = self.bootstrap._SpecMethods(self.spec).create() + module = self.util.module_from_spec(self.spec) sys.modules[self.name] = module self.assertFalse(hasattr(module, 'eggs')) - self.bootstrap._SpecMethods(self.spec).exec(module) + self.bootstrap._exec(self.spec, module) self.assertEqual(module.eggs, 1) @@ -397,7 +261,7 @@ class ModuleSpecMethodsTests: def test_load(self): self.spec.loader = NewLoader() with CleanImport(self.spec.name): - loaded = self.bootstrap._SpecMethods(self.spec).load() + loaded = self.bootstrap._load(self.spec) installed = sys.modules[self.spec.name] self.assertEqual(loaded.eggs, 1) @@ -410,7 +274,7 @@ class ModuleSpecMethodsTests: sys.modules[module.__name__] = replacement self.spec.loader = ReplacingLoader() with CleanImport(self.spec.name): - loaded = self.bootstrap._SpecMethods(self.spec).load() + loaded = self.bootstrap._load(self.spec) installed = sys.modules[self.spec.name] self.assertIs(loaded, replacement) @@ -423,7 +287,7 @@ class ModuleSpecMethodsTests: self.spec.loader = FailedLoader() with CleanImport(self.spec.name): with self.assertRaises(RuntimeError): - loaded = self.bootstrap._SpecMethods(self.spec).load() + loaded = self.bootstrap._load(self.spec) self.assertNotIn(self.spec.name, sys.modules) def test_load_failed_removed(self): @@ -434,20 +298,20 @@ class ModuleSpecMethodsTests: self.spec.loader = FailedLoader() with CleanImport(self.spec.name): with self.assertRaises(RuntimeError): - loaded = self.bootstrap._SpecMethods(self.spec).load() + loaded = self.bootstrap._load(self.spec) self.assertNotIn(self.spec.name, sys.modules) def test_load_legacy(self): self.spec.loader = LegacyLoader() with CleanImport(self.spec.name): - loaded = self.bootstrap._SpecMethods(self.spec).load() + loaded = self.bootstrap._load(self.spec) self.assertEqual(loaded.ham, -1) def test_load_legacy_attributes(self): self.spec.loader = LegacyLoader() with CleanImport(self.spec.name): - loaded = self.bootstrap._SpecMethods(self.spec).load() + loaded = self.bootstrap._load(self.spec) self.assertIs(loaded.__loader__, self.spec.loader) self.assertEqual(loaded.__package__, self.spec.parent) @@ -461,7 +325,7 @@ class ModuleSpecMethodsTests: return module self.spec.loader = ImmutableLoader() with CleanImport(self.spec.name): - loaded = self.bootstrap._SpecMethods(self.spec).load() + loaded = self.bootstrap._load(self.spec) self.assertIs(sys.modules[self.spec.name], module) @@ -470,8 +334,8 @@ class ModuleSpecMethodsTests: def test_reload(self): self.spec.loader = NewLoader() with CleanImport(self.spec.name): - loaded = self.bootstrap._SpecMethods(self.spec).load() - reloaded = self.bootstrap._SpecMethods(self.spec).exec(loaded) + loaded = self.bootstrap._load(self.spec) + reloaded = self.bootstrap._exec(self.spec, loaded) installed = sys.modules[self.spec.name] self.assertEqual(loaded.eggs, 1) @@ -481,9 +345,9 @@ class ModuleSpecMethodsTests: def test_reload_modified(self): self.spec.loader = NewLoader() with CleanImport(self.spec.name): - loaded = self.bootstrap._SpecMethods(self.spec).load() + loaded = self.bootstrap._load(self.spec) loaded.eggs = 2 - reloaded = self.bootstrap._SpecMethods(self.spec).exec(loaded) + reloaded = self.bootstrap._exec(self.spec, loaded) self.assertEqual(loaded.eggs, 1) self.assertIs(reloaded, loaded) @@ -491,9 +355,9 @@ class ModuleSpecMethodsTests: def test_reload_extra_attributes(self): self.spec.loader = NewLoader() with CleanImport(self.spec.name): - loaded = self.bootstrap._SpecMethods(self.spec).load() + loaded = self.bootstrap._load(self.spec) loaded.available = False - reloaded = self.bootstrap._SpecMethods(self.spec).exec(loaded) + reloaded = self.bootstrap._exec(self.spec, loaded) self.assertFalse(loaded.available) self.assertIs(reloaded, loaded) @@ -501,12 +365,12 @@ class ModuleSpecMethodsTests: def test_reload_init_module_attrs(self): self.spec.loader = NewLoader() with CleanImport(self.spec.name): - loaded = self.bootstrap._SpecMethods(self.spec).load() + loaded = self.bootstrap._load(self.spec) loaded.__name__ = 'ham' del loaded.__loader__ del loaded.__package__ del loaded.__spec__ - self.bootstrap._SpecMethods(self.spec).exec(loaded) + self.bootstrap._exec(self.spec, loaded) self.assertEqual(loaded.__name__, self.spec.name) self.assertIs(loaded.__loader__, self.spec.loader) @@ -519,8 +383,8 @@ class ModuleSpecMethodsTests: def test_reload_legacy(self): self.spec.loader = LegacyLoader() with CleanImport(self.spec.name): - loaded = self.bootstrap._SpecMethods(self.spec).load() - reloaded = self.bootstrap._SpecMethods(self.spec).exec(loaded) + loaded = self.bootstrap._load(self.spec) + reloaded = self.bootstrap._exec(self.spec, loaded) installed = sys.modules[self.spec.name] self.assertEqual(loaded.ham, -1) @@ -528,20 +392,18 @@ class ModuleSpecMethodsTests: self.assertIs(installed, loaded) -class Frozen_ModuleSpecMethodsTests(ModuleSpecMethodsTests, unittest.TestCase): - bootstrap = frozen_bootstrap - machinery = frozen_machinery - util = frozen_util - - -class Source_ModuleSpecMethodsTests(ModuleSpecMethodsTests, unittest.TestCase): - bootstrap = source_bootstrap - machinery = source_machinery - util = source_util +(Frozen_ModuleSpecMethodsTests, + Source_ModuleSpecMethodsTests + ) = test_util.test_both(ModuleSpecMethodsTests, init=init, util=util, + machinery=machinery) class ModuleReprTests: + @property + def bootstrap(self): + return self.init._bootstrap + def setUp(self): self.module = type(os)('spam') self.spec = self.machinery.ModuleSpec('spam', TestLoader()) @@ -625,16 +487,10 @@ class ModuleReprTests: self.assertEqual(modrepr, '<module {!r}>'.format('spam')) -class Frozen_ModuleReprTests(ModuleReprTests, unittest.TestCase): - bootstrap = frozen_bootstrap - machinery = frozen_machinery - util = frozen_util - - -class Source_ModuleReprTests(ModuleReprTests, unittest.TestCase): - bootstrap = source_bootstrap - machinery = source_machinery - util = source_util +(Frozen_ModuleReprTests, + Source_ModuleReprTests + ) = test_util.test_both(ModuleReprTests, init=init, util=util, + machinery=machinery) class FactoryTests: @@ -787,13 +643,14 @@ class FactoryTests: # spec_from_file_location() def test_spec_from_file_location_default(self): - if self.machinery is source_machinery: - raise unittest.SkipTest('not sure why this is breaking...') spec = self.util.spec_from_file_location(self.name, self.path) self.assertEqual(spec.name, self.name) + # Need to use a circuitous route to get at importlib.machinery to make + # sure the same class object is used in the isinstance() check as + # would have been used to create the loader. self.assertIsInstance(spec.loader, - self.machinery.SourceFileLoader) + self.util.abc.machinery.SourceFileLoader) self.assertEqual(spec.loader.name, self.name) self.assertEqual(spec.loader.path, self.path) self.assertEqual(spec.origin, self.path) @@ -947,11 +804,10 @@ class FactoryTests: self.assertTrue(spec.has_location) -class Frozen_FactoryTests(FactoryTests, unittest.TestCase): - util = frozen_util - machinery = frozen_machinery +(Frozen_FactoryTests, + Source_FactoryTests + ) = test_util.test_both(FactoryTests, util=util, machinery=machinery) -class Source_FactoryTests(FactoryTests, unittest.TestCase): - util = source_util - machinery = source_machinery +if __name__ == '__main__': + unittest.main() diff --git a/Lib/test/test_importlib/test_util.py b/Lib/test/test_importlib/test_util.py index b2823c6..69466b2 100644 --- a/Lib/test/test_importlib/test_util.py +++ b/Lib/test/test_importlib/test_util.py @@ -1,10 +1,11 @@ -from importlib import util -from . import util as test_util -frozen_init, source_init = test_util.import_importlib('importlib') -frozen_machinery, source_machinery = test_util.import_importlib('importlib.machinery') -frozen_util, source_util = test_util.import_importlib('importlib.util') +from . import util +abc = util.import_importlib('importlib.abc') +init = util.import_importlib('importlib') +machinery = util.import_importlib('importlib.machinery') +importlib_util = util.import_importlib('importlib.util') import os +import string import sys from test import support import types @@ -32,8 +33,94 @@ class DecodeSourceBytesTests: self.assertEqual(self.util.decode_source(source_bytes), '\n'.join([self.source, self.source])) -Frozen_DecodeSourceBytesTests, Source_DecodeSourceBytesTests = test_util.test_both( - DecodeSourceBytesTests, util=[frozen_util, source_util]) + +(Frozen_DecodeSourceBytesTests, + Source_DecodeSourceBytesTests + ) = util.test_both(DecodeSourceBytesTests, util=importlib_util) + + +class ModuleFromSpecTests: + + def test_no_create_module(self): + class Loader: + def exec_module(self, module): + pass + spec = self.machinery.ModuleSpec('test', Loader()) + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always') + module = self.util.module_from_spec(spec) + self.assertEqual(1, len(w)) + self.assertTrue(issubclass(w[0].category, DeprecationWarning)) + self.assertIn('create_module', str(w[0].message)) + self.assertIsInstance(module, types.ModuleType) + self.assertEqual(module.__name__, spec.name) + + def test_create_module_returns_None(self): + class Loader(self.abc.Loader): + def create_module(self, spec): + return None + spec = self.machinery.ModuleSpec('test', Loader()) + module = self.util.module_from_spec(spec) + self.assertIsInstance(module, types.ModuleType) + self.assertEqual(module.__name__, spec.name) + + def test_create_module(self): + name = 'already set' + class CustomModule(types.ModuleType): + pass + class Loader(self.abc.Loader): + def create_module(self, spec): + module = CustomModule(spec.name) + module.__name__ = name + return module + spec = self.machinery.ModuleSpec('test', Loader()) + module = self.util.module_from_spec(spec) + self.assertIsInstance(module, CustomModule) + self.assertEqual(module.__name__, name) + + def test___name__(self): + spec = self.machinery.ModuleSpec('test', object()) + module = self.util.module_from_spec(spec) + self.assertEqual(module.__name__, spec.name) + + def test___spec__(self): + spec = self.machinery.ModuleSpec('test', object()) + module = self.util.module_from_spec(spec) + self.assertEqual(module.__spec__, spec) + + def test___loader__(self): + loader = object() + spec = self.machinery.ModuleSpec('test', loader) + module = self.util.module_from_spec(spec) + self.assertIs(module.__loader__, loader) + + def test___package__(self): + spec = self.machinery.ModuleSpec('test.pkg', object()) + module = self.util.module_from_spec(spec) + self.assertEqual(module.__package__, spec.parent) + + def test___path__(self): + spec = self.machinery.ModuleSpec('test', object(), is_package=True) + module = self.util.module_from_spec(spec) + self.assertEqual(module.__path__, spec.submodule_search_locations) + + def test___file__(self): + spec = self.machinery.ModuleSpec('test', object(), origin='some/path') + spec.has_location = True + module = self.util.module_from_spec(spec) + self.assertEqual(module.__file__, spec.origin) + + def test___cached__(self): + spec = self.machinery.ModuleSpec('test', object()) + spec.cached = 'some/path' + spec.has_location = True + module = self.util.module_from_spec(spec) + self.assertEqual(module.__cached__, spec.cached) + +(Frozen_ModuleFromSpecTests, + Source_ModuleFromSpecTests +) = util.test_both(ModuleFromSpecTests, abc=abc, machinery=machinery, + util=importlib_util) class ModuleForLoaderTests: @@ -70,7 +157,7 @@ class ModuleForLoaderTests: # Test that when no module exists in sys.modules a new module is # created. module_name = 'a.b.c' - with test_util.uncache(module_name): + with util.uncache(module_name): module = self.return_module(module_name) self.assertIn(module_name, sys.modules) self.assertIsInstance(module, types.ModuleType) @@ -88,7 +175,7 @@ class ModuleForLoaderTests: module = types.ModuleType('a.b.c') module.__loader__ = 42 module.__package__ = 42 - with test_util.uncache(name): + with util.uncache(name): sys.modules[name] = module loader = FakeLoader() returned_module = loader.load_module(name) @@ -100,7 +187,7 @@ class ModuleForLoaderTests: # Test that a module is removed from sys.modules if added but an # exception is raised. name = 'a.b.c' - with test_util.uncache(name): + with util.uncache(name): self.raise_exception(name) self.assertNotIn(name, sys.modules) @@ -108,7 +195,7 @@ class ModuleForLoaderTests: # Test that a failure on reload leaves the module in-place. name = 'a.b.c' module = types.ModuleType(name) - with test_util.uncache(name): + with util.uncache(name): sys.modules[name] = module self.raise_exception(name) self.assertIs(module, sys.modules[name]) @@ -127,7 +214,7 @@ class ModuleForLoaderTests: name = 'mod' module = FalseModule(name) - with test_util.uncache(name): + with util.uncache(name): self.assertFalse(module) sys.modules[name] = module given = self.return_module(name) @@ -146,7 +233,7 @@ class ModuleForLoaderTests: return module name = 'pkg.mod' - with test_util.uncache(name): + with util.uncache(name): loader = FakeLoader(False) module = loader.load_module(name) self.assertEqual(module.__name__, name) @@ -154,15 +241,17 @@ class ModuleForLoaderTests: self.assertEqual(module.__package__, 'pkg') name = 'pkg.sub' - with test_util.uncache(name): + with util.uncache(name): loader = FakeLoader(True) module = loader.load_module(name) self.assertEqual(module.__name__, name) self.assertIs(module.__loader__, loader) self.assertEqual(module.__package__, name) -Frozen_ModuleForLoaderTests, Source_ModuleForLoaderTests = test_util.test_both( - ModuleForLoaderTests, util=[frozen_util, source_util]) + +(Frozen_ModuleForLoaderTests, + Source_ModuleForLoaderTests + ) = util.test_both(ModuleForLoaderTests, util=importlib_util) class SetPackageTests: @@ -222,18 +311,25 @@ class SetPackageTests: self.assertEqual(wrapped.__name__, fxn.__name__) self.assertEqual(wrapped.__qualname__, fxn.__qualname__) -Frozen_SetPackageTests, Source_SetPackageTests = test_util.test_both( - SetPackageTests, util=[frozen_util, source_util]) + +(Frozen_SetPackageTests, + Source_SetPackageTests + ) = util.test_both(SetPackageTests, util=importlib_util) class SetLoaderTests: """Tests importlib.util.set_loader().""" - class DummyLoader: - @util.set_loader - def load_module(self, module): - return self.module + @property + def DummyLoader(self): + # Set DummyLoader on the class lazily. + class DummyLoader: + @self.util.set_loader + def load_module(self, module): + return self.module + self.__class__.DummyLoader = DummyLoader + return DummyLoader def test_no_attribute(self): loader = self.DummyLoader() @@ -262,17 +358,10 @@ class SetLoaderTests: warnings.simplefilter('ignore', DeprecationWarning) self.assertEqual(42, loader.load_module('blah').__loader__) -class Frozen_SetLoaderTests(SetLoaderTests, unittest.TestCase): - class DummyLoader: - @frozen_util.set_loader - def load_module(self, module): - return self.module -class Source_SetLoaderTests(SetLoaderTests, unittest.TestCase): - class DummyLoader: - @source_util.set_loader - def load_module(self, module): - return self.module +(Frozen_SetLoaderTests, + Source_SetLoaderTests + ) = util.test_both(SetLoaderTests, util=importlib_util) class ResolveNameTests: @@ -307,9 +396,10 @@ class ResolveNameTests: with self.assertRaises(ValueError): self.util.resolve_name('..bacon', 'spam') -Frozen_ResolveNameTests, Source_ResolveNameTests = test_util.test_both( - ResolveNameTests, - util=[frozen_util, source_util]) + +(Frozen_ResolveNameTests, + Source_ResolveNameTests + ) = util.test_both(ResolveNameTests, util=importlib_util) class FindSpecTests: @@ -320,7 +410,7 @@ class FindSpecTests: def test_sys_modules(self): name = 'some_mod' - with test_util.uncache(name): + with util.uncache(name): module = types.ModuleType(name) loader = 'a loader!' spec = self.machinery.ModuleSpec(name, loader) @@ -332,7 +422,7 @@ class FindSpecTests: def test_sys_modules_without___loader__(self): name = 'some_mod' - with test_util.uncache(name): + with util.uncache(name): module = types.ModuleType(name) del module.__loader__ loader = 'a loader!' @@ -344,7 +434,7 @@ class FindSpecTests: def test_sys_modules_spec_is_None(self): name = 'some_mod' - with test_util.uncache(name): + with util.uncache(name): module = types.ModuleType(name) module.__spec__ = None sys.modules[name] = module @@ -353,7 +443,7 @@ class FindSpecTests: def test_sys_modules_loader_is_None(self): name = 'some_mod' - with test_util.uncache(name): + with util.uncache(name): module = types.ModuleType(name) spec = self.machinery.ModuleSpec(name, None) module.__spec__ = spec @@ -363,7 +453,7 @@ class FindSpecTests: def test_sys_modules_spec_is_not_set(self): name = 'some_mod' - with test_util.uncache(name): + with util.uncache(name): module = types.ModuleType(name) try: del module.__spec__ @@ -375,20 +465,11 @@ class FindSpecTests: def test_success(self): name = 'some_mod' - with test_util.uncache(name): - with test_util.import_state(meta_path=[self.FakeMetaFinder]): + with util.uncache(name): + with util.import_state(meta_path=[self.FakeMetaFinder]): self.assertEqual((name, None, None), self.util.find_spec(name)) -# def test_success_path(self): -# # Searching on a path should work. -# name = 'some_mod' -# path = 'path to some place' -# with test_util.uncache(name): -# with test_util.import_state(meta_path=[self.FakeMetaFinder]): -# self.assertEqual((name, path, None), -# self.util.find_spec(name, path)) - def test_nothing(self): # None is returned upon failure to find a loader. self.assertIsNone(self.util.find_spec('nevergoingtofindthismodule')) @@ -396,8 +477,8 @@ class FindSpecTests: def test_find_submodule(self): name = 'spam' subname = 'ham' - with test_util.temp_module(name, pkg=True) as pkg_dir: - fullname, _ = test_util.submodule(name, subname, pkg_dir) + with util.temp_module(name, pkg=True) as pkg_dir: + fullname, _ = util.submodule(name, subname, pkg_dir) spec = self.util.find_spec(fullname) self.assertIsNot(spec, None) self.assertIn(name, sorted(sys.modules)) @@ -409,9 +490,9 @@ class FindSpecTests: def test_find_submodule_parent_already_imported(self): name = 'spam' subname = 'ham' - with test_util.temp_module(name, pkg=True) as pkg_dir: + with util.temp_module(name, pkg=True) as pkg_dir: self.init.import_module(name) - fullname, _ = test_util.submodule(name, subname, pkg_dir) + fullname, _ = util.submodule(name, subname, pkg_dir) spec = self.util.find_spec(fullname) self.assertIsNot(spec, None) self.assertIn(name, sorted(sys.modules)) @@ -423,8 +504,8 @@ class FindSpecTests: def test_find_relative_module(self): name = 'spam' subname = 'ham' - with test_util.temp_module(name, pkg=True) as pkg_dir: - fullname, _ = test_util.submodule(name, subname, pkg_dir) + with util.temp_module(name, pkg=True) as pkg_dir: + fullname, _ = util.submodule(name, subname, pkg_dir) relname = '.' + subname spec = self.util.find_spec(relname, name) self.assertIsNot(spec, None) @@ -437,8 +518,8 @@ class FindSpecTests: def test_find_relative_module_missing_package(self): name = 'spam' subname = 'ham' - with test_util.temp_module(name, pkg=True) as pkg_dir: - fullname, _ = test_util.submodule(name, subname, pkg_dir) + with util.temp_module(name, pkg=True) as pkg_dir: + fullname, _ = util.submodule(name, subname, pkg_dir) relname = '.' + subname with self.assertRaises(ValueError): self.util.find_spec(relname) @@ -446,15 +527,10 @@ class FindSpecTests: self.assertNotIn(fullname, sorted(sys.modules)) -class Frozen_FindSpecTests(FindSpecTests, unittest.TestCase): - init = frozen_init - machinery = frozen_machinery - util = frozen_util - -class Source_FindSpecTests(FindSpecTests, unittest.TestCase): - init = source_init - machinery = source_machinery - util = source_util +(Frozen_FindSpecTests, + Source_FindSpecTests + ) = util.test_both(FindSpecTests, init=init, util=importlib_util, + machinery=machinery) class MagicNumberTests: @@ -467,8 +543,10 @@ class MagicNumberTests: # The magic number uses \r\n to come out wrong when splitting on lines. self.assertTrue(self.util.MAGIC_NUMBER.endswith(b'\r\n')) -Frozen_MagicNumberTests, Source_MagicNumberTests = test_util.test_both( - MagicNumberTests, util=[frozen_util, source_util]) + +(Frozen_MagicNumberTests, + Source_MagicNumberTests + ) = util.test_both(MagicNumberTests, util=importlib_util) class PEP3147Tests: @@ -485,7 +563,8 @@ class PEP3147Tests: path = os.path.join('foo', 'bar', 'baz', 'qux.py') expect = os.path.join('foo', 'bar', 'baz', '__pycache__', 'qux.{}.pyc'.format(self.tag)) - self.assertEqual(self.util.cache_from_source(path, True), expect) + self.assertEqual(self.util.cache_from_source(path, optimization=''), + expect) def test_cache_from_source_no_cache_tag(self): # No cache tag means NotImplementedError. @@ -498,43 +577,103 @@ class PEP3147Tests: path = os.path.join('foo.bar', 'file') expect = os.path.join('foo.bar', '__pycache__', 'file{}.pyc'.format(self.tag)) - self.assertEqual(self.util.cache_from_source(path, True), expect) + self.assertEqual(self.util.cache_from_source(path, optimization=''), + expect) - def test_cache_from_source_optimized(self): - # Given the path to a .py file, return the path to its PEP 3147 - # defined .pyo file (i.e. under __pycache__). + def test_cache_from_source_debug_override(self): + # Given the path to a .py file, return the path to its PEP 3147/PEP 488 + # defined .pyc file (i.e. under __pycache__). path = os.path.join('foo', 'bar', 'baz', 'qux.py') - expect = os.path.join('foo', 'bar', 'baz', '__pycache__', - 'qux.{}.pyo'.format(self.tag)) - self.assertEqual(self.util.cache_from_source(path, False), expect) + with warnings.catch_warnings(): + warnings.simplefilter('ignore') + self.assertEqual(self.util.cache_from_source(path, False), + self.util.cache_from_source(path, optimization=1)) + self.assertEqual(self.util.cache_from_source(path, True), + self.util.cache_from_source(path, optimization='')) + with warnings.catch_warnings(): + warnings.simplefilter('error') + with self.assertRaises(DeprecationWarning): + self.util.cache_from_source(path, False) + with self.assertRaises(DeprecationWarning): + self.util.cache_from_source(path, True) def test_cache_from_source_cwd(self): path = 'foo.py' expect = os.path.join('__pycache__', 'foo.{}.pyc'.format(self.tag)) - self.assertEqual(self.util.cache_from_source(path, True), expect) + self.assertEqual(self.util.cache_from_source(path, optimization=''), + expect) def test_cache_from_source_override(self): # When debug_override is not None, it can be any true-ish or false-ish # value. path = os.path.join('foo', 'bar', 'baz.py') - partial_expect = os.path.join('foo', 'bar', '__pycache__', - 'baz.{}.py'.format(self.tag)) - self.assertEqual(self.util.cache_from_source(path, []), partial_expect + 'o') - self.assertEqual(self.util.cache_from_source(path, [17]), - partial_expect + 'c') # However if the bool-ishness can't be determined, the exception # propagates. class Bearish: def __bool__(self): raise RuntimeError - with self.assertRaises(RuntimeError): - self.util.cache_from_source('/foo/bar/baz.py', Bearish()) + with warnings.catch_warnings(): + warnings.simplefilter('ignore') + self.assertEqual(self.util.cache_from_source(path, []), + self.util.cache_from_source(path, optimization=1)) + self.assertEqual(self.util.cache_from_source(path, [17]), + self.util.cache_from_source(path, optimization='')) + with self.assertRaises(RuntimeError): + self.util.cache_from_source('/foo/bar/baz.py', Bearish()) + + + def test_cache_from_source_optimization_empty_string(self): + # Setting 'optimization' to '' leads to no optimization tag (PEP 488). + path = 'foo.py' + expect = os.path.join('__pycache__', 'foo.{}.pyc'.format(self.tag)) + self.assertEqual(self.util.cache_from_source(path, optimization=''), + expect) + + def test_cache_from_source_optimization_None(self): + # Setting 'optimization' to None uses the interpreter's optimization. + # (PEP 488) + path = 'foo.py' + optimization_level = sys.flags.optimize + almost_expect = os.path.join('__pycache__', 'foo.{}'.format(self.tag)) + if optimization_level == 0: + expect = almost_expect + '.pyc' + elif optimization_level <= 2: + expect = almost_expect + '.opt-{}.pyc'.format(optimization_level) + else: + msg = '{!r} is a non-standard optimization level'.format(optimization_level) + self.skipTest(msg) + self.assertEqual(self.util.cache_from_source(path, optimization=None), + expect) + + def test_cache_from_source_optimization_set(self): + # The 'optimization' parameter accepts anything that has a string repr + # that passes str.alnum(). + path = 'foo.py' + valid_characters = string.ascii_letters + string.digits + almost_expect = os.path.join('__pycache__', 'foo.{}'.format(self.tag)) + got = self.util.cache_from_source(path, optimization=valid_characters) + # Test all valid characters are accepted. + self.assertEqual(got, + almost_expect + '.opt-{}.pyc'.format(valid_characters)) + # str() should be called on argument. + self.assertEqual(self.util.cache_from_source(path, optimization=42), + almost_expect + '.opt-42.pyc') + # Invalid characters raise ValueError. + with self.assertRaises(ValueError): + self.util.cache_from_source(path, optimization='path/is/bad') + + def test_cache_from_source_debug_override_optimization_both_set(self): + # Can only set one of the optimization-related parameters. + with warnings.catch_warnings(): + warnings.simplefilter('ignore') + with self.assertRaises(TypeError): + self.util.cache_from_source('foo.py', False, optimization='') @unittest.skipUnless(os.sep == '\\' and os.altsep == '/', 'test meaningful only where os.altsep is defined') def test_sep_altsep_and_sep_cache_from_source(self): # Windows path and PEP 3147 where sep is right of altsep. self.assertEqual( - self.util.cache_from_source('\\foo\\bar\\baz/qux.py', True), + self.util.cache_from_source('\\foo\\bar\\baz/qux.py', optimization=''), '\\foo\\bar\\baz\\__pycache__\\qux.{}.pyc'.format(self.tag)) @unittest.skipUnless(sys.implementation.cache_tag is not None, @@ -572,7 +711,12 @@ class PEP3147Tests: ValueError, self.util.source_from_cache, '__pycache__/foo.pyc') def test_source_from_cache_too_many_dots(self): - # Too many dots in final path component -> ValueError + with self.assertRaises(ValueError): + self.util.source_from_cache( + '__pycache__/foo.cpython-32.opt-1.foo.pyc') + + def test_source_from_cache_not_opt(self): + # Non-`opt-` path component -> ValueError self.assertRaises( ValueError, self.util.source_from_cache, '__pycache__/foo.cpython-32.foo.pyc') @@ -583,9 +727,21 @@ class PEP3147Tests: ValueError, self.util.source_from_cache, '/foo/bar/foo.cpython-32.foo.pyc') -Frozen_PEP3147Tests, Source_PEP3147Tests = test_util.test_both( - PEP3147Tests, - util=[frozen_util, source_util]) + def test_source_from_cache_optimized_bytecode(self): + # Optimized bytecode is not an issue. + path = os.path.join('__pycache__', 'foo.{}.opt-1.pyc'.format(self.tag)) + self.assertEqual(self.util.source_from_cache(path), 'foo.py') + + def test_source_from_cache_missing_optimization(self): + # An empty optimization level is a no-no. + path = os.path.join('__pycache__', 'foo.{}.opt-.pyc'.format(self.tag)) + with self.assertRaises(ValueError): + self.util.source_from_cache(path) + + +(Frozen_PEP3147Tests, + Source_PEP3147Tests + ) = util.test_both(PEP3147Tests, util=importlib_util) if __name__ == '__main__': diff --git a/Lib/test/test_importlib/test_windows.py b/Lib/test/test_importlib/test_windows.py index 96b4adc..c893bcf 100644 --- a/Lib/test/test_importlib/test_windows.py +++ b/Lib/test/test_importlib/test_windows.py @@ -1,14 +1,64 @@ -from . import util -frozen_machinery, source_machinery = util.import_importlib('importlib.machinery') +from . import util as test_util +machinery = test_util.import_importlib('importlib.machinery') +import os +import re import sys import unittest +from test import support +from distutils.util import get_platform +from contextlib import contextmanager +from .util import temp_module + +support.import_module('winreg', required_on=['win']) +from winreg import ( + CreateKey, HKEY_CURRENT_USER, + SetValue, REG_SZ, KEY_ALL_ACCESS, + EnumKey, CloseKey, DeleteKey, OpenKey +) + +def delete_registry_tree(root, subkey): + try: + hkey = OpenKey(root, subkey, access=KEY_ALL_ACCESS) + except OSError: + # subkey does not exist + return + while True: + try: + subsubkey = EnumKey(hkey, 0) + except OSError: + # no more subkeys + break + delete_registry_tree(hkey, subsubkey) + CloseKey(hkey) + DeleteKey(root, subkey) + +@contextmanager +def setup_module(machinery, name, path=None): + if machinery.WindowsRegistryFinder.DEBUG_BUILD: + root = machinery.WindowsRegistryFinder.REGISTRY_KEY_DEBUG + else: + root = machinery.WindowsRegistryFinder.REGISTRY_KEY + key = root.format(fullname=name, + sys_version=sys.version[:3]) + try: + with temp_module(name, "a = 1") as location: + subkey = CreateKey(HKEY_CURRENT_USER, key) + if path is None: + path = location + ".py" + SetValue(subkey, "", REG_SZ, path) + yield + finally: + if machinery.WindowsRegistryFinder.DEBUG_BUILD: + key = os.path.dirname(key) + delete_registry_tree(HKEY_CURRENT_USER, key) @unittest.skipUnless(sys.platform.startswith('win'), 'requires Windows') class WindowsRegistryFinderTests: - - # XXX Need a test that finds the spec via the registry. + # The module name is process-specific, allowing for + # simultaneous runs of the same test on a single machine. + test_module = "spamham{}".format(os.getpid()) def test_find_spec_missing(self): spec = self.machinery.WindowsRegistryFinder.find_spec('spam') @@ -18,12 +68,42 @@ class WindowsRegistryFinderTests: loader = self.machinery.WindowsRegistryFinder.find_module('spam') self.assertIs(loader, None) + def test_module_found(self): + with setup_module(self.machinery, self.test_module): + loader = self.machinery.WindowsRegistryFinder.find_module(self.test_module) + spec = self.machinery.WindowsRegistryFinder.find_spec(self.test_module) + self.assertIsNot(loader, None) + self.assertIsNot(spec, None) + + def test_module_not_found(self): + with setup_module(self.machinery, self.test_module, path="."): + loader = self.machinery.WindowsRegistryFinder.find_module(self.test_module) + spec = self.machinery.WindowsRegistryFinder.find_spec(self.test_module) + self.assertIsNone(loader) + self.assertIsNone(spec) + +(Frozen_WindowsRegistryFinderTests, + Source_WindowsRegistryFinderTests + ) = test_util.test_both(WindowsRegistryFinderTests, machinery=machinery) + +@unittest.skipUnless(sys.platform.startswith('win'), 'requires Windows') +class WindowsExtensionSuffixTests: + def test_tagged_suffix(self): + suffixes = self.machinery.EXTENSION_SUFFIXES + expected_tag = ".cp{0.major}{0.minor}-{1}.pyd".format(sys.version_info, + re.sub('[^a-zA-Z0-9]', '_', get_platform())) + try: + untagged_i = suffixes.index(".pyd") + except ValueError: + untagged_i = suffixes.index("_d.pyd") + expected_tag = "_d" + expected_tag -class Frozen_WindowsRegistryFinderTests(WindowsRegistryFinderTests, - unittest.TestCase): - machinery = frozen_machinery + self.assertIn(expected_tag, suffixes) + # Ensure the tags are in the correct order + tagged_i = suffixes.index(expected_tag) + self.assertLess(tagged_i, untagged_i) -class Source_WindowsRegistryFinderTests(WindowsRegistryFinderTests, - unittest.TestCase): - machinery = source_machinery +(Frozen_WindowsExtensionSuffixTests, + Source_WindowsExtensionSuffixTests + ) = test_util.test_both(WindowsExtensionSuffixTests, machinery=machinery) diff --git a/Lib/test/test_importlib/util.py b/Lib/test/test_importlib/util.py index 885cec3..aa4cd7e 100644 --- a/Lib/test/test_importlib/util.py +++ b/Lib/test/test_importlib/util.py @@ -1,31 +1,85 @@ -from contextlib import contextmanager -from importlib import util, invalidate_caches +import builtins +import contextlib +import errno +import functools +import importlib +from importlib import machinery, util, invalidate_caches +import os import os.path from test import support import unittest import sys +import tempfile import types +BUILTINS = types.SimpleNamespace() +BUILTINS.good_name = None +BUILTINS.bad_name = None +if 'errno' in sys.builtin_module_names: + BUILTINS.good_name = 'errno' +if 'importlib' not in sys.builtin_module_names: + BUILTINS.bad_name = 'importlib' + +EXTENSIONS = types.SimpleNamespace() +EXTENSIONS.path = None +EXTENSIONS.ext = None +EXTENSIONS.filename = None +EXTENSIONS.file_path = None +EXTENSIONS.name = '_testcapi' + +def _extension_details(): + global EXTENSIONS + for path in sys.path: + for ext in machinery.EXTENSION_SUFFIXES: + filename = EXTENSIONS.name + ext + file_path = os.path.join(path, filename) + if os.path.exists(file_path): + EXTENSIONS.path = path + EXTENSIONS.ext = ext + EXTENSIONS.filename = filename + EXTENSIONS.file_path = file_path + return + +_extension_details() + + def import_importlib(module_name): """Import a module from importlib both w/ and w/o _frozen_importlib.""" fresh = ('importlib',) if '.' in module_name else () frozen = support.import_fresh_module(module_name) source = support.import_fresh_module(module_name, fresh=fresh, blocked=('_frozen_importlib',)) + return {'Frozen': frozen, 'Source': source} + + +def specialize_class(cls, kind, base=None, **kwargs): + # XXX Support passing in submodule names--load (and cache) them? + # That would clean up the test modules a bit more. + if base is None: + base = unittest.TestCase + elif not isinstance(base, type): + base = base[kind] + name = '{}_{}'.format(kind, cls.__name__) + bases = (cls, base) + specialized = types.new_class(name, bases) + specialized.__module__ = cls.__module__ + specialized._NAME = cls.__name__ + specialized._KIND = kind + for attr, values in kwargs.items(): + value = values[kind] + setattr(specialized, attr, value) + return specialized + + +def split_frozen(cls, base=None, **kwargs): + frozen = specialize_class(cls, 'Frozen', base, **kwargs) + source = specialize_class(cls, 'Source', base, **kwargs) return frozen, source -def test_both(test_class, **kwargs): - frozen_tests = types.new_class('Frozen_'+test_class.__name__, - (test_class, unittest.TestCase)) - source_tests = types.new_class('Source_'+test_class.__name__, - (test_class, unittest.TestCase)) - frozen_tests.__module__ = source_tests.__module__ = test_class.__module__ - for attr, (frozen_value, source_value) in kwargs.items(): - setattr(frozen_tests, attr, frozen_value) - setattr(source_tests, attr, source_value) - return frozen_tests, source_tests +def test_both(test_class, base=None, **kwargs): + return split_frozen(test_class, base, **kwargs) CASE_INSENSITIVE_FS = True @@ -38,6 +92,10 @@ if sys.platform not in ('win32', 'cygwin'): if not os.path.exists(changed_name): CASE_INSENSITIVE_FS = False +source_importlib = import_importlib('importlib')['Source'] +__import__ = {'Frozen': staticmethod(builtins.__import__), + 'Source': staticmethod(source_importlib.__import__)} + def case_insensitive_tests(test): """Class decorator that nullifies tests requiring a case-insensitive @@ -53,7 +111,7 @@ def submodule(parent, name, pkg_dir, content=''): return '{}.{}'.format(parent, name), path -@contextmanager +@contextlib.contextmanager def uncache(*names): """Uncache a module from sys.modules. @@ -79,7 +137,7 @@ def uncache(*names): pass -@contextmanager +@contextlib.contextmanager def temp_module(name, content='', *, pkg=False): conflicts = [n for n in sys.modules if n.partition('.')[0] == name] with support.temp_cwd(None) as cwd: @@ -103,7 +161,7 @@ def temp_module(name, content='', *, pkg=False): yield location -@contextmanager +@contextlib.contextmanager def import_state(**kwargs): """Context manager to manage the various importers and stored state in the sys module. @@ -198,6 +256,7 @@ class mock_modules(_ImporterMock): raise return self.modules[fullname] + class mock_spec(_ImporterMock): """Importer mock using PEP 451 APIs.""" @@ -223,3 +282,99 @@ class mock_spec(_ImporterMock): self.module_code[module.__spec__.name]() except KeyError: pass + + +def writes_bytecode_files(fxn): + """Decorator to protect sys.dont_write_bytecode from mutation and to skip + tests that require it to be set to False.""" + if sys.dont_write_bytecode: + return lambda *args, **kwargs: None + @functools.wraps(fxn) + def wrapper(*args, **kwargs): + original = sys.dont_write_bytecode + sys.dont_write_bytecode = False + try: + to_return = fxn(*args, **kwargs) + finally: + sys.dont_write_bytecode = original + return to_return + return wrapper + + +def ensure_bytecode_path(bytecode_path): + """Ensure that the __pycache__ directory for PEP 3147 pyc file exists. + + :param bytecode_path: File system path to PEP 3147 pyc file. + """ + try: + os.mkdir(os.path.dirname(bytecode_path)) + except OSError as error: + if error.errno != errno.EEXIST: + raise + + +@contextlib.contextmanager +def create_modules(*names): + """Temporarily create each named module with an attribute (named 'attr') + that contains the name passed into the context manager that caused the + creation of the module. + + All files are created in a temporary directory returned by + tempfile.mkdtemp(). This directory is inserted at the beginning of + sys.path. When the context manager exits all created files (source and + bytecode) are explicitly deleted. + + No magic is performed when creating packages! This means that if you create + a module within a package you must also create the package's __init__ as + well. + + """ + source = 'attr = {0!r}' + created_paths = [] + mapping = {} + state_manager = None + uncache_manager = None + try: + temp_dir = tempfile.mkdtemp() + mapping['.root'] = temp_dir + import_names = set() + for name in names: + if not name.endswith('__init__'): + import_name = name + else: + import_name = name[:-len('.__init__')] + import_names.add(import_name) + if import_name in sys.modules: + del sys.modules[import_name] + name_parts = name.split('.') + file_path = temp_dir + for directory in name_parts[:-1]: + file_path = os.path.join(file_path, directory) + if not os.path.exists(file_path): + os.mkdir(file_path) + created_paths.append(file_path) + file_path = os.path.join(file_path, name_parts[-1] + '.py') + with open(file_path, 'w') as file: + file.write(source.format(name)) + created_paths.append(file_path) + mapping[name] = file_path + uncache_manager = uncache(*import_names) + uncache_manager.__enter__() + state_manager = import_state(path=[temp_dir]) + state_manager.__enter__() + yield mapping + finally: + if state_manager is not None: + state_manager.__exit__(None, None, None) + if uncache_manager is not None: + uncache_manager.__exit__(None, None, None) + support.rmtree(temp_dir) + + +def mock_path_hook(*entries, importer): + """A mock sys.path_hooks entry.""" + def hook(entry): + if entry not in entries: + raise ImportError + return importer + return hook |