diff options
author | orivej <orivej@yandex-team.ru> | 2022-02-10 16:45:01 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:01 +0300 |
commit | 2d37894b1b037cf24231090eda8589bbb44fb6fc (patch) | |
tree | be835aa92c6248212e705f25388ebafcf84bc7a1 /contrib/tools/python3/src/Lib/importlib/_bootstrap.py | |
parent | 718c552901d703c502ccbefdfc3c9028d608b947 (diff) | |
download | ydb-2d37894b1b037cf24231090eda8589bbb44fb6fc.tar.gz |
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/tools/python3/src/Lib/importlib/_bootstrap.py')
-rw-r--r-- | contrib/tools/python3/src/Lib/importlib/_bootstrap.py | 2144 |
1 files changed, 1072 insertions, 1072 deletions
diff --git a/contrib/tools/python3/src/Lib/importlib/_bootstrap.py b/contrib/tools/python3/src/Lib/importlib/_bootstrap.py index 7da6e9475a..e00b27ece2 100644 --- a/contrib/tools/python3/src/Lib/importlib/_bootstrap.py +++ b/contrib/tools/python3/src/Lib/importlib/_bootstrap.py @@ -1,80 +1,80 @@ -"""Core implementation of import. - -This module is NOT meant to be directly imported! It has been designed such -that it can be bootstrapped into Python as the implementation of import. As -such it requires the injection of specific modules and attributes in order to -work. One should use importlib as the public-facing version of this module. - -""" -# +"""Core implementation of import. + +This module is NOT meant to be directly imported! It has been designed such +that it can be bootstrapped into Python as the implementation of import. As +such it requires the injection of specific modules and attributes in order to +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 regen-importlib` followed by `make` in order to get the frozen version # of the module 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. -# - -# See importlib._setup() for what is injected into the global namespace. - -# When editing this code be aware that code executed at import time CANNOT -# reference any injected objects! This includes not only global code but also -# anything specified at the class level. - -# Bootstrap-related code ###################################################### - -_bootstrap_external = None - -def _wrap(new, old): - """Simple substitute for functools.update_wrapper.""" - for replace in ['__module__', '__name__', '__qualname__', '__doc__']: - if hasattr(old, replace): - setattr(new, replace, getattr(old, replace)) - new.__dict__.update(old.__dict__) - - -def _new_module(name): - return type(sys)(name) - - -# Module-level locking ######################################################## - -# A dict mapping module names to weakrefs of _ModuleLock instances -# Dictionary protected by the global import lock -_module_locks = {} -# A dict mapping thread ids to _ModuleLock instances -_blocking_on = {} - - -class _DeadlockError(RuntimeError): - pass - - -class _ModuleLock: - """A recursive lock implementation which is able to detect deadlocks - (e.g. thread 1 trying to take locks A then B, and thread 2 trying to - take locks B then A). - """ - - def __init__(self, name): - self.lock = _thread.allocate_lock() - self.wakeup = _thread.allocate_lock() - self.name = name - self.owner = None - self.count = 0 - self.waiters = 0 - - def has_deadlock(self): - # Deadlock avoidance for concurrent circular imports. - me = _thread.get_ident() - tid = self.owner +# all others who don't have a ./python around to freeze the module +# in the early stages of compilation. +# + +# See importlib._setup() for what is injected into the global namespace. + +# When editing this code be aware that code executed at import time CANNOT +# reference any injected objects! This includes not only global code but also +# anything specified at the class level. + +# Bootstrap-related code ###################################################### + +_bootstrap_external = None + +def _wrap(new, old): + """Simple substitute for functools.update_wrapper.""" + for replace in ['__module__', '__name__', '__qualname__', '__doc__']: + if hasattr(old, replace): + setattr(new, replace, getattr(old, replace)) + new.__dict__.update(old.__dict__) + + +def _new_module(name): + return type(sys)(name) + + +# Module-level locking ######################################################## + +# A dict mapping module names to weakrefs of _ModuleLock instances +# Dictionary protected by the global import lock +_module_locks = {} +# A dict mapping thread ids to _ModuleLock instances +_blocking_on = {} + + +class _DeadlockError(RuntimeError): + pass + + +class _ModuleLock: + """A recursive lock implementation which is able to detect deadlocks + (e.g. thread 1 trying to take locks A then B, and thread 2 trying to + take locks B then A). + """ + + def __init__(self, name): + self.lock = _thread.allocate_lock() + self.wakeup = _thread.allocate_lock() + self.name = name + self.owner = None + self.count = 0 + self.waiters = 0 + + def has_deadlock(self): + # Deadlock avoidance for concurrent circular imports. + me = _thread.get_ident() + tid = self.owner seen = set() - while True: - lock = _blocking_on.get(tid) - if lock is None: - return False - tid = lock.owner - if tid == me: - return True + while True: + lock = _blocking_on.get(tid) + if lock is None: + return False + tid = lock.owner + if tid == me: + return True if tid in seen: # bpo 38091: the chain of tid's we encounter here # eventually leads to a fixpoint or a cycle, but @@ -83,519 +83,519 @@ class _ModuleLock: # threads are at the beginning of acquire() below. return False seen.add(tid) - - def acquire(self): - """ - Acquire the module lock. If a potential deadlock is detected, - a _DeadlockError is raised. - Otherwise, the lock is always acquired and True is returned. - """ - tid = _thread.get_ident() - _blocking_on[tid] = self - try: - while True: - with self.lock: - if self.count == 0 or self.owner == tid: - self.owner = tid - self.count += 1 - return True - if self.has_deadlock(): - raise _DeadlockError('deadlock detected by %r' % self) - if self.wakeup.acquire(False): - self.waiters += 1 - # Wait for a release() call - self.wakeup.acquire() - self.wakeup.release() - finally: - del _blocking_on[tid] - - def release(self): - tid = _thread.get_ident() - with self.lock: - if self.owner != tid: - raise RuntimeError('cannot release un-acquired lock') - assert self.count > 0 - self.count -= 1 - if self.count == 0: - self.owner = None - if self.waiters: - self.waiters -= 1 - self.wakeup.release() - - def __repr__(self): - return '_ModuleLock({!r}) at {}'.format(self.name, id(self)) - - -class _DummyModuleLock: - """A simple _ModuleLock equivalent for Python builds without - multi-threading support.""" - - def __init__(self, name): - self.name = name - self.count = 0 - - def acquire(self): - self.count += 1 - return True - - def release(self): - if self.count == 0: - raise RuntimeError('cannot release un-acquired lock') - self.count -= 1 - - def __repr__(self): - return '_DummyModuleLock({!r}) at {}'.format(self.name, id(self)) - - -class _ModuleLockManager: - - def __init__(self, name): - self._name = name - self._lock = None - - def __enter__(self): - self._lock = _get_module_lock(self._name) - self._lock.acquire() - - def __exit__(self, *args, **kwargs): - self._lock.release() - - -# The following two functions are for consumption by Python/import.c. - -def _get_module_lock(name): - """Get or create the module lock for a given module name. - - Acquire/release internally the global import lock to protect - _module_locks.""" - - _imp.acquire_lock() - try: - try: - lock = _module_locks[name]() - except KeyError: - lock = None - - if lock is None: - if _thread is None: - lock = _DummyModuleLock(name) - else: - lock = _ModuleLock(name) - - def cb(ref, name=name): - _imp.acquire_lock() - try: - # bpo-31070: Check if another thread created a new lock - # after the previous lock was destroyed - # but before the weakref callback was called. - if _module_locks.get(name) is ref: - del _module_locks[name] - finally: - _imp.release_lock() - - _module_locks[name] = _weakref.ref(lock, cb) - finally: - _imp.release_lock() - - return lock - - -def _lock_unlock_module(name): - """Acquires then releases the module lock for a given module name. - - This is used to ensure a module is completely initialized, in the - event it is being imported by another thread. - """ - lock = _get_module_lock(name) - try: - lock.acquire() - except _DeadlockError: - # Concurrent circular import, we'll accept a partially initialized - # module object. - pass - else: - lock.release() - -# Frame stripping magic ############################################### -def _call_with_frames_removed(f, *args, **kwds): - """remove_importlib_frames in import.c will always remove sequences - of importlib frames that end with a call to this function - - Use it instead of a normal call in places where including the importlib - frames introduces unwanted noise into the traceback (e.g. when executing - module code) - """ - return f(*args, **kwds) - - -def _verbose_message(message, *args, verbosity=1): - """Print the message to stderr if -v/PYTHONVERBOSE is turned on.""" - if sys.flags.verbose >= verbosity: - if not message.startswith(('#', 'import ')): - message = '# ' + message - print(message.format(*args), file=sys.stderr) - - -def _requires_builtin(fxn): - """Decorator to verify the named module is built-in.""" - def _requires_builtin_wrapper(self, fullname): - if fullname not in sys.builtin_module_names: - raise ImportError('{!r} is not a built-in module'.format(fullname), - name=fullname) - return fxn(self, fullname) - _wrap(_requires_builtin_wrapper, fxn) - return _requires_builtin_wrapper - - -def _requires_frozen(fxn): - """Decorator to verify the named module is frozen.""" - def _requires_frozen_wrapper(self, fullname): - if not _imp.is_frozen(fullname): - raise ImportError('{!r} is not a frozen module'.format(fullname), - name=fullname) - return fxn(self, fullname) - _wrap(_requires_frozen_wrapper, fxn) - return _requires_frozen_wrapper - - -# Typically used by loader classes as a method replacement. -def _load_module_shim(self, 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) - if fullname in sys.modules: - module = sys.modules[fullname] - _exec(spec, module) - return sys.modules[fullname] - else: - return _load(spec) - -# Module specifications ####################################################### - -def _module_repr(module): - # The implementation of ModuleType.__repr__(). - loader = getattr(module, '__loader__', None) - if hasattr(loader, 'module_repr'): - # As soon as BuiltinImporter, FrozenImporter, and NamespaceLoader - # drop their implementations for module_repr. we can add a - # deprecation warning here. - try: - return loader.module_repr(module) - except Exception: - pass - try: - spec = module.__spec__ - except AttributeError: - pass - else: - if spec is not None: - return _module_repr_from_spec(spec) - - # We could use module.__class__.__name__ instead of 'module' in the - # various repr permutations. - try: - name = module.__name__ - except AttributeError: - name = '?' - try: - filename = module.__file__ - except AttributeError: - if loader is None: - return '<module {!r}>'.format(name) - else: - return '<module {!r} ({!r})>'.format(name, loader) - else: - return '<module {!r} from {!r}>'.format(name, filename) - - -class ModuleSpec: - """The specification for a module, used for loading. - - A module's spec is the source for information about the module. For - data associated with the module, including source, use the spec's - loader. - - `name` is the absolute name of the module. `loader` is the loader - to use when loading the module. `parent` is the name of the - package the module is in. The parent is derived from the name. - - `is_package` determines if the module is considered a package or - not. On modules this is reflected by the `__path__` attribute. - - `origin` is the specific location used by the loader from which to - load the module, if that information is available. When filename is - set, origin will match. - - `has_location` indicates that a spec's "origin" reflects a location. - When this is True, `__file__` attribute of the module is set. - - `cached` is the location of the cached bytecode file, if any. It - corresponds to the `__cached__` attribute. - - `submodule_search_locations` is the sequence of path entries to - search when importing submodules. If set, is_package should be - True--and False otherwise. - - Packages are simply modules that (may) have submodules. If a spec - has a non-None value in `submodule_search_locations`, the import - system will consider modules loaded from the spec as packages. - - Only finders (see importlib.abc.MetaPathFinder and - importlib.abc.PathEntryFinder) should modify ModuleSpec instances. - - """ - - def __init__(self, name, loader, *, origin=None, loader_state=None, - is_package=None): - self.name = name - self.loader = loader - self.origin = origin - self.loader_state = loader_state - self.submodule_search_locations = [] if is_package else None - - # file-location attributes - self._set_fileattr = False - self._cached = None - - def __repr__(self): - args = ['name={!r}'.format(self.name), - 'loader={!r}'.format(self.loader)] - if self.origin is not None: - args.append('origin={!r}'.format(self.origin)) - if self.submodule_search_locations is not None: - args.append('submodule_search_locations={}' - .format(self.submodule_search_locations)) - return '{}({})'.format(self.__class__.__name__, ', '.join(args)) - - def __eq__(self, other): - smsl = self.submodule_search_locations - try: - return (self.name == other.name and - self.loader == other.loader and - self.origin == other.origin and - smsl == other.submodule_search_locations and - self.cached == other.cached and - self.has_location == other.has_location) - except AttributeError: + + def acquire(self): + """ + Acquire the module lock. If a potential deadlock is detected, + a _DeadlockError is raised. + Otherwise, the lock is always acquired and True is returned. + """ + tid = _thread.get_ident() + _blocking_on[tid] = self + try: + while True: + with self.lock: + if self.count == 0 or self.owner == tid: + self.owner = tid + self.count += 1 + return True + if self.has_deadlock(): + raise _DeadlockError('deadlock detected by %r' % self) + if self.wakeup.acquire(False): + self.waiters += 1 + # Wait for a release() call + self.wakeup.acquire() + self.wakeup.release() + finally: + del _blocking_on[tid] + + def release(self): + tid = _thread.get_ident() + with self.lock: + if self.owner != tid: + raise RuntimeError('cannot release un-acquired lock') + assert self.count > 0 + self.count -= 1 + if self.count == 0: + self.owner = None + if self.waiters: + self.waiters -= 1 + self.wakeup.release() + + def __repr__(self): + return '_ModuleLock({!r}) at {}'.format(self.name, id(self)) + + +class _DummyModuleLock: + """A simple _ModuleLock equivalent for Python builds without + multi-threading support.""" + + def __init__(self, name): + self.name = name + self.count = 0 + + def acquire(self): + self.count += 1 + return True + + def release(self): + if self.count == 0: + raise RuntimeError('cannot release un-acquired lock') + self.count -= 1 + + def __repr__(self): + return '_DummyModuleLock({!r}) at {}'.format(self.name, id(self)) + + +class _ModuleLockManager: + + def __init__(self, name): + self._name = name + self._lock = None + + def __enter__(self): + self._lock = _get_module_lock(self._name) + self._lock.acquire() + + def __exit__(self, *args, **kwargs): + self._lock.release() + + +# The following two functions are for consumption by Python/import.c. + +def _get_module_lock(name): + """Get or create the module lock for a given module name. + + Acquire/release internally the global import lock to protect + _module_locks.""" + + _imp.acquire_lock() + try: + try: + lock = _module_locks[name]() + except KeyError: + lock = None + + if lock is None: + if _thread is None: + lock = _DummyModuleLock(name) + else: + lock = _ModuleLock(name) + + def cb(ref, name=name): + _imp.acquire_lock() + try: + # bpo-31070: Check if another thread created a new lock + # after the previous lock was destroyed + # but before the weakref callback was called. + if _module_locks.get(name) is ref: + del _module_locks[name] + finally: + _imp.release_lock() + + _module_locks[name] = _weakref.ref(lock, cb) + finally: + _imp.release_lock() + + return lock + + +def _lock_unlock_module(name): + """Acquires then releases the module lock for a given module name. + + This is used to ensure a module is completely initialized, in the + event it is being imported by another thread. + """ + lock = _get_module_lock(name) + try: + lock.acquire() + except _DeadlockError: + # Concurrent circular import, we'll accept a partially initialized + # module object. + pass + else: + lock.release() + +# Frame stripping magic ############################################### +def _call_with_frames_removed(f, *args, **kwds): + """remove_importlib_frames in import.c will always remove sequences + of importlib frames that end with a call to this function + + Use it instead of a normal call in places where including the importlib + frames introduces unwanted noise into the traceback (e.g. when executing + module code) + """ + return f(*args, **kwds) + + +def _verbose_message(message, *args, verbosity=1): + """Print the message to stderr if -v/PYTHONVERBOSE is turned on.""" + if sys.flags.verbose >= verbosity: + if not message.startswith(('#', 'import ')): + message = '# ' + message + print(message.format(*args), file=sys.stderr) + + +def _requires_builtin(fxn): + """Decorator to verify the named module is built-in.""" + def _requires_builtin_wrapper(self, fullname): + if fullname not in sys.builtin_module_names: + raise ImportError('{!r} is not a built-in module'.format(fullname), + name=fullname) + return fxn(self, fullname) + _wrap(_requires_builtin_wrapper, fxn) + return _requires_builtin_wrapper + + +def _requires_frozen(fxn): + """Decorator to verify the named module is frozen.""" + def _requires_frozen_wrapper(self, fullname): + if not _imp.is_frozen(fullname): + raise ImportError('{!r} is not a frozen module'.format(fullname), + name=fullname) + return fxn(self, fullname) + _wrap(_requires_frozen_wrapper, fxn) + return _requires_frozen_wrapper + + +# Typically used by loader classes as a method replacement. +def _load_module_shim(self, 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) + if fullname in sys.modules: + module = sys.modules[fullname] + _exec(spec, module) + return sys.modules[fullname] + else: + return _load(spec) + +# Module specifications ####################################################### + +def _module_repr(module): + # The implementation of ModuleType.__repr__(). + loader = getattr(module, '__loader__', None) + if hasattr(loader, 'module_repr'): + # As soon as BuiltinImporter, FrozenImporter, and NamespaceLoader + # drop their implementations for module_repr. we can add a + # deprecation warning here. + try: + return loader.module_repr(module) + except Exception: + pass + try: + spec = module.__spec__ + except AttributeError: + pass + else: + if spec is not None: + return _module_repr_from_spec(spec) + + # We could use module.__class__.__name__ instead of 'module' in the + # various repr permutations. + try: + name = module.__name__ + except AttributeError: + name = '?' + try: + filename = module.__file__ + except AttributeError: + if loader is None: + return '<module {!r}>'.format(name) + else: + return '<module {!r} ({!r})>'.format(name, loader) + else: + return '<module {!r} from {!r}>'.format(name, filename) + + +class ModuleSpec: + """The specification for a module, used for loading. + + A module's spec is the source for information about the module. For + data associated with the module, including source, use the spec's + loader. + + `name` is the absolute name of the module. `loader` is the loader + to use when loading the module. `parent` is the name of the + package the module is in. The parent is derived from the name. + + `is_package` determines if the module is considered a package or + not. On modules this is reflected by the `__path__` attribute. + + `origin` is the specific location used by the loader from which to + load the module, if that information is available. When filename is + set, origin will match. + + `has_location` indicates that a spec's "origin" reflects a location. + When this is True, `__file__` attribute of the module is set. + + `cached` is the location of the cached bytecode file, if any. It + corresponds to the `__cached__` attribute. + + `submodule_search_locations` is the sequence of path entries to + search when importing submodules. If set, is_package should be + True--and False otherwise. + + Packages are simply modules that (may) have submodules. If a spec + has a non-None value in `submodule_search_locations`, the import + system will consider modules loaded from the spec as packages. + + Only finders (see importlib.abc.MetaPathFinder and + importlib.abc.PathEntryFinder) should modify ModuleSpec instances. + + """ + + def __init__(self, name, loader, *, origin=None, loader_state=None, + is_package=None): + self.name = name + self.loader = loader + self.origin = origin + self.loader_state = loader_state + self.submodule_search_locations = [] if is_package else None + + # file-location attributes + self._set_fileattr = False + self._cached = None + + def __repr__(self): + args = ['name={!r}'.format(self.name), + 'loader={!r}'.format(self.loader)] + if self.origin is not None: + args.append('origin={!r}'.format(self.origin)) + if self.submodule_search_locations is not None: + args.append('submodule_search_locations={}' + .format(self.submodule_search_locations)) + return '{}({})'.format(self.__class__.__name__, ', '.join(args)) + + def __eq__(self, other): + smsl = self.submodule_search_locations + try: + return (self.name == other.name and + self.loader == other.loader and + self.origin == other.origin and + smsl == other.submodule_search_locations and + self.cached == other.cached and + self.has_location == other.has_location) + except AttributeError: return NotImplemented - - @property - def cached(self): - if self._cached is None: - if self.origin is not None and self._set_fileattr: - if _bootstrap_external is None: - raise NotImplementedError - self._cached = _bootstrap_external._get_cached(self.origin) - return self._cached - - @cached.setter - def cached(self, cached): - self._cached = cached - - @property - def parent(self): - """The name of the module's parent.""" - if self.submodule_search_locations is None: - return self.name.rpartition('.')[0] - else: - return self.name - - @property - def has_location(self): - return self._set_fileattr - - @has_location.setter - def has_location(self, value): - self._set_fileattr = bool(value) - - -def spec_from_loader(name, loader, *, origin=None, is_package=None): - """Return a module spec based on various loader methods.""" - if hasattr(loader, 'get_filename'): - if _bootstrap_external is None: - raise NotImplementedError - spec_from_file_location = _bootstrap_external.spec_from_file_location - - if is_package is None: - return spec_from_file_location(name, loader=loader) - search = [] if is_package else None - return spec_from_file_location(name, loader=loader, - submodule_search_locations=search) - - if is_package is None: - if hasattr(loader, 'is_package'): - try: - is_package = loader.is_package(name) - except ImportError: - is_package = None # aka, undefined - else: - # the default - is_package = False - - return ModuleSpec(name, loader, origin=origin, is_package=is_package) - - -def _spec_from_module(module, loader=None, origin=None): - # This function is meant for use in _setup(). - try: - spec = module.__spec__ - except AttributeError: - pass - else: - if spec is not None: - return spec - - name = module.__name__ - if loader is None: - try: - loader = module.__loader__ - except AttributeError: - # loader will stay None. - pass - try: - location = module.__file__ - except AttributeError: - location = None - if origin is None: - if location is None: - try: - origin = loader._ORIGIN - except AttributeError: - origin = None - else: - origin = location - try: - cached = module.__cached__ - except AttributeError: - cached = None - try: - submodule_search_locations = list(module.__path__) - except AttributeError: - submodule_search_locations = None - - spec = ModuleSpec(name, loader, origin=origin) - spec._set_fileattr = False if location is None else True - spec.cached = cached - spec.submodule_search_locations = submodule_search_locations - return spec - - -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: - if _bootstrap_external is None: - raise NotImplementedError - _NamespaceLoader = _bootstrap_external._NamespaceLoader - - loader = _NamespaceLoader.__new__(_NamespaceLoader) - loader._path = spec.submodule_search_locations - spec.loader = loader - # While the docs say that module.__file__ is not set for - # built-in modules, and the code below will avoid setting it if - # spec.has_location is false, this is incorrect for namespace - # packages. Namespace packages have no location, but their - # __spec__.origin is None, and thus their module.__file__ - # should also be None for consistency. While a bit of a hack, - # this is the best place to ensure this consistency. - # - # See # https://docs.python.org/3/library/importlib.html#importlib.abc.Loader.load_module - # and bpo-32305 - module.__file__ = None - 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.__path__ = spec.submodule_search_locations - except AttributeError: - pass - # __file__/__cached__ - if spec.has_location: - if override or getattr(module, '__file__', None) is None: - try: - module.__file__ = spec.origin - except AttributeError: - pass - - if override or getattr(module, '__cached__', None) is None: - if spec.cached is not None: - try: - module.__cached__ = spec.cached - except AttributeError: - pass - return module - - -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) - elif hasattr(spec.loader, 'exec_module'): - raise ImportError('loaders that define exec_module() ' - 'must also define create_module()') - if module is None: - module = _new_module(spec.name) - _init_module_attrs(spec, module) - return module - - -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: - 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) - - -# Used by importlib.reload() and _load_module_shim(). -def _exec(spec, module): - """Execute the spec's specified module in an existing module's namespace.""" - name = spec.name - 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) + + @property + def cached(self): + if self._cached is None: + if self.origin is not None and self._set_fileattr: + if _bootstrap_external is None: + raise NotImplementedError + self._cached = _bootstrap_external._get_cached(self.origin) + return self._cached + + @cached.setter + def cached(self, cached): + self._cached = cached + + @property + def parent(self): + """The name of the module's parent.""" + if self.submodule_search_locations is None: + return self.name.rpartition('.')[0] + else: + return self.name + + @property + def has_location(self): + return self._set_fileattr + + @has_location.setter + def has_location(self, value): + self._set_fileattr = bool(value) + + +def spec_from_loader(name, loader, *, origin=None, is_package=None): + """Return a module spec based on various loader methods.""" + if hasattr(loader, 'get_filename'): + if _bootstrap_external is None: + raise NotImplementedError + spec_from_file_location = _bootstrap_external.spec_from_file_location + + if is_package is None: + return spec_from_file_location(name, loader=loader) + search = [] if is_package else None + return spec_from_file_location(name, loader=loader, + submodule_search_locations=search) + + if is_package is None: + if hasattr(loader, 'is_package'): + try: + is_package = loader.is_package(name) + except ImportError: + is_package = None # aka, undefined + else: + # the default + is_package = False + + return ModuleSpec(name, loader, origin=origin, is_package=is_package) + + +def _spec_from_module(module, loader=None, origin=None): + # This function is meant for use in _setup(). + try: + spec = module.__spec__ + except AttributeError: + pass + else: + if spec is not None: + return spec + + name = module.__name__ + if loader is None: + try: + loader = module.__loader__ + except AttributeError: + # loader will stay None. + pass + try: + location = module.__file__ + except AttributeError: + location = None + if origin is None: + if location is None: + try: + origin = loader._ORIGIN + except AttributeError: + origin = None + else: + origin = location + try: + cached = module.__cached__ + except AttributeError: + cached = None + try: + submodule_search_locations = list(module.__path__) + except AttributeError: + submodule_search_locations = None + + spec = ModuleSpec(name, loader, origin=origin) + spec._set_fileattr = False if location is None else True + spec.cached = cached + spec.submodule_search_locations = submodule_search_locations + return spec + + +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: + if _bootstrap_external is None: + raise NotImplementedError + _NamespaceLoader = _bootstrap_external._NamespaceLoader + + loader = _NamespaceLoader.__new__(_NamespaceLoader) + loader._path = spec.submodule_search_locations + spec.loader = loader + # While the docs say that module.__file__ is not set for + # built-in modules, and the code below will avoid setting it if + # spec.has_location is false, this is incorrect for namespace + # packages. Namespace packages have no location, but their + # __spec__.origin is None, and thus their module.__file__ + # should also be None for consistency. While a bit of a hack, + # this is the best place to ensure this consistency. + # + # See # https://docs.python.org/3/library/importlib.html#importlib.abc.Loader.load_module + # and bpo-32305 + module.__file__ = None + 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.__path__ = spec.submodule_search_locations + except AttributeError: + pass + # __file__/__cached__ + if spec.has_location: + if override or getattr(module, '__file__', None) is None: + try: + module.__file__ = spec.origin + except AttributeError: + pass + + if override or getattr(module, '__cached__', None) is None: + if spec.cached is not None: + try: + module.__cached__ = spec.cached + except AttributeError: + pass + return module + + +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) + elif hasattr(spec.loader, 'exec_module'): + raise ImportError('loaders that define exec_module() ' + 'must also define create_module()') + if module is None: + module = _new_module(spec.name) + _init_module_attrs(spec, module) + return module + + +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: + 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) + + +# Used by importlib.reload() and _load_module_shim(). +def _exec(spec, module): + """Execute the spec's specified module in an existing module's namespace.""" + name = spec.name + 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) try: if spec.loader is None: if spec.submodule_search_locations is None: @@ -617,12 +617,12 @@ def _exec(spec, module): module = sys.modules.pop(spec.name) sys.modules[spec.name] = module return module - - -def _load_backward_compatible(spec): - # (issue19713) Once BuiltinImporter and ExtensionFileLoader - # have exec_module() implemented, we can add a deprecation - # warning here. + + +def _load_backward_compatible(spec): + # (issue19713) Once BuiltinImporter and ExtensionFileLoader + # have exec_module() implemented, we can add a deprecation + # warning here. try: spec.loader.load_module(spec.name) except: @@ -630,41 +630,41 @@ def _load_backward_compatible(spec): module = sys.modules.pop(spec.name) sys.modules[spec.name] = module raise - # The module must be in sys.modules at this point! + # The module must be in sys.modules at this point! # Move it to the end of sys.modules. module = sys.modules.pop(spec.name) sys.modules[spec.name] = module - 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(spec): - # A helper for direct use by the import system. - if spec.loader is not None: + 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(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) - + if not hasattr(spec.loader, 'exec_module'): + return _load_backward_compatible(spec) + + module = module_from_spec(spec) + # This must be done before putting the module in sys.modules # (otherwise an optimization shortcut in import.c becomes # wrong). @@ -693,353 +693,353 @@ def _load_unlocked(spec): _verbose_message('import {!r} # {!r}', spec.name, spec.loader) finally: spec._initializing = False - + return module -# 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. - - If a module is already in sys.modules, that existing module gets - clobbered. - - """ - with _ModuleLockManager(spec.name): - return _load_unlocked(spec) - - -# Loaders ##################################################################### - -class BuiltinImporter: - - """Meta path import for built-in modules. - - All methods are either class or static methods to avoid the need to - instantiate the class. - - """ - +# 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. + + If a module is already in sys.modules, that existing module gets + clobbered. + + """ + with _ModuleLockManager(spec.name): + return _load_unlocked(spec) + + +# Loaders ##################################################################### + +class BuiltinImporter: + + """Meta path import for built-in modules. + + All methods are either class or static methods to avoid the need to + instantiate the class. + + """ + _ORIGIN = "built-in" - @staticmethod - def module_repr(module): - """Return repr for the module. - - The method is deprecated. The import machinery does the job itself. - - """ + @staticmethod + def module_repr(module): + """Return repr for the module. + + The method is deprecated. The import machinery does the job itself. + + """ return f'<module {module.__name__!r} ({BuiltinImporter._ORIGIN})>' - - @classmethod - def find_spec(cls, fullname, path=None, target=None): - if path is not None: - return None - if _imp.is_builtin(fullname): + + @classmethod + def find_spec(cls, fullname, path=None, target=None): + if path is not None: + return None + if _imp.is_builtin(fullname): return spec_from_loader(fullname, cls, origin=cls._ORIGIN) - else: - return None - - @classmethod - def find_module(cls, fullname, path=None): - """Find the built-in module. - - If 'path' is ever specified then the search is considered a failure. - - This method is deprecated. Use find_spec() instead. - - """ - spec = cls.find_spec(fullname, path) - return spec.loader if spec is not None else None - - @classmethod - def create_module(self, spec): - """Create a built-in module""" - if spec.name not in sys.builtin_module_names: - raise ImportError('{!r} is not a built-in module'.format(spec.name), - name=spec.name) - return _call_with_frames_removed(_imp.create_builtin, spec) - - @classmethod - def exec_module(self, module): - """Exec a built-in module""" - _call_with_frames_removed(_imp.exec_builtin, module) - - @classmethod - @_requires_builtin - def get_code(cls, fullname): - """Return None as built-in modules do not have code objects.""" - return None - - @classmethod - @_requires_builtin - def get_source(cls, fullname): - """Return None as built-in modules do not have source code.""" - return None - - @classmethod - @_requires_builtin - def is_package(cls, fullname): - """Return False as built-in modules are never packages.""" - return False - - load_module = classmethod(_load_module_shim) - - -class FrozenImporter: - - """Meta path import for frozen modules. - - All methods are either class or static methods to avoid the need to - instantiate the class. - - """ - + else: + return None + + @classmethod + def find_module(cls, fullname, path=None): + """Find the built-in module. + + If 'path' is ever specified then the search is considered a failure. + + This method is deprecated. Use find_spec() instead. + + """ + spec = cls.find_spec(fullname, path) + return spec.loader if spec is not None else None + + @classmethod + def create_module(self, spec): + """Create a built-in module""" + if spec.name not in sys.builtin_module_names: + raise ImportError('{!r} is not a built-in module'.format(spec.name), + name=spec.name) + return _call_with_frames_removed(_imp.create_builtin, spec) + + @classmethod + def exec_module(self, module): + """Exec a built-in module""" + _call_with_frames_removed(_imp.exec_builtin, module) + + @classmethod + @_requires_builtin + def get_code(cls, fullname): + """Return None as built-in modules do not have code objects.""" + return None + + @classmethod + @_requires_builtin + def get_source(cls, fullname): + """Return None as built-in modules do not have source code.""" + return None + + @classmethod + @_requires_builtin + def is_package(cls, fullname): + """Return False as built-in modules are never packages.""" + return False + + load_module = classmethod(_load_module_shim) + + +class FrozenImporter: + + """Meta path import for frozen modules. + + All methods are either class or static methods to avoid the need to + instantiate the class. + + """ + _ORIGIN = "frozen" - @staticmethod - def module_repr(m): - """Return repr for the module. - - The method is deprecated. The import machinery does the job itself. - - """ + @staticmethod + def module_repr(m): + """Return repr for the module. + + The method is deprecated. The import machinery does the job itself. + + """ return '<module {!r} ({})>'.format(m.__name__, FrozenImporter._ORIGIN) - - @classmethod - def find_spec(cls, fullname, path=None, target=None): - if _imp.is_frozen(fullname): + + @classmethod + def find_spec(cls, fullname, path=None, target=None): + if _imp.is_frozen(fullname): return spec_from_loader(fullname, cls, origin=cls._ORIGIN) - else: - return None - - @classmethod - def find_module(cls, fullname, path=None): - """Find a frozen module. - - This method is deprecated. Use find_spec() instead. - - """ - return cls if _imp.is_frozen(fullname) else None - - @classmethod - def create_module(cls, spec): - """Use default semantics for module creation.""" - - @staticmethod - def exec_module(module): - name = module.__spec__.name - if not _imp.is_frozen(name): - raise ImportError('{!r} is not a frozen module'.format(name), - name=name) - code = _call_with_frames_removed(_imp.get_frozen_object, name) - exec(code, module.__dict__) - - @classmethod - def load_module(cls, fullname): - """Load a frozen module. - - This method is deprecated. Use exec_module() instead. - - """ - return _load_module_shim(cls, fullname) - - @classmethod - @_requires_frozen - def get_code(cls, fullname): - """Return the code object for the frozen module.""" - return _imp.get_frozen_object(fullname) - - @classmethod - @_requires_frozen - def get_source(cls, fullname): - """Return None as frozen modules do not have source code.""" - return None - - @classmethod - @_requires_frozen - def is_package(cls, fullname): - """Return True if the frozen module is a package.""" - return _imp.is_frozen_package(fullname) - - -# Import itself ############################################################### - -class _ImportLockContext: - - """Context manager for the import lock.""" - - def __enter__(self): - """Acquire the import lock.""" - _imp.acquire_lock() - - def __exit__(self, exc_type, exc_value, exc_traceback): - """Release the import lock regardless of any raised exceptions.""" - _imp.release_lock() - - -def _resolve_name(name, package, level): - """Resolve a relative module name to an absolute one.""" - bits = package.rsplit('.', level - 1) - if len(bits) < level: + else: + return None + + @classmethod + def find_module(cls, fullname, path=None): + """Find a frozen module. + + This method is deprecated. Use find_spec() instead. + + """ + return cls if _imp.is_frozen(fullname) else None + + @classmethod + def create_module(cls, spec): + """Use default semantics for module creation.""" + + @staticmethod + def exec_module(module): + name = module.__spec__.name + if not _imp.is_frozen(name): + raise ImportError('{!r} is not a frozen module'.format(name), + name=name) + code = _call_with_frames_removed(_imp.get_frozen_object, name) + exec(code, module.__dict__) + + @classmethod + def load_module(cls, fullname): + """Load a frozen module. + + This method is deprecated. Use exec_module() instead. + + """ + return _load_module_shim(cls, fullname) + + @classmethod + @_requires_frozen + def get_code(cls, fullname): + """Return the code object for the frozen module.""" + return _imp.get_frozen_object(fullname) + + @classmethod + @_requires_frozen + def get_source(cls, fullname): + """Return None as frozen modules do not have source code.""" + return None + + @classmethod + @_requires_frozen + def is_package(cls, fullname): + """Return True if the frozen module is a package.""" + return _imp.is_frozen_package(fullname) + + +# Import itself ############################################################### + +class _ImportLockContext: + + """Context manager for the import lock.""" + + def __enter__(self): + """Acquire the import lock.""" + _imp.acquire_lock() + + def __exit__(self, exc_type, exc_value, exc_traceback): + """Release the import lock regardless of any raised exceptions.""" + _imp.release_lock() + + +def _resolve_name(name, package, level): + """Resolve a relative module name to an absolute one.""" + bits = package.rsplit('.', level - 1) + if len(bits) < level: raise ImportError('attempted relative import beyond top-level package') - base = bits[0] - return '{}.{}'.format(base, name) if name else base - - -def _find_spec_legacy(finder, name, path): - # This would be a good place for a DeprecationWarning if - # we ended up going that route. - loader = finder.find_module(name, path) - if loader is None: - return None - return spec_from_loader(name, loader) - - -def _find_spec(name, path, target=None): - """Find a module's spec.""" - meta_path = sys.meta_path - if meta_path is None: - # PyImport_Cleanup() is running or has been called. - raise ImportError("sys.meta_path is None, Python is likely " - "shutting down") - - if not meta_path: - _warnings.warn('sys.meta_path is empty', ImportWarning) - - # We check sys.modules here for the reload case. While a passed-in - # target will usually indicate a reload there is no guarantee, whereas - # sys.modules provides one. - is_reload = name in sys.modules - for finder in meta_path: - with _ImportLockContext(): - try: - find_spec = finder.find_spec - except AttributeError: - spec = _find_spec_legacy(finder, name, path) - if spec is None: - continue - else: - spec = find_spec(name, path, target) - if spec is not None: - # The parent import may have already imported this module. - if not is_reload and name in sys.modules: - module = sys.modules[name] - try: - __spec__ = module.__spec__ - except AttributeError: - # We use the found spec since that is the one that - # we would have used if the parent module hadn't - # beaten us to the punch. - return spec - else: - if __spec__ is None: - return spec - else: - return __spec__ - else: - return spec - else: - return None - - -def _sanity_check(name, package, level): - """Verify arguments are "sane".""" - if not isinstance(name, str): - raise TypeError('module name must be str, not {}'.format(type(name))) - if level < 0: - raise ValueError('level must be >= 0') - if level > 0: - if not isinstance(package, str): - raise TypeError('__package__ not set to a string') - elif not package: - raise ImportError('attempted relative import with no known parent ' - 'package') - if not name and level == 0: - raise ValueError('Empty module name') - - -_ERR_MSG_PREFIX = 'No module named ' -_ERR_MSG = _ERR_MSG_PREFIX + '{!r}' - -def _find_and_load_unlocked(name, import_): - path = None - parent = name.rpartition('.')[0] - if parent: - if parent not in sys.modules: - _call_with_frames_removed(import_, parent) - # Crazy side-effects! - if name in sys.modules: - return sys.modules[name] - parent_module = sys.modules[parent] - try: - path = parent_module.__path__ - except AttributeError: - msg = (_ERR_MSG + '; {!r} is not a package').format(name, parent) - raise ModuleNotFoundError(msg, name=name) from None - spec = _find_spec(name, path) - if spec is None: - raise ModuleNotFoundError(_ERR_MSG.format(name), name=name) - else: - module = _load_unlocked(spec) - if parent: - # Set the module as an attribute on its parent. - parent_module = sys.modules[parent] + base = bits[0] + return '{}.{}'.format(base, name) if name else base + + +def _find_spec_legacy(finder, name, path): + # This would be a good place for a DeprecationWarning if + # we ended up going that route. + loader = finder.find_module(name, path) + if loader is None: + return None + return spec_from_loader(name, loader) + + +def _find_spec(name, path, target=None): + """Find a module's spec.""" + meta_path = sys.meta_path + if meta_path is None: + # PyImport_Cleanup() is running or has been called. + raise ImportError("sys.meta_path is None, Python is likely " + "shutting down") + + if not meta_path: + _warnings.warn('sys.meta_path is empty', ImportWarning) + + # We check sys.modules here for the reload case. While a passed-in + # target will usually indicate a reload there is no guarantee, whereas + # sys.modules provides one. + is_reload = name in sys.modules + for finder in meta_path: + with _ImportLockContext(): + try: + find_spec = finder.find_spec + except AttributeError: + spec = _find_spec_legacy(finder, name, path) + if spec is None: + continue + else: + spec = find_spec(name, path, target) + if spec is not None: + # The parent import may have already imported this module. + if not is_reload and name in sys.modules: + module = sys.modules[name] + try: + __spec__ = module.__spec__ + except AttributeError: + # We use the found spec since that is the one that + # we would have used if the parent module hadn't + # beaten us to the punch. + return spec + else: + if __spec__ is None: + return spec + else: + return __spec__ + else: + return spec + else: + return None + + +def _sanity_check(name, package, level): + """Verify arguments are "sane".""" + if not isinstance(name, str): + raise TypeError('module name must be str, not {}'.format(type(name))) + if level < 0: + raise ValueError('level must be >= 0') + if level > 0: + if not isinstance(package, str): + raise TypeError('__package__ not set to a string') + elif not package: + raise ImportError('attempted relative import with no known parent ' + 'package') + if not name and level == 0: + raise ValueError('Empty module name') + + +_ERR_MSG_PREFIX = 'No module named ' +_ERR_MSG = _ERR_MSG_PREFIX + '{!r}' + +def _find_and_load_unlocked(name, import_): + path = None + parent = name.rpartition('.')[0] + if parent: + if parent not in sys.modules: + _call_with_frames_removed(import_, parent) + # Crazy side-effects! + if name in sys.modules: + return sys.modules[name] + parent_module = sys.modules[parent] + try: + path = parent_module.__path__ + except AttributeError: + msg = (_ERR_MSG + '; {!r} is not a package').format(name, parent) + raise ModuleNotFoundError(msg, name=name) from None + spec = _find_spec(name, path) + if spec is None: + raise ModuleNotFoundError(_ERR_MSG.format(name), name=name) + else: + module = _load_unlocked(spec) + if parent: + # Set the module as an attribute on its parent. + parent_module = sys.modules[parent] child = name.rpartition('.')[2] try: setattr(parent_module, child, module) except AttributeError: msg = f"Cannot set an attribute on {parent!r} for child module {child!r}" _warnings.warn(msg, ImportWarning) - return module - - -_NEEDS_LOADING = object() - - -def _find_and_load(name, import_): - """Find and load the module.""" - with _ModuleLockManager(name): - module = sys.modules.get(name, _NEEDS_LOADING) - if module is _NEEDS_LOADING: - return _find_and_load_unlocked(name, import_) - - if module is None: - message = ('import of {} halted; ' - 'None in sys.modules'.format(name)) - raise ModuleNotFoundError(message, name=name) - - _lock_unlock_module(name) - return module - - -def _gcd_import(name, package=None, level=0): - """Import and return the module based on its name, the package the call is - being made from, and the level adjustment. - - This function represents the greatest common denominator of functionality - between import_module and __import__. This includes setting __package__ if - the loader did not. - - """ - _sanity_check(name, package, level) - if level > 0: - name = _resolve_name(name, package, level) - return _find_and_load(name, _gcd_import) - - -def _handle_fromlist(module, fromlist, import_, *, recursive=False): - """Figure out what __import__ should return. - - The import_ parameter is a callable which takes the name of module to - import. It is required to decouple the function from assuming importlib's - import implementation is desired. - - """ - # The hell that is fromlist ... - # If a package was imported, try to import stuff from fromlist. + return module + + +_NEEDS_LOADING = object() + + +def _find_and_load(name, import_): + """Find and load the module.""" + with _ModuleLockManager(name): + module = sys.modules.get(name, _NEEDS_LOADING) + if module is _NEEDS_LOADING: + return _find_and_load_unlocked(name, import_) + + if module is None: + message = ('import of {} halted; ' + 'None in sys.modules'.format(name)) + raise ModuleNotFoundError(message, name=name) + + _lock_unlock_module(name) + return module + + +def _gcd_import(name, package=None, level=0): + """Import and return the module based on its name, the package the call is + being made from, and the level adjustment. + + This function represents the greatest common denominator of functionality + between import_module and __import__. This includes setting __package__ if + the loader did not. + + """ + _sanity_check(name, package, level) + if level > 0: + name = _resolve_name(name, package, level) + return _find_and_load(name, _gcd_import) + + +def _handle_fromlist(module, fromlist, import_, *, recursive=False): + """Figure out what __import__ should return. + + The import_ parameter is a callable which takes the name of module to + import. It is required to decouple the function from assuming importlib's + import implementation is desired. + + """ + # The hell that is fromlist ... + # If a package was imported, try to import stuff from fromlist. for x in fromlist: if not isinstance(x, str): if recursive: @@ -1064,126 +1064,126 @@ def _handle_fromlist(module, fromlist, import_, *, recursive=False): sys.modules.get(from_name, _NEEDS_LOADING) is not None): continue raise - return module - - -def _calc___package__(globals): - """Calculate what __package__ should be. - - __package__ is not guaranteed to be defined or could be set to None - to represent that its proper value is unknown. - - """ - package = globals.get('__package__') - spec = globals.get('__spec__') - if package is not None: - if spec is not None and package != spec.parent: - _warnings.warn("__package__ != __spec__.parent " - f"({package!r} != {spec.parent!r})", - ImportWarning, stacklevel=3) - return package - elif spec is not None: - return spec.parent - else: - _warnings.warn("can't resolve package from __spec__ or __package__, " - "falling back on __name__ and __path__", - ImportWarning, stacklevel=3) - package = globals['__name__'] - if '__path__' not in globals: - package = package.rpartition('.')[0] - return package - - -def __import__(name, globals=None, locals=None, fromlist=(), level=0): - """Import a module. - - The 'globals' argument is used to infer where the import is occurring from - to handle relative imports. The 'locals' argument is ignored. The - 'fromlist' argument specifies what should exist as attributes on the module - being imported (e.g. ``from module import <fromlist>``). The 'level' - argument represents the package location to import from in a relative - import (e.g. ``from ..pkg import mod`` would have a 'level' of 2). - - """ - if level == 0: - module = _gcd_import(name) - else: - globals_ = globals if globals is not None else {} - package = _calc___package__(globals_) - module = _gcd_import(name, package, level) - if not fromlist: - # Return up to the first dot in 'name'. This is complicated by the fact - # that 'name' may be relative. - if level == 0: - return _gcd_import(name.partition('.')[0]) - elif not name: - return module - else: - # Figure out where to slice the module's name up to the first dot - # in 'name'. - cut_off = len(name) - len(name.partition('.')[0]) - # Slice end needs to be positive to alleviate need to special-case - # when ``'.' not in name``. - return sys.modules[module.__name__[:len(module.__name__)-cut_off]] + return module + + +def _calc___package__(globals): + """Calculate what __package__ should be. + + __package__ is not guaranteed to be defined or could be set to None + to represent that its proper value is unknown. + + """ + package = globals.get('__package__') + spec = globals.get('__spec__') + if package is not None: + if spec is not None and package != spec.parent: + _warnings.warn("__package__ != __spec__.parent " + f"({package!r} != {spec.parent!r})", + ImportWarning, stacklevel=3) + return package + elif spec is not None: + return spec.parent + else: + _warnings.warn("can't resolve package from __spec__ or __package__, " + "falling back on __name__ and __path__", + ImportWarning, stacklevel=3) + package = globals['__name__'] + if '__path__' not in globals: + package = package.rpartition('.')[0] + return package + + +def __import__(name, globals=None, locals=None, fromlist=(), level=0): + """Import a module. + + The 'globals' argument is used to infer where the import is occurring from + to handle relative imports. The 'locals' argument is ignored. The + 'fromlist' argument specifies what should exist as attributes on the module + being imported (e.g. ``from module import <fromlist>``). The 'level' + argument represents the package location to import from in a relative + import (e.g. ``from ..pkg import mod`` would have a 'level' of 2). + + """ + if level == 0: + module = _gcd_import(name) + else: + globals_ = globals if globals is not None else {} + package = _calc___package__(globals_) + module = _gcd_import(name, package, level) + if not fromlist: + # Return up to the first dot in 'name'. This is complicated by the fact + # that 'name' may be relative. + if level == 0: + return _gcd_import(name.partition('.')[0]) + elif not name: + return module + else: + # Figure out where to slice the module's name up to the first dot + # in 'name'. + cut_off = len(name) - len(name.partition('.')[0]) + # Slice end needs to be positive to alleviate need to special-case + # when ``'.' not in name``. + return sys.modules[module.__name__[:len(module.__name__)-cut_off]] elif hasattr(module, '__path__'): return _handle_fromlist(module, fromlist, _gcd_import) - else: + else: return module - - -def _builtin_from_name(name): - spec = BuiltinImporter.find_spec(name) - if spec is None: - raise ImportError('no built-in module named ' + name) - return _load_unlocked(spec) - - -def _setup(sys_module, _imp_module): - """Setup importlib by importing needed built-in modules and injecting them - into the global namespace. - - As sys is needed for sys.modules access and _imp is needed to load built-in - modules, those two modules must be explicitly passed in. - - """ - global _imp, sys - _imp = _imp_module - sys = sys_module - - # Set up the spec for existing builtin/frozen modules. - module_type = type(sys) - for name, module in sys.modules.items(): - if isinstance(module, module_type): - if name in sys.builtin_module_names: - loader = BuiltinImporter - elif _imp.is_frozen(name): - loader = FrozenImporter - else: - continue - spec = _spec_from_module(module, loader) - _init_module_attrs(spec, module) - - # Directly load built-in modules needed during bootstrap. - self_module = sys.modules[__name__] - for builtin_name in ('_thread', '_warnings', '_weakref'): - if builtin_name not in sys.modules: - builtin_module = _builtin_from_name(builtin_name) - else: - builtin_module = sys.modules[builtin_name] - setattr(self_module, builtin_name, builtin_module) - - -def _install(sys_module, _imp_module): - """Install importers for builtin and frozen modules""" - _setup(sys_module, _imp_module) - - sys.meta_path.append(BuiltinImporter) - sys.meta_path.append(FrozenImporter) - - -def _install_external_importers(): - """Install importers that require external filesystem access""" - global _bootstrap_external - import _frozen_importlib_external - _bootstrap_external = _frozen_importlib_external - _frozen_importlib_external._install(sys.modules[__name__]) + + +def _builtin_from_name(name): + spec = BuiltinImporter.find_spec(name) + if spec is None: + raise ImportError('no built-in module named ' + name) + return _load_unlocked(spec) + + +def _setup(sys_module, _imp_module): + """Setup importlib by importing needed built-in modules and injecting them + into the global namespace. + + As sys is needed for sys.modules access and _imp is needed to load built-in + modules, those two modules must be explicitly passed in. + + """ + global _imp, sys + _imp = _imp_module + sys = sys_module + + # Set up the spec for existing builtin/frozen modules. + module_type = type(sys) + for name, module in sys.modules.items(): + if isinstance(module, module_type): + if name in sys.builtin_module_names: + loader = BuiltinImporter + elif _imp.is_frozen(name): + loader = FrozenImporter + else: + continue + spec = _spec_from_module(module, loader) + _init_module_attrs(spec, module) + + # Directly load built-in modules needed during bootstrap. + self_module = sys.modules[__name__] + for builtin_name in ('_thread', '_warnings', '_weakref'): + if builtin_name not in sys.modules: + builtin_module = _builtin_from_name(builtin_name) + else: + builtin_module = sys.modules[builtin_name] + setattr(self_module, builtin_name, builtin_module) + + +def _install(sys_module, _imp_module): + """Install importers for builtin and frozen modules""" + _setup(sys_module, _imp_module) + + sys.meta_path.append(BuiltinImporter) + sys.meta_path.append(FrozenImporter) + + +def _install_external_importers(): + """Install importers that require external filesystem access""" + global _bootstrap_external + import _frozen_importlib_external + _bootstrap_external = _frozen_importlib_external + _frozen_importlib_external._install(sys.modules[__name__]) |