blob: 06f4d2f8b53063f52808cfae04e3b98b236d1b1e [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 Cannon357c9fb2013-05-30 17:31:47 -04005from ._bootstrap import module_to_load
Brett Cannon2cf03a82009-03-10 05:17:37 +00006from ._bootstrap import set_loader
Brett Cannon435aad82009-03-04 16:07:00 +00007from ._bootstrap import set_package
Brett Cannona3c96152013-06-14 22:26:30 -04008from ._bootstrap import source_from_cache
Brett Cannond200bf52012-05-13 13:45:09 -04009from ._bootstrap import _resolve_name
10
Brett Cannon0dbb4c72013-05-31 18:56:47 -040011import functools
12import warnings
13
Brett Cannond200bf52012-05-13 13:45:09 -040014
15def resolve_name(name, package):
16 """Resolve a relative module name to an absolute one."""
17 if not name.startswith('.'):
18 return name
19 elif not package:
20 raise ValueError('{!r} is not a relative name '
21 '(no leading dot)'.format(name))
22 level = 0
23 for character in name:
24 if character != '.':
25 break
26 level += 1
27 return _resolve_name(name[level:], package, level)
Brett Cannon0dbb4c72013-05-31 18:56:47 -040028
29
30def module_for_loader(fxn):
31 """Decorator to handle selecting the proper module for loaders.
32
33 The decorated function is passed the module to use instead of the module
34 name. The module passed in to the function is either from sys.modules if
35 it already exists or is a new module. If the module is new, then __name__
36 is set the first argument to the method, __loader__ is set to self, and
37 __package__ is set accordingly (if self.is_package() is defined) will be set
38 before it is passed to the decorated function (if self.is_package() does
39 not work for the module it will be set post-load).
40
41 If an exception is raised and the decorator created the module it is
42 subsequently removed from sys.modules.
43
44 The decorator assumes that the decorated function takes the module name as
45 the second argument.
46
47 """
48 warnings.warn('To make it easier for subclasses, please use '
49 'importlib.util.module_to_load() and '
50 'importlib.abc.Loader.init_module_attrs()',
51 PendingDeprecationWarning, stacklevel=2)
52 @functools.wraps(fxn)
53 def module_for_loader_wrapper(self, fullname, *args, **kwargs):
54 with module_to_load(fullname) as module:
55 module.__loader__ = self
56 try:
57 is_package = self.is_package(fullname)
58 except (ImportError, AttributeError):
59 pass
60 else:
61 if is_package:
62 module.__package__ = fullname
63 else:
64 module.__package__ = fullname.rpartition('.')[0]
65 # If __package__ was not set above, __import__() will do it later.
66 return fxn(self, module, *args, **kwargs)
67
Brett Cannon0e75c062013-05-31 18:57:45 -040068 return module_for_loader_wrapper