##// END OF EJS Templates
demandimport: make it possible to disable by setting HGDEMANDIMPORT=disable...
Mads Kiilerich -
r21025:54af51c1 default
parent child Browse files
Show More
@@ -1,174 +1,175 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 import __builtin__
27 import __builtin__, os
28 _origimport = __import__
28 _origimport = __import__
29
29
30 nothing = object()
30 nothing = object()
31
31
32 try:
32 try:
33 _origimport(__builtin__.__name__, {}, {}, None, -1)
33 _origimport(__builtin__.__name__, {}, {}, None, -1)
34 except TypeError: # no level argument
34 except TypeError: # no level argument
35 def _import(name, globals, locals, fromlist, level):
35 def _import(name, globals, locals, fromlist, level):
36 "call _origimport with no level argument"
36 "call _origimport with no level argument"
37 return _origimport(name, globals, locals, fromlist)
37 return _origimport(name, globals, locals, fromlist)
38 else:
38 else:
39 _import = _origimport
39 _import = _origimport
40
40
41 def _hgextimport(importfunc, name, globals, *args):
41 def _hgextimport(importfunc, name, globals, *args):
42 try:
42 try:
43 return importfunc(name, globals, *args)
43 return importfunc(name, globals, *args)
44 except ImportError:
44 except ImportError:
45 if not globals:
45 if not globals:
46 raise
46 raise
47 # extensions are loaded with "hgext_" prefix
47 # extensions are loaded with "hgext_" prefix
48 hgextname = 'hgext_%s' % name
48 hgextname = 'hgext_%s' % name
49 nameroot = hgextname.split('.', 1)[0]
49 nameroot = hgextname.split('.', 1)[0]
50 contextroot = globals.get('__name__', '').split('.', 1)[0]
50 contextroot = globals.get('__name__', '').split('.', 1)[0]
51 if nameroot != contextroot:
51 if nameroot != contextroot:
52 raise
52 raise
53 # retry to import with "hgext_" prefix
53 # retry to import with "hgext_" prefix
54 return importfunc(hgextname, globals, *args)
54 return importfunc(hgextname, globals, *args)
55
55
56 class _demandmod(object):
56 class _demandmod(object):
57 """module demand-loader and proxy"""
57 """module demand-loader and proxy"""
58 def __init__(self, name, globals, locals, level=-1):
58 def __init__(self, name, globals, locals, level=-1):
59 if '.' in name:
59 if '.' in name:
60 head, rest = name.split('.', 1)
60 head, rest = name.split('.', 1)
61 after = [rest]
61 after = [rest]
62 else:
62 else:
63 head = name
63 head = name
64 after = []
64 after = []
65 object.__setattr__(self, "_data",
65 object.__setattr__(self, "_data",
66 (head, globals, locals, after, level))
66 (head, globals, locals, after, level))
67 object.__setattr__(self, "_module", None)
67 object.__setattr__(self, "_module", None)
68 def _extend(self, name):
68 def _extend(self, name):
69 """add to the list of submodules to load"""
69 """add to the list of submodules to load"""
70 self._data[3].append(name)
70 self._data[3].append(name)
71 def _load(self):
71 def _load(self):
72 if not self._module:
72 if not self._module:
73 head, globals, locals, after, level = self._data
73 head, globals, locals, after, level = self._data
74 mod = _hgextimport(_import, head, globals, locals, None, level)
74 mod = _hgextimport(_import, head, globals, locals, None, level)
75 # load submodules
75 # load submodules
76 def subload(mod, p):
76 def subload(mod, p):
77 h, t = p, None
77 h, t = p, None
78 if '.' in p:
78 if '.' in p:
79 h, t = p.split('.', 1)
79 h, t = p.split('.', 1)
80 if getattr(mod, h, nothing) is nothing:
80 if getattr(mod, h, nothing) is nothing:
81 setattr(mod, h, _demandmod(p, mod.__dict__, mod.__dict__))
81 setattr(mod, h, _demandmod(p, mod.__dict__, mod.__dict__))
82 elif t:
82 elif t:
83 subload(getattr(mod, h), t)
83 subload(getattr(mod, h), t)
84
84
85 for x in after:
85 for x in after:
86 subload(mod, x)
86 subload(mod, x)
87
87
88 # are we in the locals dictionary still?
88 # are we in the locals dictionary still?
89 if locals and locals.get(head) == self:
89 if locals and locals.get(head) == self:
90 locals[head] = mod
90 locals[head] = mod
91 object.__setattr__(self, "_module", mod)
91 object.__setattr__(self, "_module", mod)
92
92
93 def __repr__(self):
93 def __repr__(self):
94 if self._module:
94 if self._module:
95 return "<proxied module '%s'>" % self._data[0]
95 return "<proxied module '%s'>" % self._data[0]
96 return "<unloaded module '%s'>" % self._data[0]
96 return "<unloaded module '%s'>" % self._data[0]
97 def __call__(self, *args, **kwargs):
97 def __call__(self, *args, **kwargs):
98 raise TypeError("%s object is not callable" % repr(self))
98 raise TypeError("%s object is not callable" % repr(self))
99 def __getattribute__(self, attr):
99 def __getattribute__(self, attr):
100 if attr in ('_data', '_extend', '_load', '_module'):
100 if attr in ('_data', '_extend', '_load', '_module'):
101 return object.__getattribute__(self, attr)
101 return object.__getattribute__(self, attr)
102 self._load()
102 self._load()
103 return getattr(self._module, attr)
103 return getattr(self._module, attr)
104 def __setattr__(self, attr, val):
104 def __setattr__(self, attr, val):
105 self._load()
105 self._load()
106 setattr(self._module, attr, val)
106 setattr(self._module, attr, val)
107
107
108 def _demandimport(name, globals=None, locals=None, fromlist=None, level=-1):
108 def _demandimport(name, globals=None, locals=None, fromlist=None, level=-1):
109 if not locals or name in ignore or fromlist == ('*',):
109 if not locals or name in ignore or fromlist == ('*',):
110 # these cases we can't really delay
110 # these cases we can't really delay
111 return _hgextimport(_import, name, globals, locals, fromlist, level)
111 return _hgextimport(_import, name, globals, locals, fromlist, level)
112 elif not fromlist:
112 elif not fromlist:
113 # import a [as b]
113 # import a [as b]
114 if '.' in name: # a.b
114 if '.' in name: # a.b
115 base, rest = name.split('.', 1)
115 base, rest = name.split('.', 1)
116 # email.__init__ loading email.mime
116 # email.__init__ loading email.mime
117 if globals and globals.get('__name__', None) == base:
117 if globals and globals.get('__name__', None) == base:
118 return _import(name, globals, locals, fromlist, level)
118 return _import(name, globals, locals, fromlist, level)
119 # if a is already demand-loaded, add b to its submodule list
119 # if a is already demand-loaded, add b to its submodule list
120 if base in locals:
120 if base in locals:
121 if isinstance(locals[base], _demandmod):
121 if isinstance(locals[base], _demandmod):
122 locals[base]._extend(rest)
122 locals[base]._extend(rest)
123 return locals[base]
123 return locals[base]
124 return _demandmod(name, globals, locals, level)
124 return _demandmod(name, globals, locals, level)
125 else:
125 else:
126 if level != -1:
126 if level != -1:
127 # from . import b,c,d or from .a import b,c,d
127 # from . import b,c,d or from .a import b,c,d
128 return _origimport(name, globals, locals, fromlist, level)
128 return _origimport(name, globals, locals, fromlist, level)
129 # from a import b,c,d
129 # from a import b,c,d
130 mod = _hgextimport(_origimport, name, globals, locals)
130 mod = _hgextimport(_origimport, name, globals, locals)
131 # recurse down the module chain
131 # recurse down the module chain
132 for comp in name.split('.')[1:]:
132 for comp in name.split('.')[1:]:
133 if getattr(mod, comp, nothing) is nothing:
133 if getattr(mod, comp, nothing) is nothing:
134 setattr(mod, comp, _demandmod(comp, mod.__dict__, mod.__dict__))
134 setattr(mod, comp, _demandmod(comp, mod.__dict__, mod.__dict__))
135 mod = getattr(mod, comp)
135 mod = getattr(mod, comp)
136 for x in fromlist:
136 for x in fromlist:
137 # set requested submodules for demand load
137 # set requested submodules for demand load
138 if getattr(mod, x, nothing) is nothing:
138 if getattr(mod, x, nothing) is nothing:
139 setattr(mod, x, _demandmod(x, mod.__dict__, locals))
139 setattr(mod, x, _demandmod(x, mod.__dict__, locals))
140 return mod
140 return mod
141
141
142 ignore = [
142 ignore = [
143 '_hashlib',
143 '_hashlib',
144 '_xmlplus',
144 '_xmlplus',
145 'fcntl',
145 'fcntl',
146 'win32com.gen_py',
146 'win32com.gen_py',
147 '_winreg', # 2.7 mimetypes needs immediate ImportError
147 '_winreg', # 2.7 mimetypes needs immediate ImportError
148 'pythoncom',
148 'pythoncom',
149 # imported by tarfile, not available under Windows
149 # imported by tarfile, not available under Windows
150 'pwd',
150 'pwd',
151 'grp',
151 'grp',
152 # imported by profile, itself imported by hotshot.stats,
152 # imported by profile, itself imported by hotshot.stats,
153 # not available under Windows
153 # not available under Windows
154 'resource',
154 'resource',
155 # this trips up many extension authors
155 # this trips up many extension authors
156 'gtk',
156 'gtk',
157 # setuptools' pkg_resources.py expects "from __main__ import x" to
157 # setuptools' pkg_resources.py expects "from __main__ import x" to
158 # raise ImportError if x not defined
158 # raise ImportError if x not defined
159 '__main__',
159 '__main__',
160 '_ssl', # conditional imports in the stdlib, issue1964
160 '_ssl', # conditional imports in the stdlib, issue1964
161 'rfc822',
161 'rfc822',
162 'mimetools',
162 'mimetools',
163 ]
163 ]
164
164
165 def isenabled():
165 def isenabled():
166 return __builtin__.__import__ == _demandimport
166 return __builtin__.__import__ == _demandimport
167
167
168 def enable():
168 def enable():
169 "enable global demand-loading of modules"
169 "enable global demand-loading of modules"
170 __builtin__.__import__ = _demandimport
170 if os.environ.get('HGDEMANDIMPORT') != 'disable':
171 __builtin__.__import__ = _demandimport
171
172
172 def disable():
173 def disable():
173 "disable global demand-loading of modules"
174 "disable global demand-loading of modules"
174 __builtin__.__import__ = _origimport
175 __builtin__.__import__ = _origimport
@@ -1,39 +1,45 b''
1 from mercurial import demandimport
1 from mercurial import demandimport
2 demandimport.enable()
2 demandimport.enable()
3
3
4 import re
4 import re
5
5
6 rsub = re.sub
6 rsub = re.sub
7 def f(obj):
7 def f(obj):
8 l = repr(obj)
8 l = repr(obj)
9 l = rsub("0x[0-9a-fA-F]+", "0x?", l)
9 l = rsub("0x[0-9a-fA-F]+", "0x?", l)
10 l = rsub("from '.*'", "from '?'", l)
10 l = rsub("from '.*'", "from '?'", l)
11 l = rsub("'<[a-z]*>'", "'<whatever>'", l)
11 l = rsub("'<[a-z]*>'", "'<whatever>'", l)
12 return l
12 return l
13
13
14 import os
14 import os
15
15
16 print "os =", f(os)
16 print "os =", f(os)
17 print "os.system =", f(os.system)
17 print "os.system =", f(os.system)
18 print "os =", f(os)
18 print "os =", f(os)
19
19
20 from mercurial import util
20 from mercurial import util
21
21
22 print "util =", f(util)
22 print "util =", f(util)
23 print "util.system =", f(util.system)
23 print "util.system =", f(util.system)
24 print "util =", f(util)
24 print "util =", f(util)
25 print "util.system =", f(util.system)
25 print "util.system =", f(util.system)
26
26
27 import re as fred
27 import re as fred
28 print "fred =", f(fred)
28 print "fred =", f(fred)
29
29
30 import sys as re
30 import sys as re
31 print "re =", f(re)
31 print "re =", f(re)
32
32
33 print "fred =", f(fred)
33 print "fred =", f(fred)
34 print "fred.sub =", f(fred.sub)
34 print "fred.sub =", f(fred.sub)
35 print "fred =", f(fred)
35 print "fred =", f(fred)
36
36
37 print "re =", f(re)
37 print "re =", f(re)
38 print "re.stderr =", f(re.stderr)
38 print "re.stderr =", f(re.stderr)
39 print "re =", f(re)
39 print "re =", f(re)
40
41 demandimport.disable()
42 os.environ['HGDEMANDIMPORT'] = 'disable'
43 demandimport.enable()
44 from mercurial import node
45 print "node =", f(node)
@@ -1,15 +1,16 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 fred = <unloaded module 're'>
8 fred = <unloaded module 're'>
9 re = <unloaded module 'sys'>
9 re = <unloaded module 'sys'>
10 fred = <unloaded module 're'>
10 fred = <unloaded module 're'>
11 fred.sub = <function sub at 0x?>
11 fred.sub = <function sub at 0x?>
12 fred = <proxied module 're'>
12 fred = <proxied module 're'>
13 re = <unloaded module 'sys'>
13 re = <unloaded module 'sys'>
14 re.stderr = <open file '<whatever>', mode 'w' at 0x?>
14 re.stderr = <open file '<whatever>', mode 'w' at 0x?>
15 re = <proxied module 'sys'>
15 re = <proxied module 'sys'>
16 node = <module 'mercurial.node' from '?'>
General Comments 0
You need to be logged in to leave comments. Login now