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

1""" 

2apipkg: control the exported namespace of a Python package. 

3 

4see https://pypi.python.org/pypi/apipkg 

5 

6(c) holger krekel, 2009 - MIT license 

7""" 

8import os 

9import sys 

10from types import ModuleType 

11 

12from .version import version as __version__ # NOQA:F401 

13 

14 

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__"): 

21 

22 return path 

23 else: 

24 return os.path.abspath(path) 

25 

26 

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 

31 

32 try: 

33 dist = get_distribution(name) 

34 except DistributionNotFound: 

35 pass 

36 else: 

37 return dist.version 

38 

39 

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 

71 

72 

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 

78 

79 retval = module 

80 names = attrname.split(".") 

81 for x in names: 

82 retval = getattr(retval, x) 

83 return retval 

84 

85 

86class ApiModule(ModuleType): 

87 """the magical lazy-loading module standing""" 

88 

89 def __docget(self): 

90 try: 

91 return self.__doc 

92 except AttributeError: 

93 if "__doc__" in self.__map__: 

94 return self.__makeattr("__doc__") 

95 

96 def __docset(self, value): 

97 self.__doc = value 

98 

99 __doc__ = property(__docget, __docset) 

100 

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 

122 

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) 

131 

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__) 

141 

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 

164 

165 __getattr__ = __makeattr 

166 

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 

181 

182 

183def AliasModule(modname, modpath, attrname=None): 

184 mod = [] 

185 

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] 

193 

194 x = modpath + ("." + attrname if attrname else "") 

195 repr_result = "<AliasModule {!r} for {!r}>".format(modname, x) 

196 

197 class AliasModule(ModuleType): 

198 def __repr__(self): 

199 return repr_result 

200 

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 

210 

211 def __setattr__(self, name, value): 

212 setattr(getmod(), name, value) 

213 

214 def __delattr__(self, name): 

215 delattr(getmod(), name) 

216 

217 return AliasModule(str(modname))