Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1""" 

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

3 

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

5 

6(c) holger krekel, 2009 - MIT license 

7""" 

8import os 

9import sys 

10from types import ModuleType 

11 

12 

13__version__ = '1.4' 

14 

15 

16def _py_abspath(path): 

17 """ 

18 special version of abspath 

19 that will leave paths from jython jars alone 

20 """ 

21 if path.startswith('__pyclasspath__'): 

22 

23 return path 

24 else: 

25 return os.path.abspath(path) 

26 

27 

28def distribution_version(name): 

29 """try to get the version of the named distribution, 

30 returs None on failure""" 

31 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 

38 

39 

40def initpkg(pkgname, exportdefs, attr=dict(), eager=False): 

41 """ initialize given package from the export definitions. """ 

42 oldmod = sys.modules.get(pkgname) 

43 d = {} 

44 f = getattr(oldmod, '__file__', None) 

45 if f: 

46 f = _py_abspath(f) 

47 d['__file__'] = f 

48 if hasattr(oldmod, '__version__'): 

49 d['__version__'] = oldmod.__version__ 

50 if hasattr(oldmod, '__loader__'): 

51 d['__loader__'] = oldmod.__loader__ 

52 if hasattr(oldmod, '__path__'): 

53 d['__path__'] = [_py_abspath(p) for p in oldmod.__path__] 

54 if '__doc__' not in exportdefs and getattr(oldmod, '__doc__', None): 

55 d['__doc__'] = oldmod.__doc__ 

56 d.update(attr) 

57 if hasattr(oldmod, "__dict__"): 

58 oldmod.__dict__.update(d) 

59 mod = ApiModule(pkgname, exportdefs, implprefix=pkgname, attr=d) 

60 sys.modules[pkgname] = mod 

61 # eagerload in bypthon to avoid their monkeypatching breaking packages 

62 if 'bpython' in sys.modules or eager: 

63 for module in sys.modules.values(): 

64 if isinstance(module, ApiModule): 

65 module.__dict__ 

66 

67 

68def importobj(modpath, attrname): 

69 module = __import__(modpath, None, None, ['__doc__']) 

70 if not attrname: 

71 return module 

72 

73 retval = module 

74 names = attrname.split(".") 

75 for x in names: 

76 retval = getattr(retval, x) 

77 return retval 

78 

79 

80class ApiModule(ModuleType): 

81 def __docget(self): 

82 try: 

83 return self.__doc 

84 except AttributeError: 

85 if '__doc__' in self.__map__: 

86 return self.__makeattr('__doc__') 

87 

88 def __docset(self, value): 

89 self.__doc = value 

90 __doc__ = property(__docget, __docset) 

91 

92 def __init__(self, name, importspec, implprefix=None, attr=None): 

93 self.__name__ = name 

94 self.__all__ = [x for x in importspec if x != '__onfirstaccess__'] 

95 self.__map__ = {} 

96 self.__implprefix__ = implprefix or name 

97 if attr: 

98 for name, val in attr.items(): 

99 # print "setting", self.__name__, name, val 

100 setattr(self, name, val) 

101 for name, importspec in importspec.items(): 

102 if isinstance(importspec, dict): 

103 subname = '%s.%s' % (self.__name__, name) 

104 apimod = ApiModule(subname, importspec, implprefix) 

105 sys.modules[subname] = apimod 

106 setattr(self, name, apimod) 

107 else: 

108 parts = importspec.split(':') 

109 modpath = parts.pop(0) 

110 attrname = parts and parts[0] or "" 

111 if modpath[0] == '.': 

112 modpath = implprefix + modpath 

113 

114 if not attrname: 

115 subname = '%s.%s' % (self.__name__, name) 

116 apimod = AliasModule(subname, modpath) 

117 sys.modules[subname] = apimod 

118 if '.' not in name: 

119 setattr(self, name, apimod) 

120 else: 

121 self.__map__[name] = (modpath, attrname) 

122 

123 def __repr__(self): 

124 l = [] 

125 if hasattr(self, '__version__'): 

126 l.append("version=" + repr(self.__version__)) 

127 if hasattr(self, '__file__'): 

128 l.append('from ' + repr(self.__file__)) 

129 if l: 

130 return '<ApiModule %r %s>' % (self.__name__, " ".join(l)) 

131 return '<ApiModule %r>' % (self.__name__,) 

132 

133 def __makeattr(self, name): 

134 """lazily compute value for name or raise AttributeError if unknown.""" 

135 # print "makeattr", self.__name__, name 

136 target = None 

137 if '__onfirstaccess__' in self.__map__: 

138 target = self.__map__.pop('__onfirstaccess__') 

139 importobj(*target)() 

140 try: 

141 modpath, attrname = self.__map__[name] 

142 except KeyError: 

143 if target is not None and name != '__onfirstaccess__': 

144 # retry, onfirstaccess might have set attrs 

145 return getattr(self, name) 

146 raise AttributeError(name) 

147 else: 

148 result = importobj(modpath, attrname) 

149 setattr(self, name, result) 

150 try: 

151 del self.__map__[name] 

152 except KeyError: 

153 pass # in a recursive-import situation a double-del can happen 

154 return result 

155 

156 __getattr__ = __makeattr 

157 

158 @property 

159 def __dict__(self): 

160 # force all the content of the module 

161 # to be loaded when __dict__ is read 

162 dictdescr = ModuleType.__dict__['__dict__'] 

163 dict = dictdescr.__get__(self) 

164 if dict is not None: 

165 hasattr(self, 'some') 

166 for name in self.__all__: 

167 try: 

168 self.__makeattr(name) 

169 except AttributeError: 

170 pass 

171 return dict 

172 

173 

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

175 mod = [] 

176 

177 def getmod(): 

178 if not mod: 

179 x = importobj(modpath, None) 

180 if attrname is not None: 

181 x = getattr(x, attrname) 

182 mod.append(x) 

183 return mod[0] 

184 

185 class AliasModule(ModuleType): 

186 

187 def __repr__(self): 

188 x = modpath 

189 if attrname: 

190 x += "." + attrname 

191 return '<AliasModule %r for %r>' % (modname, x) 

192 

193 def __getattribute__(self, name): 

194 try: 

195 return getattr(getmod(), name) 

196 except ImportError: 

197 return None 

198 

199 def __setattr__(self, name, value): 

200 setattr(getmod(), name, value) 

201 

202 def __delattr__(self, name): 

203 delattr(getmod(), name) 

204 

205 return AliasModule(str(modname))