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