mirror of
https://github.com/python/cpython.git
synced 2024-11-30 18:51:15 +01:00
f24fecd4ac
The helper function makes it easier to implement imoprtlib.abc.InspectLoader.get_source() by making that function require just the raw bytes for source code and handling all other details.
70 lines
2.6 KiB
Python
70 lines
2.6 KiB
Python
"""Utility code for constructing importers, etc."""
|
|
|
|
from ._bootstrap import MAGIC_NUMBER
|
|
from ._bootstrap import cache_from_source
|
|
from ._bootstrap import decode_source
|
|
from ._bootstrap import module_to_load
|
|
from ._bootstrap import set_loader
|
|
from ._bootstrap import set_package
|
|
from ._bootstrap import source_from_cache
|
|
from ._bootstrap import _resolve_name
|
|
|
|
import functools
|
|
import warnings
|
|
|
|
|
|
def resolve_name(name, package):
|
|
"""Resolve a relative module name to an absolute one."""
|
|
if not name.startswith('.'):
|
|
return name
|
|
elif not package:
|
|
raise ValueError('{!r} is not a relative name '
|
|
'(no leading dot)'.format(name))
|
|
level = 0
|
|
for character in name:
|
|
if character != '.':
|
|
break
|
|
level += 1
|
|
return _resolve_name(name[level:], package, level)
|
|
|
|
|
|
def module_for_loader(fxn):
|
|
"""Decorator to handle selecting the proper module for loaders.
|
|
|
|
The decorated function is passed the module to use instead of the module
|
|
name. The module passed in to the function is either from sys.modules if
|
|
it already exists or is a new module. If the module is new, then __name__
|
|
is set the first argument to the method, __loader__ is set to self, and
|
|
__package__ is set accordingly (if self.is_package() is defined) will be set
|
|
before it is passed to the decorated function (if self.is_package() does
|
|
not work for the module it will be set post-load).
|
|
|
|
If an exception is raised and the decorator created the module it is
|
|
subsequently removed from sys.modules.
|
|
|
|
The decorator assumes that the decorated function takes the module name as
|
|
the second argument.
|
|
|
|
"""
|
|
warnings.warn('To make it easier for subclasses, please use '
|
|
'importlib.util.module_to_load() and '
|
|
'importlib.abc.Loader.init_module_attrs()',
|
|
PendingDeprecationWarning, stacklevel=2)
|
|
@functools.wraps(fxn)
|
|
def module_for_loader_wrapper(self, fullname, *args, **kwargs):
|
|
with module_to_load(fullname) as module:
|
|
module.__loader__ = self
|
|
try:
|
|
is_package = self.is_package(fullname)
|
|
except (ImportError, AttributeError):
|
|
pass
|
|
else:
|
|
if is_package:
|
|
module.__package__ = fullname
|
|
else:
|
|
module.__package__ = fullname.rpartition('.')[0]
|
|
# If __package__ was not set above, __import__() will do it later.
|
|
return fxn(self, module, *args, **kwargs)
|
|
|
|
return module_for_loader_wrapper
|