##// END OF EJS Templates
demandimport: insert empty line per method...
Yuya Nishihara -
r32446:63365e96 default
parent child Browse files
Show More
@@ -1,297 +1,302 b''
1 # demandimport.py - global demand-loading of modules for Mercurial
1 # demandimport.py - global demand-loading of modules for Mercurial
2 #
2 #
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 '''
8 '''
9 demandimport - automatic demandloading of modules
9 demandimport - automatic demandloading of modules
10
10
11 To enable this module, do:
11 To enable this module, do:
12
12
13 import demandimport; demandimport.enable()
13 import demandimport; demandimport.enable()
14
14
15 Imports of the following forms will be demand-loaded:
15 Imports of the following forms will be demand-loaded:
16
16
17 import a, b.c
17 import a, b.c
18 import a.b as c
18 import a.b as c
19 from a import b,c # a will be loaded immediately
19 from a import b,c # a will be loaded immediately
20
20
21 These imports will not be delayed:
21 These imports will not be delayed:
22
22
23 from a import *
23 from a import *
24 b = __import__(a)
24 b = __import__(a)
25 '''
25 '''
26
26
27 from __future__ import absolute_import
27 from __future__ import absolute_import
28
28
29 import contextlib
29 import contextlib
30 import os
30 import os
31 import sys
31 import sys
32
32
33 # __builtin__ in Python 2, builtins in Python 3.
33 # __builtin__ in Python 2, builtins in Python 3.
34 try:
34 try:
35 import __builtin__ as builtins
35 import __builtin__ as builtins
36 except ImportError:
36 except ImportError:
37 import builtins
37 import builtins
38
38
39 contextmanager = contextlib.contextmanager
39 contextmanager = contextlib.contextmanager
40
40
41 _origimport = __import__
41 _origimport = __import__
42
42
43 nothing = object()
43 nothing = object()
44
44
45 # Python 3 doesn't have relative imports nor level -1.
45 # Python 3 doesn't have relative imports nor level -1.
46 level = -1
46 level = -1
47 if sys.version_info[0] >= 3:
47 if sys.version_info[0] >= 3:
48 level = 0
48 level = 0
49 _import = _origimport
49 _import = _origimport
50
50
51 def _hgextimport(importfunc, name, globals, *args, **kwargs):
51 def _hgextimport(importfunc, name, globals, *args, **kwargs):
52 try:
52 try:
53 return importfunc(name, globals, *args, **kwargs)
53 return importfunc(name, globals, *args, **kwargs)
54 except ImportError:
54 except ImportError:
55 if not globals:
55 if not globals:
56 raise
56 raise
57 # extensions are loaded with "hgext_" prefix
57 # extensions are loaded with "hgext_" prefix
58 hgextname = 'hgext_%s' % name
58 hgextname = 'hgext_%s' % name
59 nameroot = hgextname.split('.', 1)[0]
59 nameroot = hgextname.split('.', 1)[0]
60 contextroot = globals.get('__name__', '').split('.', 1)[0]
60 contextroot = globals.get('__name__', '').split('.', 1)[0]
61 if nameroot != contextroot:
61 if nameroot != contextroot:
62 raise
62 raise
63 # retry to import with "hgext_" prefix
63 # retry to import with "hgext_" prefix
64 return importfunc(hgextname, globals, *args, **kwargs)
64 return importfunc(hgextname, globals, *args, **kwargs)
65
65
66 class _demandmod(object):
66 class _demandmod(object):
67 """module demand-loader and proxy
67 """module demand-loader and proxy
68
68
69 Specify 1 as 'level' argument at construction, to import module
69 Specify 1 as 'level' argument at construction, to import module
70 relatively.
70 relatively.
71 """
71 """
72
72 def __init__(self, name, globals, locals, level):
73 def __init__(self, name, globals, locals, level):
73 if '.' in name:
74 if '.' in name:
74 head, rest = name.split('.', 1)
75 head, rest = name.split('.', 1)
75 after = [rest]
76 after = [rest]
76 else:
77 else:
77 head = name
78 head = name
78 after = []
79 after = []
79 object.__setattr__(self, r"_data",
80 object.__setattr__(self, r"_data",
80 (head, globals, locals, after, level, set()))
81 (head, globals, locals, after, level, set()))
81 object.__setattr__(self, r"_module", None)
82 object.__setattr__(self, r"_module", None)
83
82 def _extend(self, name):
84 def _extend(self, name):
83 """add to the list of submodules to load"""
85 """add to the list of submodules to load"""
84 self._data[3].append(name)
86 self._data[3].append(name)
85
87
86 def _addref(self, name):
88 def _addref(self, name):
87 """Record that the named module ``name`` imports this module.
89 """Record that the named module ``name`` imports this module.
88
90
89 References to this proxy class having the name of this module will be
91 References to this proxy class having the name of this module will be
90 replaced at module load time. We assume the symbol inside the importing
92 replaced at module load time. We assume the symbol inside the importing
91 module is identical to the "head" name of this module. We don't
93 module is identical to the "head" name of this module. We don't
92 actually know if "as X" syntax is being used to change the symbol name
94 actually know if "as X" syntax is being used to change the symbol name
93 because this information isn't exposed to __import__.
95 because this information isn't exposed to __import__.
94 """
96 """
95 self._data[5].add(name)
97 self._data[5].add(name)
96
98
97 def _load(self):
99 def _load(self):
98 if not self._module:
100 if not self._module:
99 head, globals, locals, after, level, modrefs = self._data
101 head, globals, locals, after, level, modrefs = self._data
100 mod = _hgextimport(_import, head, globals, locals, None, level)
102 mod = _hgextimport(_import, head, globals, locals, None, level)
101 if mod is self:
103 if mod is self:
102 # In this case, _hgextimport() above should imply
104 # In this case, _hgextimport() above should imply
103 # _demandimport(). Otherwise, _hgextimport() never
105 # _demandimport(). Otherwise, _hgextimport() never
104 # returns _demandmod. This isn't intentional behavior,
106 # returns _demandmod. This isn't intentional behavior,
105 # in fact. (see also issue5304 for detail)
107 # in fact. (see also issue5304 for detail)
106 #
108 #
107 # If self._module is already bound at this point, self
109 # If self._module is already bound at this point, self
108 # should be already _load()-ed while _hgextimport().
110 # should be already _load()-ed while _hgextimport().
109 # Otherwise, there is no way to import actual module
111 # Otherwise, there is no way to import actual module
110 # as expected, because (re-)invoking _hgextimport()
112 # as expected, because (re-)invoking _hgextimport()
111 # should cause same result.
113 # should cause same result.
112 # This is reason why _load() returns without any more
114 # This is reason why _load() returns without any more
113 # setup but assumes self to be already bound.
115 # setup but assumes self to be already bound.
114 mod = self._module
116 mod = self._module
115 assert mod and mod is not self, "%s, %s" % (self, mod)
117 assert mod and mod is not self, "%s, %s" % (self, mod)
116 return
118 return
117
119
118 # load submodules
120 # load submodules
119 def subload(mod, p):
121 def subload(mod, p):
120 h, t = p, None
122 h, t = p, None
121 if '.' in p:
123 if '.' in p:
122 h, t = p.split('.', 1)
124 h, t = p.split('.', 1)
123 if getattr(mod, h, nothing) is nothing:
125 if getattr(mod, h, nothing) is nothing:
124 setattr(mod, h, _demandmod(p, mod.__dict__, mod.__dict__,
126 setattr(mod, h, _demandmod(p, mod.__dict__, mod.__dict__,
125 level=1))
127 level=1))
126 elif t:
128 elif t:
127 subload(getattr(mod, h), t)
129 subload(getattr(mod, h), t)
128
130
129 for x in after:
131 for x in after:
130 subload(mod, x)
132 subload(mod, x)
131
133
132 # Replace references to this proxy instance with the actual module.
134 # Replace references to this proxy instance with the actual module.
133 if locals and locals.get(head) is self:
135 if locals and locals.get(head) is self:
134 locals[head] = mod
136 locals[head] = mod
135
137
136 for modname in modrefs:
138 for modname in modrefs:
137 modref = sys.modules.get(modname, None)
139 modref = sys.modules.get(modname, None)
138 if modref and getattr(modref, head, None) is self:
140 if modref and getattr(modref, head, None) is self:
139 setattr(modref, head, mod)
141 setattr(modref, head, mod)
140
142
141 object.__setattr__(self, r"_module", mod)
143 object.__setattr__(self, r"_module", mod)
142
144
143 def __repr__(self):
145 def __repr__(self):
144 if self._module:
146 if self._module:
145 return "<proxied module '%s'>" % self._data[0]
147 return "<proxied module '%s'>" % self._data[0]
146 return "<unloaded module '%s'>" % self._data[0]
148 return "<unloaded module '%s'>" % self._data[0]
149
147 def __call__(self, *args, **kwargs):
150 def __call__(self, *args, **kwargs):
148 raise TypeError("%s object is not callable" % repr(self))
151 raise TypeError("%s object is not callable" % repr(self))
152
149 def __getattribute__(self, attr):
153 def __getattribute__(self, attr):
150 if attr in ('_data', '_extend', '_load', '_module', '_addref'):
154 if attr in ('_data', '_extend', '_load', '_module', '_addref'):
151 return object.__getattribute__(self, attr)
155 return object.__getattribute__(self, attr)
152 self._load()
156 self._load()
153 return getattr(self._module, attr)
157 return getattr(self._module, attr)
158
154 def __setattr__(self, attr, val):
159 def __setattr__(self, attr, val):
155 self._load()
160 self._load()
156 setattr(self._module, attr, val)
161 setattr(self._module, attr, val)
157
162
158 _pypy = '__pypy__' in sys.builtin_module_names
163 _pypy = '__pypy__' in sys.builtin_module_names
159
164
160 def _demandimport(name, globals=None, locals=None, fromlist=None, level=level):
165 def _demandimport(name, globals=None, locals=None, fromlist=None, level=level):
161 if locals is None or name in ignore or fromlist == ('*',):
166 if locals is None or name in ignore or fromlist == ('*',):
162 # these cases we can't really delay
167 # these cases we can't really delay
163 return _hgextimport(_import, name, globals, locals, fromlist, level)
168 return _hgextimport(_import, name, globals, locals, fromlist, level)
164 elif not fromlist:
169 elif not fromlist:
165 # import a [as b]
170 # import a [as b]
166 if '.' in name: # a.b
171 if '.' in name: # a.b
167 base, rest = name.split('.', 1)
172 base, rest = name.split('.', 1)
168 # email.__init__ loading email.mime
173 # email.__init__ loading email.mime
169 if globals and globals.get('__name__', None) == base:
174 if globals and globals.get('__name__', None) == base:
170 return _import(name, globals, locals, fromlist, level)
175 return _import(name, globals, locals, fromlist, level)
171 # if a is already demand-loaded, add b to its submodule list
176 # if a is already demand-loaded, add b to its submodule list
172 if base in locals:
177 if base in locals:
173 if isinstance(locals[base], _demandmod):
178 if isinstance(locals[base], _demandmod):
174 locals[base]._extend(rest)
179 locals[base]._extend(rest)
175 return locals[base]
180 return locals[base]
176 return _demandmod(name, globals, locals, level)
181 return _demandmod(name, globals, locals, level)
177 else:
182 else:
178 # There is a fromlist.
183 # There is a fromlist.
179 # from a import b,c,d
184 # from a import b,c,d
180 # from . import b,c,d
185 # from . import b,c,d
181 # from .a import b,c,d
186 # from .a import b,c,d
182
187
183 # level == -1: relative and absolute attempted (Python 2 only).
188 # level == -1: relative and absolute attempted (Python 2 only).
184 # level >= 0: absolute only (Python 2 w/ absolute_import and Python 3).
189 # level >= 0: absolute only (Python 2 w/ absolute_import and Python 3).
185 # The modern Mercurial convention is to use absolute_import everywhere,
190 # The modern Mercurial convention is to use absolute_import everywhere,
186 # so modern Mercurial code will have level >= 0.
191 # so modern Mercurial code will have level >= 0.
187
192
188 # The name of the module the import statement is located in.
193 # The name of the module the import statement is located in.
189 globalname = globals.get('__name__')
194 globalname = globals.get('__name__')
190
195
191 def processfromitem(mod, attr):
196 def processfromitem(mod, attr):
192 """Process an imported symbol in the import statement.
197 """Process an imported symbol in the import statement.
193
198
194 If the symbol doesn't exist in the parent module, and if the
199 If the symbol doesn't exist in the parent module, and if the
195 parent module is a package, it must be a module. We set missing
200 parent module is a package, it must be a module. We set missing
196 modules up as _demandmod instances.
201 modules up as _demandmod instances.
197 """
202 """
198 symbol = getattr(mod, attr, nothing)
203 symbol = getattr(mod, attr, nothing)
199 nonpkg = getattr(mod, '__path__', nothing) is nothing
204 nonpkg = getattr(mod, '__path__', nothing) is nothing
200 if symbol is nothing:
205 if symbol is nothing:
201 if nonpkg:
206 if nonpkg:
202 # do not try relative import, which would raise ValueError,
207 # do not try relative import, which would raise ValueError,
203 # and leave unknown attribute as the default __import__()
208 # and leave unknown attribute as the default __import__()
204 # would do. the missing attribute will be detected later
209 # would do. the missing attribute will be detected later
205 # while processing the import statement.
210 # while processing the import statement.
206 return
211 return
207 mn = '%s.%s' % (mod.__name__, attr)
212 mn = '%s.%s' % (mod.__name__, attr)
208 if mn in ignore:
213 if mn in ignore:
209 importfunc = _origimport
214 importfunc = _origimport
210 else:
215 else:
211 importfunc = _demandmod
216 importfunc = _demandmod
212 symbol = importfunc(attr, mod.__dict__, locals, level=1)
217 symbol = importfunc(attr, mod.__dict__, locals, level=1)
213 setattr(mod, attr, symbol)
218 setattr(mod, attr, symbol)
214
219
215 # Record the importing module references this symbol so we can
220 # Record the importing module references this symbol so we can
216 # replace the symbol with the actual module instance at load
221 # replace the symbol with the actual module instance at load
217 # time.
222 # time.
218 if globalname and isinstance(symbol, _demandmod):
223 if globalname and isinstance(symbol, _demandmod):
219 symbol._addref(globalname)
224 symbol._addref(globalname)
220
225
221 def chainmodules(rootmod, modname):
226 def chainmodules(rootmod, modname):
222 # recurse down the module chain, and return the leaf module
227 # recurse down the module chain, and return the leaf module
223 mod = rootmod
228 mod = rootmod
224 for comp in modname.split('.')[1:]:
229 for comp in modname.split('.')[1:]:
225 if getattr(mod, comp, nothing) is nothing:
230 if getattr(mod, comp, nothing) is nothing:
226 setattr(mod, comp, _demandmod(comp, mod.__dict__,
231 setattr(mod, comp, _demandmod(comp, mod.__dict__,
227 mod.__dict__, level=1))
232 mod.__dict__, level=1))
228 mod = getattr(mod, comp)
233 mod = getattr(mod, comp)
229 return mod
234 return mod
230
235
231 if level >= 0:
236 if level >= 0:
232 if name:
237 if name:
233 # "from a import b" or "from .a import b" style
238 # "from a import b" or "from .a import b" style
234 rootmod = _hgextimport(_origimport, name, globals, locals,
239 rootmod = _hgextimport(_origimport, name, globals, locals,
235 level=level)
240 level=level)
236 mod = chainmodules(rootmod, name)
241 mod = chainmodules(rootmod, name)
237 elif _pypy:
242 elif _pypy:
238 # PyPy's __import__ throws an exception if invoked
243 # PyPy's __import__ throws an exception if invoked
239 # with an empty name and no fromlist. Recreate the
244 # with an empty name and no fromlist. Recreate the
240 # desired behaviour by hand.
245 # desired behaviour by hand.
241 mn = globalname
246 mn = globalname
242 mod = sys.modules[mn]
247 mod = sys.modules[mn]
243 if getattr(mod, '__path__', nothing) is nothing:
248 if getattr(mod, '__path__', nothing) is nothing:
244 mn = mn.rsplit('.', 1)[0]
249 mn = mn.rsplit('.', 1)[0]
245 mod = sys.modules[mn]
250 mod = sys.modules[mn]
246 if level > 1:
251 if level > 1:
247 mn = mn.rsplit('.', level - 1)[0]
252 mn = mn.rsplit('.', level - 1)[0]
248 mod = sys.modules[mn]
253 mod = sys.modules[mn]
249 else:
254 else:
250 mod = _hgextimport(_origimport, name, globals, locals,
255 mod = _hgextimport(_origimport, name, globals, locals,
251 level=level)
256 level=level)
252
257
253 for x in fromlist:
258 for x in fromlist:
254 processfromitem(mod, x)
259 processfromitem(mod, x)
255
260
256 return mod
261 return mod
257
262
258 # But, we still need to support lazy loading of standard library and 3rd
263 # But, we still need to support lazy loading of standard library and 3rd
259 # party modules. So handle level == -1.
264 # party modules. So handle level == -1.
260 mod = _hgextimport(_origimport, name, globals, locals)
265 mod = _hgextimport(_origimport, name, globals, locals)
261 mod = chainmodules(mod, name)
266 mod = chainmodules(mod, name)
262
267
263 for x in fromlist:
268 for x in fromlist:
264 processfromitem(mod, x)
269 processfromitem(mod, x)
265
270
266 return mod
271 return mod
267
272
268 ignore = []
273 ignore = []
269
274
270 def init(ignorelist):
275 def init(ignorelist):
271 global ignore
276 global ignore
272 ignore = ignorelist
277 ignore = ignorelist
273
278
274 def isenabled():
279 def isenabled():
275 return builtins.__import__ == _demandimport
280 return builtins.__import__ == _demandimport
276
281
277 def enable():
282 def enable():
278 "enable global demand-loading of modules"
283 "enable global demand-loading of modules"
279 if os.environ.get('HGDEMANDIMPORT') != 'disable':
284 if os.environ.get('HGDEMANDIMPORT') != 'disable':
280 builtins.__import__ = _demandimport
285 builtins.__import__ = _demandimport
281
286
282 def disable():
287 def disable():
283 "disable global demand-loading of modules"
288 "disable global demand-loading of modules"
284 builtins.__import__ = _origimport
289 builtins.__import__ = _origimport
285
290
286 @contextmanager
291 @contextmanager
287 def deactivated():
292 def deactivated():
288 "context manager for disabling demandimport in 'with' blocks"
293 "context manager for disabling demandimport in 'with' blocks"
289 demandenabled = isenabled()
294 demandenabled = isenabled()
290 if demandenabled:
295 if demandenabled:
291 disable()
296 disable()
292
297
293 try:
298 try:
294 yield
299 yield
295 finally:
300 finally:
296 if demandenabled:
301 if demandenabled:
297 enable()
302 enable()
General Comments 0
You need to be logged in to leave comments. Login now