blob: 6d73b1d7b6d274617e5e4d92f829b4e4676139a4 [file] [log] [blame]
Brett Cannond2e7b332009-02-17 02:45:03 +00001"""Utility code for constructing importers, etc."""
Barry Warsaw28a691b2010-04-17 00:19:56 +00002
Brett Cannon05a647d2013-06-14 19:02:34 -04003from ._bootstrap import MAGIC_NUMBER
Brett Cannona3c96152013-06-14 22:26:30 -04004from ._bootstrap import cache_from_source
Brett Cannonf24fecd2013-06-16 18:37:53 -04005from ._bootstrap import decode_source
Brett Cannona3c96152013-06-14 22:26:30 -04006from ._bootstrap import source_from_cache
Eric Snowb523f842013-11-22 09:05:39 -07007from ._bootstrap import spec_from_loader
8from ._bootstrap import spec_from_file_location
Brett Cannond200bf52012-05-13 13:45:09 -04009from ._bootstrap import _resolve_name
Eric Snow6029e082014-01-25 15:32:46 -070010from ._bootstrap import _find_spec
Brett Cannond200bf52012-05-13 13:45:09 -040011
Eric Snowb523f842013-11-22 09:05:39 -070012from contextlib import contextmanager
Brett Cannon0dbb4c72013-05-31 18:56:47 -040013import functools
Eric Snowb523f842013-11-22 09:05:39 -070014import sys
Brett Cannon0dbb4c72013-05-31 18:56:47 -040015import warnings
16
Brett Cannond200bf52012-05-13 13:45:09 -040017
18def resolve_name(name, package):
19 """Resolve a relative module name to an absolute one."""
20 if not name.startswith('.'):
21 return name
22 elif not package:
23 raise ValueError('{!r} is not a relative name '
24 '(no leading dot)'.format(name))
25 level = 0
26 for character in name:
27 if character != '.':
28 break
29 level += 1
30 return _resolve_name(name[level:], package, level)
Brett Cannon0dbb4c72013-05-31 18:56:47 -040031
32
Eric Snow6029e082014-01-25 15:32:46 -070033def _find_spec_from_path(name, path=None):
34 """Return the spec for the specified module.
35
36 First, sys.modules is checked to see if the module was already imported. If
37 so, then sys.modules[name].__spec__ is returned. If that happens to be
38 set to None, then ValueError is raised. If the module is not in
39 sys.modules, then sys.meta_path is searched for a suitable spec with the
40 value of 'path' given to the finders. None is returned if no spec could
41 be found.
42
43 Dotted names do not have their parent packages implicitly imported. You will
44 most likely need to explicitly import all parent packages in the proper
45 order for a submodule to get the correct spec.
46
47 """
48 if name not in sys.modules:
49 return _find_spec(name, path)
50 else:
51 module = sys.modules[name]
52 if module is None:
53 return None
54 try:
55 spec = module.__spec__
56 except AttributeError:
57 raise ValueError('{}.__spec__ is not set'.format(name))
58 else:
59 if spec is None:
60 raise ValueError('{}.__spec__ is None'.format(name))
61 return spec
62
63
64def find_spec(name, package=None):
65 """Return the spec for the specified module.
66
67 First, sys.modules is checked to see if the module was already imported. If
68 so, then sys.modules[name].__spec__ is returned. If that happens to be
69 set to None, then ValueError is raised. If the module is not in
70 sys.modules, then sys.meta_path is searched for a suitable spec with the
71 value of 'path' given to the finders. None is returned if no spec could
72 be found.
73
74 If the name is for submodule (contains a dot), the parent module is
75 automatically imported.
76
77 The name and package arguments work the same as importlib.import_module().
78 In other words, relative module names (with leading dots) work.
79
80 """
81 fullname = resolve_name(name, package) if name.startswith('.') else name
82 if fullname not in sys.modules:
83 parent_name = fullname.rpartition('.')[0]
84 if parent_name:
85 # Use builtins.__import__() in case someone replaced it.
86 parent = __import__(parent_name, fromlist=['__path__'])
87 return _find_spec(fullname, parent.__path__)
88 else:
89 return _find_spec(fullname, None)
90 else:
91 module = sys.modules[fullname]
92 if module is None:
93 return None
94 try:
95 spec = module.__spec__
96 except AttributeError:
97 raise ValueError('{}.__spec__ is not set'.format(name))
98 else:
99 if spec is None:
100 raise ValueError('{}.__spec__ is None'.format(name))
101 return spec
102
103
Eric Snowb523f842013-11-22 09:05:39 -0700104@contextmanager
105def _module_to_load(name):
106 is_reload = name in sys.modules
107
108 module = sys.modules.get(name)
109 if not is_reload:
110 # This must be done before open() is called as the 'io' module
111 # implicitly imports 'locale' and would otherwise trigger an
112 # infinite loop.
113 module = type(sys)(name)
114 # This must be done before putting the module in sys.modules
115 # (otherwise an optimization shortcut in import.c becomes wrong)
116 module.__initializing__ = True
117 sys.modules[name] = module
118 try:
119 yield module
120 except Exception:
121 if not is_reload:
122 try:
123 del sys.modules[name]
124 except KeyError:
125 pass
126 finally:
127 module.__initializing__ = False
128
129
Eric Snowb523f842013-11-22 09:05:39 -0700130def set_package(fxn):
Eric Snow1500d492014-01-06 20:49:04 -0700131 """Set __package__ on the returned module.
132
133 This function is deprecated.
134
135 """
Eric Snowb523f842013-11-22 09:05:39 -0700136 @functools.wraps(fxn)
137 def set_package_wrapper(*args, **kwargs):
Eric Snow1500d492014-01-06 20:49:04 -0700138 warnings.warn('The import system now takes care of this automatically.',
139 DeprecationWarning, stacklevel=2)
Eric Snowb523f842013-11-22 09:05:39 -0700140 module = fxn(*args, **kwargs)
141 if getattr(module, '__package__', None) is None:
142 module.__package__ = module.__name__
143 if not hasattr(module, '__path__'):
144 module.__package__ = module.__package__.rpartition('.')[0]
145 return module
146 return set_package_wrapper
147
148
Eric Snowb523f842013-11-22 09:05:39 -0700149def set_loader(fxn):
Eric Snow1500d492014-01-06 20:49:04 -0700150 """Set __loader__ on the returned module.
151
152 This function is deprecated.
153
154 """
Eric Snowb523f842013-11-22 09:05:39 -0700155 @functools.wraps(fxn)
156 def set_loader_wrapper(self, *args, **kwargs):
Eric Snow1500d492014-01-06 20:49:04 -0700157 warnings.warn('The import system now takes care of this automatically.',
158 DeprecationWarning, stacklevel=2)
Eric Snowb523f842013-11-22 09:05:39 -0700159 module = fxn(self, *args, **kwargs)
160 if getattr(module, '__loader__', None) is None:
161 module.__loader__ = self
162 return module
163 return set_loader_wrapper
164
165
Brett Cannon0dbb4c72013-05-31 18:56:47 -0400166def module_for_loader(fxn):
167 """Decorator to handle selecting the proper module for loaders.
168
169 The decorated function is passed the module to use instead of the module
170 name. The module passed in to the function is either from sys.modules if
171 it already exists or is a new module. If the module is new, then __name__
172 is set the first argument to the method, __loader__ is set to self, and
173 __package__ is set accordingly (if self.is_package() is defined) will be set
174 before it is passed to the decorated function (if self.is_package() does
175 not work for the module it will be set post-load).
176
177 If an exception is raised and the decorator created the module it is
178 subsequently removed from sys.modules.
179
180 The decorator assumes that the decorated function takes the module name as
181 the second argument.
182
183 """
Eric Snowb523f842013-11-22 09:05:39 -0700184 warnings.warn('The import system now takes care of this automatically.',
Eric Snow1500d492014-01-06 20:49:04 -0700185 DeprecationWarning, stacklevel=2)
Brett Cannon0dbb4c72013-05-31 18:56:47 -0400186 @functools.wraps(fxn)
187 def module_for_loader_wrapper(self, fullname, *args, **kwargs):
Eric Snowb523f842013-11-22 09:05:39 -0700188 with _module_to_load(fullname) as module:
Brett Cannon0dbb4c72013-05-31 18:56:47 -0400189 module.__loader__ = self
190 try:
191 is_package = self.is_package(fullname)
192 except (ImportError, AttributeError):
193 pass
194 else:
195 if is_package:
196 module.__package__ = fullname
197 else:
198 module.__package__ = fullname.rpartition('.')[0]
199 # If __package__ was not set above, __import__() will do it later.
200 return fxn(self, module, *args, **kwargs)
201
Brett Cannon0e75c062013-05-31 18:57:45 -0400202 return module_for_loader_wrapper