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