diff options
author | Brett Cannon <brett@python.org> | 2014-05-30 14:55:29 -0400 |
---|---|---|
committer | Brett Cannon <brett@python.org> | 2014-05-30 14:55:29 -0400 |
commit | 2a17bde930af72995a217f6625d763e828bf5ce1 (patch) | |
tree | e36ddef450d49c50b324d5e2741161f9ea22188c /Lib | |
parent | Closes #21608: Merged documentation update from 3.4. (diff) | |
download | cpython-2a17bde930af72995a217f6625d763e828bf5ce1.tar.gz cpython-2a17bde930af72995a217f6625d763e828bf5ce1.tar.bz2 cpython-2a17bde930af72995a217f6625d763e828bf5ce1.zip |
Issue #20383: Introduce importlib.util.module_from_spec().
Along the way, dismantle importlib._bootstrap._SpecMethods as it was
no longer relevant and constructing the new function required
partially dismantling the class anyway.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/imp.py | 17 | ||||
-rw-r--r-- | Lib/importlib/__init__.py | 3 | ||||
-rw-r--r-- | Lib/importlib/_bootstrap.py | 381 | ||||
-rw-r--r-- | Lib/importlib/abc.py | 2 | ||||
-rw-r--r-- | Lib/importlib/util.py | 1 | ||||
-rw-r--r-- | Lib/pkgutil.py | 2 | ||||
-rwxr-xr-x | Lib/pydoc.py | 9 | ||||
-rw-r--r-- | Lib/runpy.py | 2 | ||||
-rw-r--r-- | Lib/test/test_importlib/test_spec.py | 187 | ||||
-rw-r--r-- | Lib/test/test_importlib/test_util.py | 152 | ||||
-rw-r--r-- | Lib/test/test_tools.py | 4 |
11 files changed, 322 insertions, 438 deletions
diff --git a/Lib/imp.py b/Lib/imp.py index c8449c61554..59ce41cc0a2 100644 --- a/Lib/imp.py +++ b/Lib/imp.py @@ -16,7 +16,7 @@ except ImportError: # Platform doesn't support dynamic loading. load_dynamic = None -from importlib._bootstrap import SourcelessFileLoader, _ERR_MSG, _SpecMethods +from importlib._bootstrap import SourcelessFileLoader, _ERR_MSG, _exec, _load from importlib import machinery from importlib import util @@ -164,11 +164,10 @@ class _LoadSourceCompatibility(_HackedGetData, machinery.SourceFileLoader): def load_source(name, pathname, file=None): loader = _LoadSourceCompatibility(name, pathname, file) spec = util.spec_from_file_location(name, pathname, loader=loader) - methods = _SpecMethods(spec) if name in sys.modules: - module = methods.exec(sys.modules[name]) + module = _exec(spec, sys.modules[name]) else: - module = methods.load() + module = _load(spec) # To allow reloading to potentially work, use a non-hacked loader which # won't rely on a now-closed file object. module.__loader__ = machinery.SourceFileLoader(name, pathname) @@ -185,11 +184,10 @@ def load_compiled(name, pathname, file=None): """**DEPRECATED**""" loader = _LoadCompiledCompatibility(name, pathname, file) spec = util.spec_from_file_location(name, pathname, loader=loader) - methods = _SpecMethods(spec) if name in sys.modules: - module = methods.exec(sys.modules[name]) + module = _exec(spec, sys.modules[name]) else: - module = methods.load() + module = _load(spec) # To allow reloading to potentially work, use a non-hacked loader which # won't rely on a now-closed file object. module.__loader__ = SourcelessFileLoader(name, pathname) @@ -210,11 +208,10 @@ def load_package(name, path): raise ValueError('{!r} is not a package'.format(path)) spec = util.spec_from_file_location(name, path, submodule_search_locations=[]) - methods = _SpecMethods(spec) if name in sys.modules: - return methods.exec(sys.modules[name]) + return _exec(spec, sys.modules[name]) else: - return methods.load() + return _load(spec) def load_module(name, file, filename, details): diff --git a/Lib/importlib/__init__.py b/Lib/importlib/__init__.py index 1bc99474f2a..e0fe4665f4f 100644 --- a/Lib/importlib/__init__.py +++ b/Lib/importlib/__init__.py @@ -145,8 +145,7 @@ def reload(module): pkgpath = None target = module spec = module.__spec__ = _bootstrap._find_spec(name, pkgpath, target) - methods = _bootstrap._SpecMethods(spec) - methods.exec(module) + _bootstrap._exec(spec, module) # The module may have replaced itself in sys.modules! return sys.modules[name] finally: diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py index 705c393eefe..06196296740 100644 --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -9,7 +9,7 @@ work. One should use importlib as the public-facing version of this module. # # IMPORTANT: Whenever making changes to this module, be sure to run # a top-level make in order to get the frozen version of the module -# update. Not doing so will result in the Makefile to fail for +# updated. Not doing so will result in the Makefile to fail for # all others who don't have a ./python around to freeze the module # in the early stages of compilation. # @@ -581,20 +581,19 @@ def _find_module_shim(self, fullname): return loader -def _load_module_shim(self, fullname): +def _load_module_shim(spec, fullname): """Load the specified module into sys.modules and return it. This method is deprecated. Use loader.exec_module instead. """ - spec = spec_from_loader(fullname, self) - methods = _SpecMethods(spec) + spec = spec_from_loader(fullname, spec) if fullname in sys.modules: module = sys.modules[fullname] - methods.exec(module) + _exec(spec, module) return sys.modules[fullname] else: - return methods.load() + return _load(spec) def _validate_bytecode_header(data, source_stats=None, name=None, path=None): @@ -705,7 +704,7 @@ def _module_repr(module): pass else: if spec is not None: - return _SpecMethods(spec).module_repr() + return _module_repr_from_spec(spec) # We could use module.__class__.__name__ instead of 'module' in the # various repr permutations. @@ -991,234 +990,182 @@ def _spec_from_module(module, loader=None, origin=None): return spec -class _SpecMethods: - - """Convenience wrapper around spec objects to provide spec-specific - methods.""" - - # The various spec_from_* functions could be made factory methods here. - - def __init__(self, spec): - self.spec = spec - - def module_repr(self): - """Return the repr to use for the module.""" - # We mostly replicate _module_repr() using the spec attributes. - spec = self.spec - name = '?' if spec.name is None else spec.name - if spec.origin is None: - if spec.loader is None: - return '<module {!r}>'.format(name) - else: - return '<module {!r} ({!r})>'.format(name, spec.loader) - else: - if spec.has_location: - return '<module {!r} from {!r}>'.format(name, spec.origin) - else: - return '<module {!r} ({})>'.format(spec.name, spec.origin) - - def init_module_attrs(self, module, *, _override=False, _force_name=True): - """Set the module's attributes. - - All missing import-related module attributes will be set. Here - is how the spec attributes map onto the module: - - spec.name -> module.__name__ - spec.loader -> module.__loader__ - spec.parent -> module.__package__ - spec -> module.__spec__ - - Optional: - spec.origin -> module.__file__ (if spec.set_fileattr is true) - spec.cached -> module.__cached__ (if __file__ also set) - spec.submodule_search_locations -> module.__path__ (if set) - - """ - spec = self.spec - - # The passed in module may be not support attribute assignment, - # in which case we simply don't set the attributes. - - # __name__ - if (_override or _force_name or - getattr(module, '__name__', None) is None): - try: - module.__name__ = spec.name - except AttributeError: - pass - - # __loader__ - if _override or getattr(module, '__loader__', None) is None: - loader = spec.loader - if loader is None: - # A backward compatibility hack. - if spec.submodule_search_locations is not None: - loader = _NamespaceLoader.__new__(_NamespaceLoader) - loader._path = spec.submodule_search_locations +def _init_module_attrs(spec, module, *, override=False): + # The passed-in module may be not support attribute assignment, + # in which case we simply don't set the attributes. + # __name__ + if (override or getattr(module, '__name__', None) is None): + try: + module.__name__ = spec.name + except AttributeError: + pass + # __loader__ + if override or getattr(module, '__loader__', None) is None: + loader = spec.loader + if loader is None: + # A backward compatibility hack. + if spec.submodule_search_locations is not None: + loader = _NamespaceLoader.__new__(_NamespaceLoader) + loader._path = spec.submodule_search_locations + try: + module.__loader__ = loader + except AttributeError: + pass + # __package__ + if override or getattr(module, '__package__', None) is None: + try: + module.__package__ = spec.parent + except AttributeError: + pass + # __spec__ + try: + module.__spec__ = spec + except AttributeError: + pass + # __path__ + if override or getattr(module, '__path__', None) is None: + if spec.submodule_search_locations is not None: try: - module.__loader__ = loader + module.__path__ = spec.submodule_search_locations except AttributeError: pass - - # __package__ - if _override or getattr(module, '__package__', None) is None: + # __file__/__cached__ + if spec.has_location: + if override or getattr(module, '__file__', None) is None: try: - module.__package__ = spec.parent + module.__file__ = spec.origin except AttributeError: pass - # __spec__ - try: - module.__spec__ = spec - except AttributeError: - pass - - # __path__ - if _override or getattr(module, '__path__', None) is None: - if spec.submodule_search_locations is not None: + if override or getattr(module, '__cached__', None) is None: + if spec.cached is not None: try: - module.__path__ = spec.submodule_search_locations - except AttributeError: - pass - - if spec.has_location: - # __file__ - if _override or getattr(module, '__file__', None) is None: - try: - module.__file__ = spec.origin + module.__cached__ = spec.cached except AttributeError: pass + return module - # __cached__ - if _override or getattr(module, '__cached__', None) is None: - if spec.cached is not None: - try: - module.__cached__ = spec.cached - except AttributeError: - pass - def create(self): - """Return a new module to be loaded. +def module_from_spec(spec): + """Create a module based on the provided spec.""" + # Typically loaders will not implement create_module(). + module = None + if hasattr(spec.loader, 'create_module'): + # If create_module() returns `None` then it means default + # module creation should be used. + module = spec.loader.create_module(spec) + if module is None: + module = _new_module(spec.name) + _init_module_attrs(spec, module) + return module - The import-related module attributes are also set with the - appropriate values from the spec. - """ - spec = self.spec - # Typically loaders will not implement create_module(). - if hasattr(spec.loader, 'create_module'): - # If create_module() returns `None` it means the default - # module creation should be used. - module = spec.loader.create_module(spec) +def _module_repr_from_spec(spec): + """Return the repr to use for the module.""" + # We mostly replicate _module_repr() using the spec attributes. + name = '?' if spec.name is None else spec.name + if spec.origin is None: + if spec.loader is None: + return '<module {!r}>'.format(name) else: - module = None - if module is None: - # This must be done before open() is ever called as the 'io' - # module implicitly imports 'locale' and would otherwise - # trigger an infinite loop. - module = _new_module(spec.name) - self.init_module_attrs(module) - return module - - def _exec(self, module): - """Do everything necessary to execute the module. - - The namespace of `module` is used as the target of execution. - This method uses the loader's `exec_module()` method. + return '<module {!r} ({!r})>'.format(name, spec.loader) + else: + if spec.has_location: + return '<module {!r} from {!r}>'.format(name, spec.origin) + else: + return '<module {!r} ({})>'.format(spec.name, spec.origin) - """ - self.spec.loader.exec_module(module) - # Used by importlib.reload() and _load_module_shim(). - def exec(self, module): - """Execute the spec in an existing module's namespace.""" - name = self.spec.name - _imp.acquire_lock() - with _ModuleLockManager(name): - if sys.modules.get(name) is not module: - msg = 'module {!r} not in sys.modules'.format(name) - raise ImportError(msg, name=name) - if self.spec.loader is None: - if self.spec.submodule_search_locations is None: - raise ImportError('missing loader', name=self.spec.name) - # namespace package - self.init_module_attrs(module, _override=True) - return module - self.init_module_attrs(module, _override=True) - if not hasattr(self.spec.loader, 'exec_module'): - # (issue19713) Once BuiltinImporter and ExtensionFileLoader - # have exec_module() implemented, we can add a deprecation - # warning here. - self.spec.loader.load_module(name) - else: - self._exec(module) - return sys.modules[name] - - def _load_backward_compatible(self): - # (issue19713) Once BuiltinImporter and ExtensionFileLoader - # have exec_module() implemented, we can add a deprecation - # warning here. - spec = self.spec - spec.loader.load_module(spec.name) - # The module must be in sys.modules at this point! - module = sys.modules[spec.name] - if getattr(module, '__loader__', None) is None: - try: - module.__loader__ = spec.loader - except AttributeError: - pass - if getattr(module, '__package__', None) is None: - try: - # Since module.__path__ may not line up with - # spec.submodule_search_paths, we can't necessarily rely - # on spec.parent here. - module.__package__ = module.__name__ - if not hasattr(module, '__path__'): - module.__package__ = spec.name.rpartition('.')[0] - except AttributeError: - pass - if getattr(module, '__spec__', None) is None: - try: - module.__spec__ = spec - except AttributeError: - pass - return module +# Used by importlib.reload() and _load_module_shim(). +def _exec(spec, module): + """Execute the spec in an existing module's namespace.""" + name = spec.name + _imp.acquire_lock() + with _ModuleLockManager(name): + if sys.modules.get(name) is not module: + msg = 'module {!r} not in sys.modules'.format(name) + raise ImportError(msg, name=name) + if spec.loader is None: + if spec.submodule_search_locations is None: + raise ImportError('missing loader', name=spec.name) + # namespace package + _init_module_attrs(spec, module, override=True) + return module + _init_module_attrs(spec, module, override=True) + if not hasattr(spec.loader, 'exec_module'): + # (issue19713) Once BuiltinImporter and ExtensionFileLoader + # have exec_module() implemented, we can add a deprecation + # warning here. + spec.loader.load_module(name) + else: + spec.loader.exec_module(module) + return sys.modules[name] + + +def _load_backward_compatible(spec): + # (issue19713) Once BuiltinImporter and ExtensionFileLoader + # have exec_module() implemented, we can add a deprecation + # warning here. + spec.loader.load_module(spec.name) + # The module must be in sys.modules at this point! + module = sys.modules[spec.name] + if getattr(module, '__loader__', None) is None: + try: + module.__loader__ = spec.loader + except AttributeError: + pass + if getattr(module, '__package__', None) is None: + try: + # Since module.__path__ may not line up with + # spec.submodule_search_paths, we can't necessarily rely + # on spec.parent here. + module.__package__ = module.__name__ + if not hasattr(module, '__path__'): + module.__package__ = spec.name.rpartition('.')[0] + except AttributeError: + pass + if getattr(module, '__spec__', None) is None: + try: + module.__spec__ = spec + except AttributeError: + pass + return module - def _load_unlocked(self): - # A helper for direct use by the import system. - if self.spec.loader is not None: - # not a namespace package - if not hasattr(self.spec.loader, 'exec_module'): - return self._load_backward_compatible() - - module = self.create() - with _installed_safely(module): - if self.spec.loader is None: - if self.spec.submodule_search_locations is None: - raise ImportError('missing loader', name=self.spec.name) - # A namespace package so do nothing. - else: - self._exec(module) +def _load_unlocked(spec): + # A helper for direct use by the import system. + if spec.loader is not None: + # not a namespace package + if not hasattr(spec.loader, 'exec_module'): + return _load_backward_compatible(spec) + + module = module_from_spec(spec) + with _installed_safely(module): + if spec.loader is None: + if spec.submodule_search_locations is None: + raise ImportError('missing loader', name=spec.name) + # A namespace package so do nothing. + else: + spec.loader.exec_module(module) - # We don't ensure that the import-related module attributes get - # set in the sys.modules replacement case. Such modules are on - # their own. - return sys.modules[self.spec.name] + # We don't ensure that the import-related module attributes get + # set in the sys.modules replacement case. Such modules are on + # their own. + return sys.modules[spec.name] - # A method used during testing of _load_unlocked() and by - # _load_module_shim(). - def load(self): - """Return a new module object, loaded by the spec's loader. +# A method used during testing of _load_unlocked() and by +# _load_module_shim(). +def _load(spec): + """Return a new module object, loaded by the spec's loader. - The module is not added to its parent. + The module is not added to its parent. - If a module is already in sys.modules, that existing module gets - clobbered. + If a module is already in sys.modules, that existing module gets + clobbered. - """ - _imp.acquire_lock() - with _ModuleLockManager(self.spec.name): - return self._load_unlocked() + """ + _imp.acquire_lock() + with _ModuleLockManager(spec.name): + return _load_unlocked(spec) def _fix_up_module(ns, name, pathname, cpathname=None): @@ -1800,7 +1747,7 @@ class _NamespacePath: self._path.append(item) -# We use this exclusively in init_module_attrs() for backward-compatibility. +# We use this exclusively in module_from_spec() for backward-compatibility. class _NamespaceLoader: def __init__(self, name, path, path_finder): self._path = _NamespacePath(name, path, path_finder) @@ -2224,7 +2171,7 @@ def _find_and_load_unlocked(name, import_): if spec is None: raise ImportError(_ERR_MSG.format(name), name=name) else: - module = _SpecMethods(spec)._load_unlocked() + module = _load_unlocked(spec) if parent: # Set the module as an attribute on its parent. parent_module = sys.modules[parent] @@ -2359,8 +2306,7 @@ def _builtin_from_name(name): spec = BuiltinImporter.find_spec(name) if spec is None: raise ImportError('no built-in module named ' + name) - methods = _SpecMethods(spec) - return methods._load_unlocked() + return _load_unlocked(spec) def _setup(sys_module, _imp_module): @@ -2391,8 +2337,7 @@ def _setup(sys_module, _imp_module): else: continue spec = _spec_from_module(module, loader) - methods = _SpecMethods(spec) - methods.init_module_attrs(module) + _init_module_attrs(spec, module) # Directly load built-in modules needed during bootstrap. self_module = sys.modules[__name__] diff --git a/Lib/importlib/abc.py b/Lib/importlib/abc.py index 7f6f235971d..6b6a602aaf5 100644 --- a/Lib/importlib/abc.py +++ b/Lib/importlib/abc.py @@ -126,7 +126,7 @@ class Loader(metaclass=abc.ABCMeta): create_module() is optional. """ - # By default, defer to _SpecMethods.create() for the new module. + # By default, defer to default semantics for the new module. return None # We don't define exec_module() here since that would break diff --git a/Lib/importlib/util.py b/Lib/importlib/util.py index e50ef6dc273..2424144b91f 100644 --- a/Lib/importlib/util.py +++ b/Lib/importlib/util.py @@ -3,6 +3,7 @@ from . import abc from ._bootstrap import MAGIC_NUMBER from ._bootstrap import cache_from_source from ._bootstrap import decode_source +from ._bootstrap import module_from_spec from ._bootstrap import source_from_cache from ._bootstrap import spec_from_loader from ._bootstrap import spec_from_file_location diff --git a/Lib/pkgutil.py b/Lib/pkgutil.py index a54e9474d5b..fc4a074f5b8 100644 --- a/Lib/pkgutil.py +++ b/Lib/pkgutil.py @@ -616,7 +616,7 @@ def get_data(package, resource): return None # XXX needs test mod = (sys.modules.get(package) or - importlib._bootstrap._SpecMethods(spec).load()) + importlib._bootstrap._load(spec)) if mod is None or not hasattr(mod, '__file__'): return None diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 220a3cb1ccc..42f65dcf794 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -263,9 +263,8 @@ def synopsis(filename, cache={}): # XXX We probably don't need to pass in the loader here. spec = importlib.util.spec_from_file_location('__temp__', filename, loader=loader) - _spec = importlib._bootstrap._SpecMethods(spec) try: - module = _spec.load() + module = importlib._bootstrap._load(spec) except: return None del sys.modules['__temp__'] @@ -297,9 +296,8 @@ def importfile(path): loader = importlib._bootstrap.SourceFileLoader(name, path) # XXX We probably don't need to pass in the loader here. spec = importlib.util.spec_from_file_location(name, path, loader=loader) - _spec = importlib._bootstrap._SpecMethods(spec) try: - return _spec.load() + return importlib._bootstrap._load(spec) except: raise ErrorDuringImport(path, sys.exc_info()) @@ -2057,9 +2055,8 @@ class ModuleScanner: else: path = None else: - _spec = importlib._bootstrap._SpecMethods(spec) try: - module = _spec.load() + module = importlib._bootstrap._load(spec) except ImportError: if onerror: onerror(modname) diff --git a/Lib/runpy.py b/Lib/runpy.py index 0bb57d76cef..d9c643d6577 100644 --- a/Lib/runpy.py +++ b/Lib/runpy.py @@ -58,7 +58,7 @@ class _ModifiedArgv0(object): self.value = self._sentinel sys.argv[0] = self._saved_value -# TODO: Replace these helpers with importlib._bootstrap._SpecMethods +# TODO: Replace these helpers with importlib._bootstrap functions def _run_code(code, run_globals, init_globals=None, mod_name=None, mod_spec=None, pkg_name=None, script_name=None): diff --git a/Lib/test/test_importlib/test_spec.py b/Lib/test/test_importlib/test_spec.py index 0cb14eea42a..418b4c00758 100644 --- a/Lib/test/test_importlib/test_spec.py +++ b/Lib/test/test_importlib/test_spec.py @@ -242,152 +242,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) @@ -396,7 +258,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) @@ -409,7 +271,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) @@ -422,7 +284,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): @@ -433,20 +295,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) @@ -460,7 +322,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) @@ -469,8 +331,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) @@ -480,9 +342,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) @@ -490,9 +352,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) @@ -500,12 +362,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) @@ -518,8 +380,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) @@ -778,13 +640,14 @@ class FactoryTests: # spec_from_file_location() def test_spec_from_file_location_default(self): - if self.machinery is machinery['Source']: - 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) @@ -941,3 +804,7 @@ class FactoryTests: (Frozen_FactoryTests, Source_FactoryTests ) = test_util.test_both(FactoryTests, util=util, machinery=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 9428471539c..cd9344c0f3a 100644 --- a/Lib/test/test_importlib/test_util.py +++ b/Lib/test/test_importlib/test_util.py @@ -1,8 +1,8 @@ -import importlib.util -from . import util as test_util -init = test_util.import_importlib('importlib') -machinery = test_util.import_importlib('importlib.machinery') -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 sys @@ -35,7 +35,85 @@ class DecodeSourceBytesTests: (Frozen_DecodeSourceBytesTests, Source_DecodeSourceBytesTests - ) = test_util.test_both(DecodeSourceBytesTests, util=util) + ) = util.test_both(DecodeSourceBytesTests, util=importlib_util) + + +class ModuleFromSpecTests: + + def test_no_create_module(self): + class Loader(self.abc.Loader): + pass + 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_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: @@ -72,7 +150,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) @@ -90,7 +168,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) @@ -102,7 +180,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) @@ -110,7 +188,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]) @@ -129,7 +207,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) @@ -148,7 +226,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) @@ -156,7 +234,7 @@ 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) @@ -166,7 +244,7 @@ class ModuleForLoaderTests: (Frozen_ModuleForLoaderTests, Source_ModuleForLoaderTests - ) = test_util.test_both(ModuleForLoaderTests, util=util) + ) = util.test_both(ModuleForLoaderTests, util=importlib_util) class SetPackageTests: @@ -229,7 +307,7 @@ class SetPackageTests: (Frozen_SetPackageTests, Source_SetPackageTests - ) = test_util.test_both(SetPackageTests, util=util) + ) = util.test_both(SetPackageTests, util=importlib_util) class SetLoaderTests: @@ -276,7 +354,7 @@ class SetLoaderTests: (Frozen_SetLoaderTests, Source_SetLoaderTests - ) = test_util.test_both(SetLoaderTests, util=util) + ) = util.test_both(SetLoaderTests, util=importlib_util) class ResolveNameTests: @@ -314,7 +392,7 @@ class ResolveNameTests: (Frozen_ResolveNameTests, Source_ResolveNameTests - ) = test_util.test_both(ResolveNameTests, util=util) + ) = util.test_both(ResolveNameTests, util=importlib_util) class FindSpecTests: @@ -325,7 +403,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) @@ -337,7 +415,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!' @@ -349,7 +427,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 @@ -358,7 +436,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 @@ -368,7 +446,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__ @@ -380,8 +458,8 @@ 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)) @@ -389,8 +467,8 @@ class FindSpecTests: # # 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]): +# with util.uncache(name): +# with util.import_state(meta_path=[self.FakeMetaFinder]): # self.assertEqual((name, path, None), # self.util.find_spec(name, path)) @@ -401,8 +479,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)) @@ -414,9 +492,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)) @@ -428,8 +506,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) @@ -442,8 +520,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) @@ -453,7 +531,7 @@ class FindSpecTests: (Frozen_FindSpecTests, Source_FindSpecTests - ) = test_util.test_both(FindSpecTests, init=init, util=util, + ) = util.test_both(FindSpecTests, init=init, util=importlib_util, machinery=machinery) @@ -470,7 +548,7 @@ class MagicNumberTests: (Frozen_MagicNumberTests, Source_MagicNumberTests - ) = test_util.test_both(MagicNumberTests, util=util) + ) = util.test_both(MagicNumberTests, util=importlib_util) class PEP3147Tests: @@ -588,7 +666,7 @@ class PEP3147Tests: (Frozen_PEP3147Tests, Source_PEP3147Tests - ) = test_util.test_both(PEP3147Tests, util=util) + ) = util.test_both(PEP3147Tests, util=importlib_util) if __name__ == '__main__': diff --git a/Lib/test/test_tools.py b/Lib/test/test_tools.py index 1bf7d54c1ee..2eb80664c9b 100644 --- a/Lib/test/test_tools.py +++ b/Lib/test/test_tools.py @@ -407,7 +407,7 @@ class PdepsTests(unittest.TestCase): def setUpClass(self): path = os.path.join(scriptsdir, 'pdeps.py') spec = importlib.util.spec_from_file_location('pdeps', path) - self.pdeps = importlib._bootstrap._SpecMethods(spec).load() + self.pdeps = importlib._bootstrap._load(spec) @classmethod def tearDownClass(self): @@ -432,7 +432,7 @@ class Gprof2htmlTests(unittest.TestCase): def setUp(self): path = os.path.join(scriptsdir, 'gprof2html.py') spec = importlib.util.spec_from_file_location('gprof2html', path) - self.gprof = importlib._bootstrap._SpecMethods(spec).load() + self.gprof = importlib._bootstrap._load(spec) oldargv = sys.argv def fixup(): sys.argv = oldargv |