1
"""Utility code for constructing importers, etc."""
3
from ._bootstrap import MAGIC_NUMBER
4
from ._bootstrap import cache_from_source
5
from ._bootstrap import decode_source
6
from ._bootstrap import source_from_cache
7
from ._bootstrap import spec_from_loader
8
from ._bootstrap import spec_from_file_location
9
from ._bootstrap import _resolve_name
11
from contextlib import contextmanager
17
def resolve_name(name, package):
18
"""Resolve a relative module name to an absolute one."""
19
if not name.startswith('.'):
22
raise ValueError('{!r} is not a relative name '
23
'(no leading dot)'.format(name))
25
for character in name:
29
return _resolve_name(name[level:], package, level)
33
def _module_to_load(name):
34
is_reload = name in sys.modules
36
module = sys.modules.get(name)
38
# This must be done before open() is called as the 'io' module
39
# implicitly imports 'locale' and would otherwise trigger an
41
module = type(sys)(name)
42
# This must be done before putting the module in sys.modules
43
# (otherwise an optimization shortcut in import.c becomes wrong)
44
module.__initializing__ = True
45
sys.modules[name] = module
55
module.__initializing__ = False
60
"""Set __package__ on the returned module."""
62
def set_package_wrapper(*args, **kwargs):
63
module = fxn(*args, **kwargs)
64
if getattr(module, '__package__', None) is None:
65
module.__package__ = module.__name__
66
if not hasattr(module, '__path__'):
67
module.__package__ = module.__package__.rpartition('.')[0]
69
return set_package_wrapper
74
"""Set __loader__ on the returned module."""
76
def set_loader_wrapper(self, *args, **kwargs):
77
module = fxn(self, *args, **kwargs)
78
if getattr(module, '__loader__', None) is None:
79
module.__loader__ = self
81
return set_loader_wrapper
84
def module_for_loader(fxn):
85
"""Decorator to handle selecting the proper module for loaders.
87
The decorated function is passed the module to use instead of the module
88
name. The module passed in to the function is either from sys.modules if
89
it already exists or is a new module. If the module is new, then __name__
90
is set the first argument to the method, __loader__ is set to self, and
91
__package__ is set accordingly (if self.is_package() is defined) will be set
92
before it is passed to the decorated function (if self.is_package() does
93
not work for the module it will be set post-load).
95
If an exception is raised and the decorator created the module it is
96
subsequently removed from sys.modules.
98
The decorator assumes that the decorated function takes the module name as
102
warnings.warn('The import system now takes care of this automatically.',
103
PendingDeprecationWarning, stacklevel=2)
104
@functools.wraps(fxn)
105
def module_for_loader_wrapper(self, fullname, *args, **kwargs):
106
with _module_to_load(fullname) as module:
107
module.__loader__ = self
109
is_package = self.is_package(fullname)
110
except (ImportError, AttributeError):
114
module.__package__ = fullname
116
module.__package__ = fullname.rpartition('.')[0]
117
# If __package__ was not set above, __import__() will do it later.
118
return fxn(self, module, *args, **kwargs)
120
return module_for_loader_wrapper