Coverage for /pythoncovmergedfiles/medio/medio/src/py/py/_vendored_packages/apipkg/__init__.py: 70%
155 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:35 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:35 +0000
1"""
2apipkg: control the exported namespace of a Python package.
4see https://pypi.python.org/pypi/apipkg
6(c) holger krekel, 2009 - MIT license
7"""
8import os
9import sys
10from types import ModuleType
12from .version import version as __version__ # NOQA:F401
15def _py_abspath(path):
16 """
17 special version of abspath
18 that will leave paths from jython jars alone
19 """
20 if path.startswith("__pyclasspath__"):
22 return path
23 else:
24 return os.path.abspath(path)
27def distribution_version(name):
28 """try to get the version of the named distribution,
29 returs None on failure"""
30 from pkg_resources import get_distribution, DistributionNotFound
32 try:
33 dist = get_distribution(name)
34 except DistributionNotFound:
35 pass
36 else:
37 return dist.version
40def initpkg(pkgname, exportdefs, attr=None, eager=False):
41 """ initialize given package from the export definitions. """
42 attr = attr or {}
43 oldmod = sys.modules.get(pkgname)
44 d = {}
45 f = getattr(oldmod, "__file__", None)
46 if f:
47 f = _py_abspath(f)
48 d["__file__"] = f
49 if hasattr(oldmod, "__version__"):
50 d["__version__"] = oldmod.__version__
51 if hasattr(oldmod, "__loader__"):
52 d["__loader__"] = oldmod.__loader__
53 if hasattr(oldmod, "__path__"):
54 d["__path__"] = [_py_abspath(p) for p in oldmod.__path__]
55 if hasattr(oldmod, "__package__"):
56 d["__package__"] = oldmod.__package__
57 if "__doc__" not in exportdefs and getattr(oldmod, "__doc__", None):
58 d["__doc__"] = oldmod.__doc__
59 d["__spec__"] = getattr(oldmod, "__spec__", None)
60 d.update(attr)
61 if hasattr(oldmod, "__dict__"):
62 oldmod.__dict__.update(d)
63 mod = ApiModule(pkgname, exportdefs, implprefix=pkgname, attr=d)
64 sys.modules[pkgname] = mod
65 # eagerload in bypthon to avoid their monkeypatching breaking packages
66 if "bpython" in sys.modules or eager:
67 for module in list(sys.modules.values()):
68 if isinstance(module, ApiModule):
69 module.__dict__
70 return mod
73def importobj(modpath, attrname):
74 """imports a module, then resolves the attrname on it"""
75 module = __import__(modpath, None, None, ["__doc__"])
76 if not attrname:
77 return module
79 retval = module
80 names = attrname.split(".")
81 for x in names:
82 retval = getattr(retval, x)
83 return retval
86class ApiModule(ModuleType):
87 """the magical lazy-loading module standing"""
89 def __docget(self):
90 try:
91 return self.__doc
92 except AttributeError:
93 if "__doc__" in self.__map__:
94 return self.__makeattr("__doc__")
96 def __docset(self, value):
97 self.__doc = value
99 __doc__ = property(__docget, __docset)
101 def __init__(self, name, importspec, implprefix=None, attr=None):
102 self.__name__ = name
103 self.__all__ = [x for x in importspec if x != "__onfirstaccess__"]
104 self.__map__ = {}
105 self.__implprefix__ = implprefix or name
106 if attr:
107 for name, val in attr.items():
108 # print "setting", self.__name__, name, val
109 setattr(self, name, val)
110 for name, importspec in importspec.items():
111 if isinstance(importspec, dict):
112 subname = "{}.{}".format(self.__name__, name)
113 apimod = ApiModule(subname, importspec, implprefix)
114 sys.modules[subname] = apimod
115 setattr(self, name, apimod)
116 else:
117 parts = importspec.split(":")
118 modpath = parts.pop(0)
119 attrname = parts and parts[0] or ""
120 if modpath[0] == ".":
121 modpath = implprefix + modpath
123 if not attrname:
124 subname = "{}.{}".format(self.__name__, name)
125 apimod = AliasModule(subname, modpath)
126 sys.modules[subname] = apimod
127 if "." not in name:
128 setattr(self, name, apimod)
129 else:
130 self.__map__[name] = (modpath, attrname)
132 def __repr__(self):
133 repr_list = []
134 if hasattr(self, "__version__"):
135 repr_list.append("version=" + repr(self.__version__))
136 if hasattr(self, "__file__"):
137 repr_list.append("from " + repr(self.__file__))
138 if repr_list:
139 return "<ApiModule {!r} {}>".format(self.__name__, " ".join(repr_list))
140 return "<ApiModule {!r}>".format(self.__name__)
142 def __makeattr(self, name):
143 """lazily compute value for name or raise AttributeError if unknown."""
144 # print "makeattr", self.__name__, name
145 target = None
146 if "__onfirstaccess__" in self.__map__:
147 target = self.__map__.pop("__onfirstaccess__")
148 importobj(*target)()
149 try:
150 modpath, attrname = self.__map__[name]
151 except KeyError:
152 if target is not None and name != "__onfirstaccess__":
153 # retry, onfirstaccess might have set attrs
154 return getattr(self, name)
155 raise AttributeError(name)
156 else:
157 result = importobj(modpath, attrname)
158 setattr(self, name, result)
159 try:
160 del self.__map__[name]
161 except KeyError:
162 pass # in a recursive-import situation a double-del can happen
163 return result
165 __getattr__ = __makeattr
167 @property
168 def __dict__(self):
169 # force all the content of the module
170 # to be loaded when __dict__ is read
171 dictdescr = ModuleType.__dict__["__dict__"]
172 dict = dictdescr.__get__(self)
173 if dict is not None:
174 hasattr(self, "some")
175 for name in self.__all__:
176 try:
177 self.__makeattr(name)
178 except AttributeError:
179 pass
180 return dict
183def AliasModule(modname, modpath, attrname=None):
184 mod = []
186 def getmod():
187 if not mod:
188 x = importobj(modpath, None)
189 if attrname is not None:
190 x = getattr(x, attrname)
191 mod.append(x)
192 return mod[0]
194 x = modpath + ("." + attrname if attrname else "")
195 repr_result = "<AliasModule {!r} for {!r}>".format(modname, x)
197 class AliasModule(ModuleType):
198 def __repr__(self):
199 return repr_result
201 def __getattribute__(self, name):
202 try:
203 return getattr(getmod(), name)
204 except ImportError:
205 if modpath == "pytest" and attrname is None:
206 # hack for pylibs py.test
207 return None
208 else:
209 raise
211 def __setattr__(self, name, value):
212 setattr(getmod(), name, value)
214 def __delattr__(self, name):
215 delattr(getmod(), name)
217 return AliasModule(str(modname))