blob: 42fc9eae93fefdbaf257b6e9f4851b63f815aba6 [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
10
Eric Snowb523f842013-11-22 09:05:39 -070011from contextlib import contextmanager
Brett Cannon0dbb4c72013-05-31 18:56:47 -040012import functools
Eric Snowb523f842013-11-22 09:05:39 -070013import sys
Brett Cannon0dbb4c72013-05-31 18:56:47 -040014import warnings
15
Brett Cannond200bf52012-05-13 13:45:09 -040016
17def resolve_name(name, package):
18 """Resolve a relative module name to an absolute one."""
19 if not name.startswith('.'):
20 return name
21 elif not package:
22 raise ValueError('{!r} is not a relative name '
23 '(no leading dot)'.format(name))
24 level = 0
25 for character in name:
26 if character != '.':
27 break
28 level += 1
29 return _resolve_name(name[level:], package, level)
Brett Cannon0dbb4c72013-05-31 18:56:47 -040030
31
Eric Snowb523f842013-11-22 09:05:39 -070032@contextmanager
33def _module_to_load(name):
34 is_reload = name in sys.modules
35
36 module = sys.modules.get(name)
37 if not is_reload:
38 # This must be done before open() is called as the 'io' module
39 # implicitly imports 'locale' and would otherwise trigger an
40 # infinite loop.
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
46 try:
47 yield module
48 except Exception:
49 if not is_reload:
50 try:
51 del sys.modules[name]
52 except KeyError:
53 pass
54 finally:
55 module.__initializing__ = False
56
57
Eric Snowb523f842013-11-22 09:05:39 -070058def set_package(fxn):
Eric Snow1500d492014-01-06 20:49:04 -070059 """Set __package__ on the returned module.
60
61 This function is deprecated.
62
63 """
Eric Snowb523f842013-11-22 09:05:39 -070064 @functools.wraps(fxn)
65 def set_package_wrapper(*args, **kwargs):
Eric Snow1500d492014-01-06 20:49:04 -070066 warnings.warn('The import system now takes care of this automatically.',
67 DeprecationWarning, stacklevel=2)
Eric Snowb523f842013-11-22 09:05:39 -070068 module = fxn(*args, **kwargs)
69 if getattr(module, '__package__', None) is None:
70 module.__package__ = module.__name__
71 if not hasattr(module, '__path__'):
72 module.__package__ = module.__package__.rpartition('.')[0]
73 return module
74 return set_package_wrapper
75
76
Eric Snowb523f842013-11-22 09:05:39 -070077def set_loader(fxn):
Eric Snow1500d492014-01-06 20:49:04 -070078 """Set __loader__ on the returned module.
79
80 This function is deprecated.
81
82 """
Eric Snowb523f842013-11-22 09:05:39 -070083 @functools.wraps(fxn)
84 def set_loader_wrapper(self, *args, **kwargs):
Eric Snow1500d492014-01-06 20:49:04 -070085 warnings.warn('The import system now takes care of this automatically.',
86 DeprecationWarning, stacklevel=2)
Eric Snowb523f842013-11-22 09:05:39 -070087 module = fxn(self, *args, **kwargs)
88 if getattr(module, '__loader__', None) is None:
89 module.__loader__ = self
90 return module
91 return set_loader_wrapper
92
93
Brett Cannon0dbb4c72013-05-31 18:56:47 -040094def module_for_loader(fxn):
95 """Decorator to handle selecting the proper module for loaders.
96
97 The decorated function is passed the module to use instead of the module
98 name. The module passed in to the function is either from sys.modules if
99 it already exists or is a new module. If the module is new, then __name__
100 is set the first argument to the method, __loader__ is set to self, and
101 __package__ is set accordingly (if self.is_package() is defined) will be set
102 before it is passed to the decorated function (if self.is_package() does
103 not work for the module it will be set post-load).
104
105 If an exception is raised and the decorator created the module it is
106 subsequently removed from sys.modules.
107
108 The decorator assumes that the decorated function takes the module name as
109 the second argument.
110
111 """
Eric Snowb523f842013-11-22 09:05:39 -0700112 warnings.warn('The import system now takes care of this automatically.',
Eric Snow1500d492014-01-06 20:49:04 -0700113 DeprecationWarning, stacklevel=2)
Brett Cannon0dbb4c72013-05-31 18:56:47 -0400114 @functools.wraps(fxn)
115 def module_for_loader_wrapper(self, fullname, *args, **kwargs):
Eric Snowb523f842013-11-22 09:05:39 -0700116 with _module_to_load(fullname) as module:
Brett Cannon0dbb4c72013-05-31 18:56:47 -0400117 module.__loader__ = self
118 try:
119 is_package = self.is_package(fullname)
120 except (ImportError, AttributeError):
121 pass
122 else:
123 if is_package:
124 module.__package__ = fullname
125 else:
126 module.__package__ = fullname.rpartition('.')[0]
127 # If __package__ was not set above, __import__() will do it later.
128 return fxn(self, module, *args, **kwargs)
129
Brett Cannon0e75c062013-05-31 18:57:45 -0400130 return module_for_loader_wrapper