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