##// END OF EJS Templates
demandimport: stop overriding __getattribute__()...
Yuya Nishihara -
r32448:91a2ec8e default
parent child Browse files
Show More
@@ -1,305 +1,313 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
73 def __init__(self, name, globals, locals, level):
73 def __init__(self, name, globals, locals, level):
74 if '.' in name:
74 if '.' in name:
75 head, rest = name.split('.', 1)
75 head, rest = name.split('.', 1)
76 after = [rest]
76 after = [rest]
77 else:
77 else:
78 head = name
78 head = name
79 after = []
79 after = []
80 object.__setattr__(self, r"_data",
80 object.__setattr__(self, r"_data",
81 (head, globals, locals, after, level, set()))
81 (head, globals, locals, after, level, set()))
82 object.__setattr__(self, r"_module", None)
82 object.__setattr__(self, r"_module", None)
83
83
84 def _extend(self, name):
84 def _extend(self, name):
85 """add to the list of submodules to load"""
85 """add to the list of submodules to load"""
86 self._data[3].append(name)
86 self._data[3].append(name)
87
87
88 def _addref(self, name):
88 def _addref(self, name):
89 """Record that the named module ``name`` imports this module.
89 """Record that the named module ``name`` imports this module.
90
90
91 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
92 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
93 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
94 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
95 because this information isn't exposed to __import__.
95 because this information isn't exposed to __import__.
96 """
96 """
97 self._data[5].add(name)
97 self._data[5].add(name)
98
98
99 def _load(self):
99 def _load(self):
100 if not self._module:
100 if not self._module:
101 head, globals, locals, after, level, modrefs = self._data
101 head, globals, locals, after, level, modrefs = self._data
102 mod = _hgextimport(_import, head, globals, locals, None, level)
102 mod = _hgextimport(_import, head, globals, locals, None, level)
103 if mod is self:
103 if mod is self:
104 # In this case, _hgextimport() above should imply
104 # In this case, _hgextimport() above should imply
105 # _demandimport(). Otherwise, _hgextimport() never
105 # _demandimport(). Otherwise, _hgextimport() never
106 # returns _demandmod. This isn't intentional behavior,
106 # returns _demandmod. This isn't intentional behavior,
107 # in fact. (see also issue5304 for detail)
107 # in fact. (see also issue5304 for detail)
108 #
108 #
109 # If self._module is already bound at this point, self
109 # If self._module is already bound at this point, self
110 # should be already _load()-ed while _hgextimport().
110 # should be already _load()-ed while _hgextimport().
111 # Otherwise, there is no way to import actual module
111 # Otherwise, there is no way to import actual module
112 # as expected, because (re-)invoking _hgextimport()
112 # as expected, because (re-)invoking _hgextimport()
113 # should cause same result.
113 # should cause same result.
114 # This is reason why _load() returns without any more
114 # This is reason why _load() returns without any more
115 # setup but assumes self to be already bound.
115 # setup but assumes self to be already bound.
116 mod = self._module
116 mod = self._module
117 assert mod and mod is not self, "%s, %s" % (self, mod)
117 assert mod and mod is not self, "%s, %s" % (self, mod)
118 return
118 return
119
119
120 # load submodules
120 # load submodules
121 def subload(mod, p):
121 def subload(mod, p):
122 h, t = p, None
122 h, t = p, None
123 if '.' in p:
123 if '.' in p:
124 h, t = p.split('.', 1)
124 h, t = p.split('.', 1)
125 if getattr(mod, h, nothing) is nothing:
125 if getattr(mod, h, nothing) is nothing:
126 setattr(mod, h, _demandmod(p, mod.__dict__, mod.__dict__,
126 setattr(mod, h, _demandmod(p, mod.__dict__, mod.__dict__,
127 level=1))
127 level=1))
128 elif t:
128 elif t:
129 subload(getattr(mod, h), t)
129 subload(getattr(mod, h), t)
130
130
131 for x in after:
131 for x in after:
132 subload(mod, x)
132 subload(mod, x)
133
133
134 # Replace references to this proxy instance with the actual module.
134 # Replace references to this proxy instance with the actual module.
135 if locals:
135 if locals:
136 if locals.get(head) is self:
136 if locals.get(head) is self:
137 locals[head] = mod
137 locals[head] = mod
138 elif locals.get(head + r'mod') is self:
138 elif locals.get(head + r'mod') is self:
139 locals[head + r'mod'] = mod
139 locals[head + r'mod'] = mod
140
140
141 for modname in modrefs:
141 for modname in modrefs:
142 modref = sys.modules.get(modname, None)
142 modref = sys.modules.get(modname, None)
143 if modref and getattr(modref, head, None) is self:
143 if modref and getattr(modref, head, None) is self:
144 setattr(modref, head, mod)
144 setattr(modref, head, mod)
145
145
146 object.__setattr__(self, r"_module", mod)
146 object.__setattr__(self, r"_module", mod)
147
147
148 def __repr__(self):
148 def __repr__(self):
149 if self._module:
149 if self._module:
150 return "<proxied module '%s'>" % self._data[0]
150 return "<proxied module '%s'>" % self._data[0]
151 return "<unloaded module '%s'>" % self._data[0]
151 return "<unloaded module '%s'>" % self._data[0]
152
152
153 def __call__(self, *args, **kwargs):
153 def __call__(self, *args, **kwargs):
154 raise TypeError("%s object is not callable" % repr(self))
154 raise TypeError("%s object is not callable" % repr(self))
155
155
156 def __getattribute__(self, attr):
156 def __getattr__(self, attr):
157 if attr in ('_data', '_extend', '_load', '_module', '_addref'):
158 return object.__getattribute__(self, attr)
159 self._load()
157 self._load()
160 return getattr(self._module, attr)
158 return getattr(self._module, attr)
161
159
162 def __setattr__(self, attr, val):
160 def __setattr__(self, attr, val):
163 self._load()
161 self._load()
164 setattr(self._module, attr, val)
162 setattr(self._module, attr, val)
165
163
164 @property
165 def __dict__(self):
166 self._load()
167 return self._module.__dict__
168
169 @property
170 def __doc__(self):
171 self._load()
172 return self._module.__doc__
173
166 _pypy = '__pypy__' in sys.builtin_module_names
174 _pypy = '__pypy__' in sys.builtin_module_names
167
175
168 def _demandimport(name, globals=None, locals=None, fromlist=None, level=level):
176 def _demandimport(name, globals=None, locals=None, fromlist=None, level=level):
169 if locals is None or name in ignore or fromlist == ('*',):
177 if locals is None or name in ignore or fromlist == ('*',):
170 # these cases we can't really delay
178 # these cases we can't really delay
171 return _hgextimport(_import, name, globals, locals, fromlist, level)
179 return _hgextimport(_import, name, globals, locals, fromlist, level)
172 elif not fromlist:
180 elif not fromlist:
173 # import a [as b]
181 # import a [as b]
174 if '.' in name: # a.b
182 if '.' in name: # a.b
175 base, rest = name.split('.', 1)
183 base, rest = name.split('.', 1)
176 # email.__init__ loading email.mime
184 # email.__init__ loading email.mime
177 if globals and globals.get('__name__', None) == base:
185 if globals and globals.get('__name__', None) == base:
178 return _import(name, globals, locals, fromlist, level)
186 return _import(name, globals, locals, fromlist, level)
179 # if a is already demand-loaded, add b to its submodule list
187 # if a is already demand-loaded, add b to its submodule list
180 if base in locals:
188 if base in locals:
181 if isinstance(locals[base], _demandmod):
189 if isinstance(locals[base], _demandmod):
182 locals[base]._extend(rest)
190 locals[base]._extend(rest)
183 return locals[base]
191 return locals[base]
184 return _demandmod(name, globals, locals, level)
192 return _demandmod(name, globals, locals, level)
185 else:
193 else:
186 # There is a fromlist.
194 # There is a fromlist.
187 # from a import b,c,d
195 # from a import b,c,d
188 # from . import b,c,d
196 # from . import b,c,d
189 # from .a import b,c,d
197 # from .a import b,c,d
190
198
191 # level == -1: relative and absolute attempted (Python 2 only).
199 # level == -1: relative and absolute attempted (Python 2 only).
192 # level >= 0: absolute only (Python 2 w/ absolute_import and Python 3).
200 # level >= 0: absolute only (Python 2 w/ absolute_import and Python 3).
193 # The modern Mercurial convention is to use absolute_import everywhere,
201 # The modern Mercurial convention is to use absolute_import everywhere,
194 # so modern Mercurial code will have level >= 0.
202 # so modern Mercurial code will have level >= 0.
195
203
196 # The name of the module the import statement is located in.
204 # The name of the module the import statement is located in.
197 globalname = globals.get('__name__')
205 globalname = globals.get('__name__')
198
206
199 def processfromitem(mod, attr):
207 def processfromitem(mod, attr):
200 """Process an imported symbol in the import statement.
208 """Process an imported symbol in the import statement.
201
209
202 If the symbol doesn't exist in the parent module, and if the
210 If the symbol doesn't exist in the parent module, and if the
203 parent module is a package, it must be a module. We set missing
211 parent module is a package, it must be a module. We set missing
204 modules up as _demandmod instances.
212 modules up as _demandmod instances.
205 """
213 """
206 symbol = getattr(mod, attr, nothing)
214 symbol = getattr(mod, attr, nothing)
207 nonpkg = getattr(mod, '__path__', nothing) is nothing
215 nonpkg = getattr(mod, '__path__', nothing) is nothing
208 if symbol is nothing:
216 if symbol is nothing:
209 if nonpkg:
217 if nonpkg:
210 # do not try relative import, which would raise ValueError,
218 # do not try relative import, which would raise ValueError,
211 # and leave unknown attribute as the default __import__()
219 # and leave unknown attribute as the default __import__()
212 # would do. the missing attribute will be detected later
220 # would do. the missing attribute will be detected later
213 # while processing the import statement.
221 # while processing the import statement.
214 return
222 return
215 mn = '%s.%s' % (mod.__name__, attr)
223 mn = '%s.%s' % (mod.__name__, attr)
216 if mn in ignore:
224 if mn in ignore:
217 importfunc = _origimport
225 importfunc = _origimport
218 else:
226 else:
219 importfunc = _demandmod
227 importfunc = _demandmod
220 symbol = importfunc(attr, mod.__dict__, locals, level=1)
228 symbol = importfunc(attr, mod.__dict__, locals, level=1)
221 setattr(mod, attr, symbol)
229 setattr(mod, attr, symbol)
222
230
223 # Record the importing module references this symbol so we can
231 # Record the importing module references this symbol so we can
224 # replace the symbol with the actual module instance at load
232 # replace the symbol with the actual module instance at load
225 # time.
233 # time.
226 if globalname and isinstance(symbol, _demandmod):
234 if globalname and isinstance(symbol, _demandmod):
227 symbol._addref(globalname)
235 symbol._addref(globalname)
228
236
229 def chainmodules(rootmod, modname):
237 def chainmodules(rootmod, modname):
230 # recurse down the module chain, and return the leaf module
238 # recurse down the module chain, and return the leaf module
231 mod = rootmod
239 mod = rootmod
232 for comp in modname.split('.')[1:]:
240 for comp in modname.split('.')[1:]:
233 if getattr(mod, comp, nothing) is nothing:
241 if getattr(mod, comp, nothing) is nothing:
234 setattr(mod, comp, _demandmod(comp, mod.__dict__,
242 setattr(mod, comp, _demandmod(comp, mod.__dict__,
235 mod.__dict__, level=1))
243 mod.__dict__, level=1))
236 mod = getattr(mod, comp)
244 mod = getattr(mod, comp)
237 return mod
245 return mod
238
246
239 if level >= 0:
247 if level >= 0:
240 if name:
248 if name:
241 # "from a import b" or "from .a import b" style
249 # "from a import b" or "from .a import b" style
242 rootmod = _hgextimport(_origimport, name, globals, locals,
250 rootmod = _hgextimport(_origimport, name, globals, locals,
243 level=level)
251 level=level)
244 mod = chainmodules(rootmod, name)
252 mod = chainmodules(rootmod, name)
245 elif _pypy:
253 elif _pypy:
246 # PyPy's __import__ throws an exception if invoked
254 # PyPy's __import__ throws an exception if invoked
247 # with an empty name and no fromlist. Recreate the
255 # with an empty name and no fromlist. Recreate the
248 # desired behaviour by hand.
256 # desired behaviour by hand.
249 mn = globalname
257 mn = globalname
250 mod = sys.modules[mn]
258 mod = sys.modules[mn]
251 if getattr(mod, '__path__', nothing) is nothing:
259 if getattr(mod, '__path__', nothing) is nothing:
252 mn = mn.rsplit('.', 1)[0]
260 mn = mn.rsplit('.', 1)[0]
253 mod = sys.modules[mn]
261 mod = sys.modules[mn]
254 if level > 1:
262 if level > 1:
255 mn = mn.rsplit('.', level - 1)[0]
263 mn = mn.rsplit('.', level - 1)[0]
256 mod = sys.modules[mn]
264 mod = sys.modules[mn]
257 else:
265 else:
258 mod = _hgextimport(_origimport, name, globals, locals,
266 mod = _hgextimport(_origimport, name, globals, locals,
259 level=level)
267 level=level)
260
268
261 for x in fromlist:
269 for x in fromlist:
262 processfromitem(mod, x)
270 processfromitem(mod, x)
263
271
264 return mod
272 return mod
265
273
266 # But, we still need to support lazy loading of standard library and 3rd
274 # But, we still need to support lazy loading of standard library and 3rd
267 # party modules. So handle level == -1.
275 # party modules. So handle level == -1.
268 mod = _hgextimport(_origimport, name, globals, locals)
276 mod = _hgextimport(_origimport, name, globals, locals)
269 mod = chainmodules(mod, name)
277 mod = chainmodules(mod, name)
270
278
271 for x in fromlist:
279 for x in fromlist:
272 processfromitem(mod, x)
280 processfromitem(mod, x)
273
281
274 return mod
282 return mod
275
283
276 ignore = []
284 ignore = []
277
285
278 def init(ignorelist):
286 def init(ignorelist):
279 global ignore
287 global ignore
280 ignore = ignorelist
288 ignore = ignorelist
281
289
282 def isenabled():
290 def isenabled():
283 return builtins.__import__ == _demandimport
291 return builtins.__import__ == _demandimport
284
292
285 def enable():
293 def enable():
286 "enable global demand-loading of modules"
294 "enable global demand-loading of modules"
287 if os.environ.get('HGDEMANDIMPORT') != 'disable':
295 if os.environ.get('HGDEMANDIMPORT') != 'disable':
288 builtins.__import__ = _demandimport
296 builtins.__import__ = _demandimport
289
297
290 def disable():
298 def disable():
291 "disable global demand-loading of modules"
299 "disable global demand-loading of modules"
292 builtins.__import__ = _origimport
300 builtins.__import__ = _origimport
293
301
294 @contextmanager
302 @contextmanager
295 def deactivated():
303 def deactivated():
296 "context manager for disabling demandimport in 'with' blocks"
304 "context manager for disabling demandimport in 'with' blocks"
297 demandenabled = isenabled()
305 demandenabled = isenabled()
298 if demandenabled:
306 if demandenabled:
299 disable()
307 disable()
300
308
301 try:
309 try:
302 yield
310 yield
303 finally:
311 finally:
304 if demandenabled:
312 if demandenabled:
305 enable()
313 enable()
@@ -1,95 +1,106 b''
1 from __future__ import print_function
1 from __future__ import print_function
2
2
3 from mercurial import demandimport
3 from mercurial import demandimport
4 demandimport.enable()
4 demandimport.enable()
5
5
6 import os
6 import os
7 import subprocess
7 import subprocess
8 import sys
8 import sys
9
9
10 # Only run if demandimport is allowed
10 # Only run if demandimport is allowed
11 if subprocess.call(['python', '%s/hghave' % os.environ['TESTDIR'],
11 if subprocess.call(['python', '%s/hghave' % os.environ['TESTDIR'],
12 'demandimport']):
12 'demandimport']):
13 sys.exit(80)
13 sys.exit(80)
14
14
15 if os.name != 'nt':
15 if os.name != 'nt':
16 try:
16 try:
17 import distutils.msvc9compiler
17 import distutils.msvc9compiler
18 print('distutils.msvc9compiler needs to be an immediate '
18 print('distutils.msvc9compiler needs to be an immediate '
19 'importerror on non-windows platforms')
19 'importerror on non-windows platforms')
20 distutils.msvc9compiler
20 distutils.msvc9compiler
21 except ImportError:
21 except ImportError:
22 pass
22 pass
23
23
24 import re
24 import re
25
25
26 rsub = re.sub
26 rsub = re.sub
27 def f(obj):
27 def f(obj):
28 l = repr(obj)
28 l = repr(obj)
29 l = rsub("0x[0-9a-fA-F]+", "0x?", l)
29 l = rsub("0x[0-9a-fA-F]+", "0x?", l)
30 l = rsub("from '.*'", "from '?'", l)
30 l = rsub("from '.*'", "from '?'", l)
31 l = rsub("'<[a-z]*>'", "'<whatever>'", l)
31 l = rsub("'<[a-z]*>'", "'<whatever>'", l)
32 return l
32 return l
33
33
34 import os
34 import os
35
35
36 print("os =", f(os))
36 print("os =", f(os))
37 print("os.system =", f(os.system))
37 print("os.system =", f(os.system))
38 print("os =", f(os))
38 print("os =", f(os))
39
39
40 from mercurial import util
40 from mercurial import util
41
41
42 print("util =", f(util))
42 print("util =", f(util))
43 print("util.system =", f(util.system))
43 print("util.system =", f(util.system))
44 print("util =", f(util))
44 print("util =", f(util))
45 print("util.system =", f(util.system))
45 print("util.system =", f(util.system))
46
46
47 from mercurial import hgweb
47 from mercurial import hgweb
48 print("hgweb =", f(hgweb))
48 print("hgweb =", f(hgweb))
49 print("hgweb_mod =", f(hgweb.hgweb_mod))
49 print("hgweb_mod =", f(hgweb.hgweb_mod))
50 print("hgweb =", f(hgweb))
50 print("hgweb =", f(hgweb))
51
51
52 import re as fred
52 import re as fred
53 print("fred =", f(fred))
53 print("fred =", f(fred))
54
54
55 import re as remod
55 import re as remod
56 print("remod =", f(remod))
56 print("remod =", f(remod))
57
57
58 import sys as re
58 import sys as re
59 print("re =", f(re))
59 print("re =", f(re))
60
60
61 print("fred =", f(fred))
61 print("fred =", f(fred))
62 print("fred.sub =", f(fred.sub))
62 print("fred.sub =", f(fred.sub))
63 print("fred =", f(fred))
63 print("fred =", f(fred))
64
64
65 remod.escape # use remod
65 remod.escape # use remod
66 print("remod =", f(remod))
66 print("remod =", f(remod))
67
67
68 print("re =", f(re))
68 print("re =", f(re))
69 print("re.stderr =", f(re.stderr))
69 print("re.stderr =", f(re.stderr))
70 print("re =", f(re))
70 print("re =", f(re))
71
71
72 # Test access to special attributes through demandmod proxy
73 from mercurial import pvec as pvecproxy
74 print("pvecproxy =", f(pvecproxy))
75 print("pvecproxy.__doc__ = %r"
76 % (' '.join(pvecproxy.__doc__.split()[:3]) + ' ...'))
77 print("pvecproxy.__name__ = %r" % pvecproxy.__name__)
78 # __name__ must be accessible via __dict__ so the relative imports can be
79 # resolved
80 print("pvecproxy.__dict__['__name__'] = %r" % pvecproxy.__dict__['__name__'])
81 print("pvecproxy =", f(pvecproxy))
82
72 import contextlib
83 import contextlib
73 print("contextlib =", f(contextlib))
84 print("contextlib =", f(contextlib))
74 try:
85 try:
75 from contextlib import unknownattr
86 from contextlib import unknownattr
76 print('no demandmod should be created for attribute of non-package '
87 print('no demandmod should be created for attribute of non-package '
77 'module:\ncontextlib.unknownattr =', f(unknownattr))
88 'module:\ncontextlib.unknownattr =', f(unknownattr))
78 except ImportError as inst:
89 except ImportError as inst:
79 print('contextlib.unknownattr = ImportError: %s'
90 print('contextlib.unknownattr = ImportError: %s'
80 % rsub(r"'", '', str(inst)))
91 % rsub(r"'", '', str(inst)))
81
92
82 # Unlike the import statement, __import__() function should not raise
93 # Unlike the import statement, __import__() function should not raise
83 # ImportError even if fromlist has an unknown item
94 # ImportError even if fromlist has an unknown item
84 # (see Python/import.c:import_module_level() and ensure_fromlist())
95 # (see Python/import.c:import_module_level() and ensure_fromlist())
85 contextlibimp = __import__('contextlib', globals(), locals(), ['unknownattr'])
96 contextlibimp = __import__('contextlib', globals(), locals(), ['unknownattr'])
86 print("__import__('contextlib', ..., ['unknownattr']) =", f(contextlibimp))
97 print("__import__('contextlib', ..., ['unknownattr']) =", f(contextlibimp))
87 print("hasattr(contextlibimp, 'unknownattr') =",
98 print("hasattr(contextlibimp, 'unknownattr') =",
88 util.safehasattr(contextlibimp, 'unknownattr'))
99 util.safehasattr(contextlibimp, 'unknownattr'))
89
100
90 demandimport.disable()
101 demandimport.disable()
91 os.environ['HGDEMANDIMPORT'] = 'disable'
102 os.environ['HGDEMANDIMPORT'] = 'disable'
92 # this enable call should not actually enable demandimport!
103 # this enable call should not actually enable demandimport!
93 demandimport.enable()
104 demandimport.enable()
94 from mercurial import node
105 from mercurial import node
95 print("node =", f(node))
106 print("node =", f(node))
@@ -1,25 +1,30 b''
1 os = <unloaded module 'os'>
1 os = <unloaded module 'os'>
2 os.system = <built-in function system>
2 os.system = <built-in function system>
3 os = <module 'os' from '?'>
3 os = <module 'os' from '?'>
4 util = <unloaded module 'util'>
4 util = <unloaded module 'util'>
5 util.system = <function system at 0x?>
5 util.system = <function system at 0x?>
6 util = <module 'mercurial.util' from '?'>
6 util = <module 'mercurial.util' from '?'>
7 util.system = <function system at 0x?>
7 util.system = <function system at 0x?>
8 hgweb = <unloaded module 'hgweb'>
8 hgweb = <unloaded module 'hgweb'>
9 hgweb_mod = <unloaded module 'hgweb_mod'>
9 hgweb_mod = <unloaded module 'hgweb_mod'>
10 hgweb = <module 'mercurial.hgweb' from '?'>
10 hgweb = <module 'mercurial.hgweb' from '?'>
11 fred = <unloaded module 're'>
11 fred = <unloaded module 're'>
12 remod = <unloaded module 're'>
12 remod = <unloaded module 're'>
13 re = <unloaded module 'sys'>
13 re = <unloaded module 'sys'>
14 fred = <unloaded module 're'>
14 fred = <unloaded module 're'>
15 fred.sub = <function sub at 0x?>
15 fred.sub = <function sub at 0x?>
16 fred = <proxied module 're'>
16 fred = <proxied module 're'>
17 remod = <module 're' from '?'>
17 remod = <module 're' from '?'>
18 re = <unloaded module 'sys'>
18 re = <unloaded module 'sys'>
19 re.stderr = <open file '<whatever>', mode 'w' at 0x?>
19 re.stderr = <open file '<whatever>', mode 'w' at 0x?>
20 re = <proxied module 'sys'>
20 re = <proxied module 'sys'>
21 pvecproxy = <unloaded module 'pvec'>
22 pvecproxy.__doc__ = 'A "pvec" is ...'
23 pvecproxy.__name__ = 'mercurial.pvec'
24 pvecproxy.__dict__['__name__'] = 'mercurial.pvec'
25 pvecproxy = <proxied module 'pvec'>
21 contextlib = <unloaded module 'contextlib'>
26 contextlib = <unloaded module 'contextlib'>
22 contextlib.unknownattr = ImportError: cannot import name unknownattr
27 contextlib.unknownattr = ImportError: cannot import name unknownattr
23 __import__('contextlib', ..., ['unknownattr']) = <module 'contextlib' from '?'>
28 __import__('contextlib', ..., ['unknownattr']) = <module 'contextlib' from '?'>
24 hasattr(contextlibimp, 'unknownattr') = False
29 hasattr(contextlibimp, 'unknownattr') = False
25 node = <module 'mercurial.node' from '?'>
30 node = <module 'mercurial.node' from '?'>
General Comments 0
You need to be logged in to leave comments. Login now