##// END OF EJS Templates
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
Bradley M. Froehle -
Show More
@@ -14,9 +14,9 b' Alternatively, you can add a dreload builtin alongside normal reload with::'
14
14
15 __builtin__.dreload = deepreload.reload
15 __builtin__.dreload = deepreload.reload
16
16
17 This code is almost entirely based on knee.py from the standard library.
17 This code is almost entirely based on knee.py, which is a Python
18 re-implementation of hierarchical module import.
18 """
19 """
19
20 #*****************************************************************************
20 #*****************************************************************************
21 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
21 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
22 #
22 #
@@ -28,135 +28,267 b' import __builtin__'
28 import imp
28 import imp
29 import sys
29 import sys
30
30
31 # Replacement for __import__()
31 from types import ModuleType
32 def deep_import_hook(name, globals=None, locals=None, fromlist=None, level=-1):
32 from warnings import warn
33 # For now level is ignored, it's just there to prevent crash
33
34 # with from __future__ import absolute_import
34 def get_parent(globals, level):
35 parent = determine_parent(globals)
35 """
36 q, tail = find_head_package(parent, name)
36 parent, name = get_parent(globals, level)
37 m = load_tail(q, tail)
37
38 if not fromlist:
38 Return the package that an import is being performed in. If globals comes
39 return q
39 from the module foo.bar.bat (not itself a package), this returns the
40 if hasattr(m, "__path__"):
40 sys.modules entry for foo.bar. If globals is from a package's __init__.py,
41 ensure_fromlist(m, fromlist)
41 the package's entry in sys.modules is returned.
42 return m
42
43 If globals doesn't come from a package or a module in a package, or a
44 corresponding entry is not found in sys.modules, None is returned.
45 """
46 orig_level = level
43
47
44 def determine_parent(globals):
48 if not level or not isinstance(globals, dict):
45 if not globals or not globals.has_key("__name__"):
49 return None, ''
46 return None
50
47 pname = globals['__name__']
51 pkgname = globals.get('__package__', None)
48 if globals.has_key("__path__"):
52
49 parent = sys.modules[pname]
53 if pkgname is not None:
50 assert globals is parent.__dict__
54 # __package__ is set, so use it
51 return parent
55 if not hasattr(pkgname, 'rindex'):
52 if '.' in pname:
56 raise ValueError('__package__ set to non-string')
53 i = pname.rfind('.')
57 if len(pkgname) == 0:
54 pname = pname[:i]
58 if level > 0:
55 parent = sys.modules[pname]
59 raise ValueError('Attempted relative import in non-package')
56 assert parent.__name__ == pname
60 return None, ''
57 return parent
61 name = pkgname
58 return None
59
60 def find_head_package(parent, name):
61 # Import the first
62 if '.' in name:
63 # 'some.nested.package' -> head = 'some', tail = 'nested.package'
64 i = name.find('.')
65 head = name[:i]
66 tail = name[i+1:]
67 else:
62 else:
68 # 'packagename' -> head = 'packagename', tail = ''
63 # __package__ not set, so figure it out and set it
69 head = name
64 if '__name__' not in globals:
70 tail = ""
65 return None, ''
71 if parent:
66 modname = globals['__name__']
72 # If this is a subpackage then qname = parent's name + head
67
73 qname = "%s.%s" % (parent.__name__, head)
68 if '__path__' in globals:
69 # __path__ is set, so modname is already the package name
70 globals['__package__'] = name = modname
71 else:
72 # Normal module, so work out the package name if any
73 lastdot = modname.rfind('.')
74 if lastdot < 0 and level > 0:
75 raise ValueError("Attempted relative import in non-package")
76 if lastdot < 0:
77 globals['__package__'] = None
78 return None, ''
79 globals['__package__'] = name = modname[:lastdot]
80
81 dot = len(name)
82 for x in xrange(level, 1, -1):
83 try:
84 dot = name.rindex('.', 0, dot)
85 except ValueError:
86 raise ValueError("attempted relative import beyond top-level "
87 "package")
88 name = name[:dot]
89
90 try:
91 parent = sys.modules[name]
92 except:
93 if orig_level < 1:
94 warn("Parent module '%.200s' not found while handling absolute "
95 "import" % name)
96 parent = None
97 else:
98 raise SystemError("Parent module '%.200s' not loaded, cannot "
99 "perform relative import" % name)
100
101 # We expect, but can't guarantee, if parent != None, that:
102 # - parent.__name__ == name
103 # - parent.__dict__ is globals
104 # If this is violated... Who cares?
105 return parent, name
106
107 def load_next(mod, altmod, name, buf):
108 """
109 mod, name, buf = load_next(mod, altmod, name, buf)
110
111 altmod is either None or same as mod
112 """
113
114 if len(name) == 0:
115 # completely empty module name should only happen in
116 # 'from . import' (or '__import__("")')
117 return mod, None, buf
118
119 dot = name.find('.')
120 if dot == 0:
121 raise ValueError('Empty module name')
122
123 if dot < 0:
124 subname = name
125 next = None
74 else:
126 else:
75 qname = head
127 subname = name[:dot]
76 q = import_module(head, qname, parent)
128 next = name[dot+1:]
77 if q: return q, tail
78 if parent:
79 qname = head
80 parent = None
81 q = import_module(head, qname, parent)
82 if q: return q, tail
83 raise ImportError, "No module named " + qname
84
85 def load_tail(q, tail):
86 m = q
87 while tail:
88 i = tail.find('.')
89 if i < 0: i = len(tail)
90 head, tail = tail[:i], tail[i+1:]
91
92 # fperez: fix dotted.name reloading failures by changing:
93 #mname = "%s.%s" % (m.__name__, head)
94 # to:
95 mname = m.__name__
96 # This needs more testing!!! (I don't understand this module too well)
97
98 #print '** head,tail=|%s|->|%s|, mname=|%s|' % (head,tail,mname) # dbg
99 m = import_module(head, mname, m)
100 if not m:
101 raise ImportError, "No module named " + mname
102 return m
103
129
104 def ensure_fromlist(m, fromlist, recursive=0):
130 if buf != '':
105 for sub in fromlist:
131 buf += '.'
106 if sub == "*":
132 buf += subname
107 if not recursive:
133
108 try:
134 result = import_submodule(mod, subname, buf)
109 all = m.__all__
135 if result is None and mod != altmod:
110 except AttributeError:
136 result = import_submodule(altmod, subname, subname)
111 pass
137 if result is not None:
112 else:
138 buf = subname
113 ensure_fromlist(m, all, 1)
139
114 continue
140 if result is None:
115 if sub != "*" and not hasattr(m, sub):
141 raise ImportError("No module named %.200s" % name)
116 subname = "%s.%s" % (m.__name__, sub)
142
117 submod = import_module(sub, subname, m)
143 return result, next, buf
118 if not submod:
119 raise ImportError, "No module named " + subname
120
144
121 # Need to keep track of what we've already reloaded to prevent cyclic evil
145 # Need to keep track of what we've already reloaded to prevent cyclic evil
122 found_now = {}
146 found_now = {}
123
147
124 def import_module(partname, fqname, parent):
148 def import_submodule(mod, subname, fullname):
149 """m = import_submodule(mod, subname, fullname)"""
150 # Require:
151 # if mod == None: subname == fullname
152 # else: mod.__name__ + "." + subname == fullname
153
125 global found_now
154 global found_now
126 if found_now.has_key(fqname):
155 if fullname in found_now and fullname in sys.modules:
156 m = sys.modules[fullname]
157 else:
158 print 'Reloading', fullname
159 found_now[fullname] = 1
160 oldm = sys.modules.get(fullname, None)
161
162 if mod is None:
163 path = None
164 elif hasattr(mod, '__path__'):
165 path = mod.__path__
166 else:
167 return None
168
127 try:
169 try:
128 return sys.modules[fqname]
170 fp, filename, stuff = imp.find_module(subname, path)
129 except KeyError:
171 except ImportError:
130 pass
172 return None
173
174 try:
175 m = imp.load_module(fullname, fp, filename, stuff)
176 except:
177 # load_module probably removed name from modules because of
178 # the error. Put back the original module object.
179 if oldm:
180 sys.modules[fullname] = oldm
181 raise
182 finally:
183 if fp: fp.close()
184
185 add_submodule(mod, m, fullname, subname)
186
187 return m
188
189 def add_submodule(mod, submod, fullname, subname):
190 """mod.{subname} = submod"""
191 if mod is None:
192 return #Nothing to do here.
193
194 if submod is None:
195 submod = sys.modules[fullname]
131
196
132 print 'Reloading', fqname #, sys.excepthook is sys.__excepthook__, \
197 setattr(mod, subname, submod)
133 #sys.displayhook is sys.__displayhook__
198
199 return
200
201 def ensure_fromlist(mod, fromlist, buf, recursive):
202 """Handle 'from module import a, b, c' imports."""
203 if not hasattr(mod, '__path__'):
204 return
205 for item in fromlist:
206 if not hasattr(item, 'rindex'):
207 raise TypeError("Item in ``from list'' not a string")
208 if item == '*':
209 if recursive:
210 continue # avoid endless recursion
211 try:
212 all = mod.__all__
213 except AttributeError:
214 pass
215 else:
216 ret = ensure_fromlist(mod, all, buf, 1)
217 if not ret:
218 return 0
219 elif not hasattr(mod, item):
220 import_submodule(mod, item, buf + '.' + item)
221
222 def import_module_level(name, globals=None, locals=None, fromlist=None, level=-1):
223 """Replacement for __import__()"""
224 parent, buf = get_parent(globals, level)
225
226 head, name, buf = load_next(parent, None if level < 0 else parent, name, buf)
227
228 tail = head
229 while name:
230 tail, name, buf = load_next(tail, tail, name, buf)
231
232 # If tail is None, both get_parent and load_next found
233 # an empty module name: someone called __import__("") or
234 # doctored faulty bytecode
235 if tail is None:
236 raise ValueError('Empty module name')
237
238 if not fromlist:
239 return head
134
240
135 found_now[fqname] = 1
241 ensure_fromlist(tail, fromlist, buf, 0)
242 return tail
243
244 modules_reloading = {}
245
246 def reload_module(m):
247 """Replacement for reload()."""
248 if not isinstance(m, ModuleType):
249 raise TypeError("reload() argument must be module")
250
251 name = m.__name__
252
253 if name not in sys.modules:
254 raise ImportError("reload(): module %.200s not in sys.modules" % name)
255
256 global modules_reloading
136 try:
257 try:
137 fp, pathname, stuff = imp.find_module(partname,
258 return modules_reloading[name]
138 parent and parent.__path__)
259 except:
139 except ImportError:
260 modules_reloading[name] = m
140 return None
261
262 dot = name.rfind('.')
263 if dot < 0:
264 subname = name
265 path = None
266 else:
267 try:
268 parent = sys.modules[name[:dot]]
269 except KeyError:
270 modules_reloading.clear()
271 raise ImportError("reload(): parent %.200s not in sys.modules" % name[:dot])
272 subname = name[dot+1:]
273 path = getattr(parent, "__path__", None)
141
274
142 try:
275 try:
143 m = imp.load_module(fqname, fp, pathname, stuff)
276 fp, filename, stuff = imp.find_module(subname, path)
144 finally:
277 finally:
145 if fp: fp.close()
278 modules_reloading.clear()
146
279
147 if parent:
280 try:
148 setattr(parent, partname, m)
281 newm = imp.load_module(name, fp, filename, stuff)
149
282 except:
150 return m
283 # load_module probably removed name from modules because of
284 # the error. Put back the original module object.
285 sys.modules[name] = m
286 raise
287 finally:
288 if fp: fp.close()
151
289
152 def deep_reload_hook(module):
290 modules_reloading.clear()
153 name = module.__name__
291 return newm
154 if '.' not in name:
155 return import_module(name, name, None)
156 i = name.rfind('.')
157 pname = name[:i]
158 parent = sys.modules[pname]
159 return import_module(name[i+1:], name, parent)
160
292
161 # Save the original hooks
293 # Save the original hooks
162 try:
294 try:
@@ -165,7 +297,7 b' except AttributeError:'
165 original_reload = imp.reload # Python 3
297 original_reload = imp.reload # Python 3
166
298
167 # Replacement for reload()
299 # Replacement for reload()
168 def reload(module, exclude=['sys', '__builtin__', '__main__']):
300 def reload(module, exclude=['sys', 'os.path', '__builtin__', '__main__']):
169 """Recursively reload all modules used in the given module. Optionally
301 """Recursively reload all modules used in the given module. Optionally
170 takes a list of modules to exclude from reloading. The default exclude
302 takes a list of modules to exclude from reloading. The default exclude
171 list contains sys, __main__, and __builtin__, to prevent, e.g., resetting
303 list contains sys, __main__, and __builtin__, to prevent, e.g., resetting
@@ -175,9 +307,9 b" def reload(module, exclude=['sys', '__builtin__', '__main__']):"
175 for i in exclude:
307 for i in exclude:
176 found_now[i] = 1
308 found_now[i] = 1
177 original_import = __builtin__.__import__
309 original_import = __builtin__.__import__
178 __builtin__.__import__ = deep_import_hook
310 __builtin__.__import__ = import_module_level
179 try:
311 try:
180 ret = deep_reload_hook(module)
312 ret = reload_module(module)
181 finally:
313 finally:
182 __builtin__.__import__ = original_import
314 __builtin__.__import__ = original_import
183 found_now = {}
315 found_now = {}
General Comments 0
You need to be logged in to leave comments. Login now