##// END OF EJS Templates
fix to autoreload for cases when module has no __name__ attribute
jc -
Show More
@@ -1,536 +1,536 b''
1 """IPython extension to reload modules before executing user code.
1 """IPython extension to reload modules before executing user code.
2
2
3 ``autoreload`` reloads modules automatically before entering the execution of
3 ``autoreload`` reloads modules automatically before entering the execution of
4 code typed at the IPython prompt.
4 code typed at the IPython prompt.
5
5
6 This makes for example the following workflow possible:
6 This makes for example the following workflow possible:
7
7
8 .. sourcecode:: ipython
8 .. sourcecode:: ipython
9
9
10 In [1]: %load_ext autoreload
10 In [1]: %load_ext autoreload
11
11
12 In [2]: %autoreload 2
12 In [2]: %autoreload 2
13
13
14 In [3]: from foo import some_function
14 In [3]: from foo import some_function
15
15
16 In [4]: some_function()
16 In [4]: some_function()
17 Out[4]: 42
17 Out[4]: 42
18
18
19 In [5]: # open foo.py in an editor and change some_function to return 43
19 In [5]: # open foo.py in an editor and change some_function to return 43
20
20
21 In [6]: some_function()
21 In [6]: some_function()
22 Out[6]: 43
22 Out[6]: 43
23
23
24 The module was reloaded without reloading it explicitly, and the object
24 The module was reloaded without reloading it explicitly, and the object
25 imported with ``from foo import ...`` was also updated.
25 imported with ``from foo import ...`` was also updated.
26
26
27 Usage
27 Usage
28 =====
28 =====
29
29
30 The following magic commands are provided:
30 The following magic commands are provided:
31
31
32 ``%autoreload``
32 ``%autoreload``
33
33
34 Reload all modules (except those excluded by ``%aimport``)
34 Reload all modules (except those excluded by ``%aimport``)
35 automatically now.
35 automatically now.
36
36
37 ``%autoreload 0``
37 ``%autoreload 0``
38
38
39 Disable automatic reloading.
39 Disable automatic reloading.
40
40
41 ``%autoreload 1``
41 ``%autoreload 1``
42
42
43 Reload all modules imported with ``%aimport`` every time before
43 Reload all modules imported with ``%aimport`` every time before
44 executing the Python code typed.
44 executing the Python code typed.
45
45
46 ``%autoreload 2``
46 ``%autoreload 2``
47
47
48 Reload all modules (except those excluded by ``%aimport``) every
48 Reload all modules (except those excluded by ``%aimport``) every
49 time before executing the Python code typed.
49 time before executing the Python code typed.
50
50
51 ``%aimport``
51 ``%aimport``
52
52
53 List modules which are to be automatically imported or not to be imported.
53 List modules which are to be automatically imported or not to be imported.
54
54
55 ``%aimport foo``
55 ``%aimport foo``
56
56
57 Import module 'foo' and mark it to be autoreloaded for ``%autoreload 1``
57 Import module 'foo' and mark it to be autoreloaded for ``%autoreload 1``
58
58
59 ``%aimport -foo``
59 ``%aimport -foo``
60
60
61 Mark module 'foo' to not be autoreloaded.
61 Mark module 'foo' to not be autoreloaded.
62
62
63 Caveats
63 Caveats
64 =======
64 =======
65
65
66 Reloading Python modules in a reliable way is in general difficult,
66 Reloading Python modules in a reliable way is in general difficult,
67 and unexpected things may occur. ``%autoreload`` tries to work around
67 and unexpected things may occur. ``%autoreload`` tries to work around
68 common pitfalls by replacing function code objects and parts of
68 common pitfalls by replacing function code objects and parts of
69 classes previously in the module with new versions. This makes the
69 classes previously in the module with new versions. This makes the
70 following things to work:
70 following things to work:
71
71
72 - Functions and classes imported via 'from xxx import foo' are upgraded
72 - Functions and classes imported via 'from xxx import foo' are upgraded
73 to new versions when 'xxx' is reloaded.
73 to new versions when 'xxx' is reloaded.
74
74
75 - Methods and properties of classes are upgraded on reload, so that
75 - Methods and properties of classes are upgraded on reload, so that
76 calling 'c.foo()' on an object 'c' created before the reload causes
76 calling 'c.foo()' on an object 'c' created before the reload causes
77 the new code for 'foo' to be executed.
77 the new code for 'foo' to be executed.
78
78
79 Some of the known remaining caveats are:
79 Some of the known remaining caveats are:
80
80
81 - Replacing code objects does not always succeed: changing a @property
81 - Replacing code objects does not always succeed: changing a @property
82 in a class to an ordinary method or a method to a member variable
82 in a class to an ordinary method or a method to a member variable
83 can cause problems (but in old objects only).
83 can cause problems (but in old objects only).
84
84
85 - Functions that are removed (eg. via monkey-patching) from a module
85 - Functions that are removed (eg. via monkey-patching) from a module
86 before it is reloaded are not upgraded.
86 before it is reloaded are not upgraded.
87
87
88 - C extension modules cannot be reloaded, and so cannot be autoreloaded.
88 - C extension modules cannot be reloaded, and so cannot be autoreloaded.
89 """
89 """
90 from __future__ import print_function
90 from __future__ import print_function
91
91
92 skip_doctest = True
92 skip_doctest = True
93
93
94 #-----------------------------------------------------------------------------
94 #-----------------------------------------------------------------------------
95 # Copyright (C) 2000 Thomas Heller
95 # Copyright (C) 2000 Thomas Heller
96 # Copyright (C) 2008 Pauli Virtanen <pav@iki.fi>
96 # Copyright (C) 2008 Pauli Virtanen <pav@iki.fi>
97 # Copyright (C) 2012 The IPython Development Team
97 # Copyright (C) 2012 The IPython Development Team
98 #
98 #
99 # Distributed under the terms of the BSD License. The full license is in
99 # Distributed under the terms of the BSD License. The full license is in
100 # the file COPYING, distributed as part of this software.
100 # the file COPYING, distributed as part of this software.
101 #-----------------------------------------------------------------------------
101 #-----------------------------------------------------------------------------
102 #
102 #
103 # This IPython module is written by Pauli Virtanen, based on the autoreload
103 # This IPython module is written by Pauli Virtanen, based on the autoreload
104 # code by Thomas Heller.
104 # code by Thomas Heller.
105
105
106 #-----------------------------------------------------------------------------
106 #-----------------------------------------------------------------------------
107 # Imports
107 # Imports
108 #-----------------------------------------------------------------------------
108 #-----------------------------------------------------------------------------
109
109
110 import os
110 import os
111 import sys
111 import sys
112 import traceback
112 import traceback
113 import types
113 import types
114 import weakref
114 import weakref
115
115
116 try:
116 try:
117 # Reload is not defined by default in Python3.
117 # Reload is not defined by default in Python3.
118 reload
118 reload
119 except NameError:
119 except NameError:
120 from imp import reload
120 from imp import reload
121
121
122 from IPython.utils import openpy
122 from IPython.utils import openpy
123 from IPython.utils.py3compat import PY3
123 from IPython.utils.py3compat import PY3
124
124
125 #------------------------------------------------------------------------------
125 #------------------------------------------------------------------------------
126 # Autoreload functionality
126 # Autoreload functionality
127 #------------------------------------------------------------------------------
127 #------------------------------------------------------------------------------
128
128
129 class ModuleReloader(object):
129 class ModuleReloader(object):
130 enabled = False
130 enabled = False
131 """Whether this reloader is enabled"""
131 """Whether this reloader is enabled"""
132
132
133 check_all = True
133 check_all = True
134 """Autoreload all modules, not just those listed in 'modules'"""
134 """Autoreload all modules, not just those listed in 'modules'"""
135
135
136 def __init__(self):
136 def __init__(self):
137 # Modules that failed to reload: {module: mtime-on-failed-reload, ...}
137 # Modules that failed to reload: {module: mtime-on-failed-reload, ...}
138 self.failed = {}
138 self.failed = {}
139 # Modules specially marked as autoreloadable.
139 # Modules specially marked as autoreloadable.
140 self.modules = {}
140 self.modules = {}
141 # Modules specially marked as not autoreloadable.
141 # Modules specially marked as not autoreloadable.
142 self.skip_modules = {}
142 self.skip_modules = {}
143 # (module-name, name) -> weakref, for replacing old code objects
143 # (module-name, name) -> weakref, for replacing old code objects
144 self.old_objects = {}
144 self.old_objects = {}
145 # Module modification timestamps
145 # Module modification timestamps
146 self.modules_mtimes = {}
146 self.modules_mtimes = {}
147
147
148 # Cache module modification times
148 # Cache module modification times
149 self.check(check_all=True, do_reload=False)
149 self.check(check_all=True, do_reload=False)
150
150
151 def mark_module_skipped(self, module_name):
151 def mark_module_skipped(self, module_name):
152 """Skip reloading the named module in the future"""
152 """Skip reloading the named module in the future"""
153 try:
153 try:
154 del self.modules[module_name]
154 del self.modules[module_name]
155 except KeyError:
155 except KeyError:
156 pass
156 pass
157 self.skip_modules[module_name] = True
157 self.skip_modules[module_name] = True
158
158
159 def mark_module_reloadable(self, module_name):
159 def mark_module_reloadable(self, module_name):
160 """Reload the named module in the future (if it is imported)"""
160 """Reload the named module in the future (if it is imported)"""
161 try:
161 try:
162 del self.skip_modules[module_name]
162 del self.skip_modules[module_name]
163 except KeyError:
163 except KeyError:
164 pass
164 pass
165 self.modules[module_name] = True
165 self.modules[module_name] = True
166
166
167 def aimport_module(self, module_name):
167 def aimport_module(self, module_name):
168 """Import a module, and mark it reloadable
168 """Import a module, and mark it reloadable
169
169
170 Returns
170 Returns
171 -------
171 -------
172 top_module : module
172 top_module : module
173 The imported module if it is top-level, or the top-level
173 The imported module if it is top-level, or the top-level
174 top_name : module
174 top_name : module
175 Name of top_module
175 Name of top_module
176
176
177 """
177 """
178 self.mark_module_reloadable(module_name)
178 self.mark_module_reloadable(module_name)
179
179
180 __import__(module_name)
180 __import__(module_name)
181 top_name = module_name.split('.')[0]
181 top_name = module_name.split('.')[0]
182 top_module = sys.modules[top_name]
182 top_module = sys.modules[top_name]
183 return top_module, top_name
183 return top_module, top_name
184
184
185 def filename_and_mtime(self, module):
185 def filename_and_mtime(self, module):
186 if not hasattr(module, '__file__') or module.__file__ is None:
186 if not hasattr(module, '__file__') or module.__file__ is None:
187 return None, None
187 return None, None
188
188
189 if module.__name__ == '__main__':
189 if getattr(module, '__name__', None) == '__main__':
190 # we cannot reload(__main__)
190 # we cannot reload(__main__)
191 return None, None
191 return None, None
192
192
193 filename = module.__file__
193 filename = module.__file__
194 path, ext = os.path.splitext(filename)
194 path, ext = os.path.splitext(filename)
195
195
196 if ext.lower() == '.py':
196 if ext.lower() == '.py':
197 py_filename = filename
197 py_filename = filename
198 else:
198 else:
199 try:
199 try:
200 py_filename = openpy.source_from_cache(filename)
200 py_filename = openpy.source_from_cache(filename)
201 except ValueError:
201 except ValueError:
202 return None, None
202 return None, None
203
203
204 try:
204 try:
205 pymtime = os.stat(py_filename).st_mtime
205 pymtime = os.stat(py_filename).st_mtime
206 except OSError:
206 except OSError:
207 return None, None
207 return None, None
208
208
209 return py_filename, pymtime
209 return py_filename, pymtime
210
210
211 def check(self, check_all=False, do_reload=True):
211 def check(self, check_all=False, do_reload=True):
212 """Check whether some modules need to be reloaded."""
212 """Check whether some modules need to be reloaded."""
213
213
214 if not self.enabled and not check_all:
214 if not self.enabled and not check_all:
215 return
215 return
216
216
217 if check_all or self.check_all:
217 if check_all or self.check_all:
218 modules = list(sys.modules.keys())
218 modules = list(sys.modules.keys())
219 else:
219 else:
220 modules = list(self.modules.keys())
220 modules = list(self.modules.keys())
221
221
222 for modname in modules:
222 for modname in modules:
223 m = sys.modules.get(modname, None)
223 m = sys.modules.get(modname, None)
224
224
225 if modname in self.skip_modules:
225 if modname in self.skip_modules:
226 continue
226 continue
227
227
228 py_filename, pymtime = self.filename_and_mtime(m)
228 py_filename, pymtime = self.filename_and_mtime(m)
229 if py_filename is None:
229 if py_filename is None:
230 continue
230 continue
231
231
232 try:
232 try:
233 if pymtime <= self.modules_mtimes[modname]:
233 if pymtime <= self.modules_mtimes[modname]:
234 continue
234 continue
235 except KeyError:
235 except KeyError:
236 self.modules_mtimes[modname] = pymtime
236 self.modules_mtimes[modname] = pymtime
237 continue
237 continue
238 else:
238 else:
239 if self.failed.get(py_filename, None) == pymtime:
239 if self.failed.get(py_filename, None) == pymtime:
240 continue
240 continue
241
241
242 self.modules_mtimes[modname] = pymtime
242 self.modules_mtimes[modname] = pymtime
243
243
244 # If we've reached this point, we should try to reload the module
244 # If we've reached this point, we should try to reload the module
245 if do_reload:
245 if do_reload:
246 try:
246 try:
247 superreload(m, reload, self.old_objects)
247 superreload(m, reload, self.old_objects)
248 if py_filename in self.failed:
248 if py_filename in self.failed:
249 del self.failed[py_filename]
249 del self.failed[py_filename]
250 except:
250 except:
251 print("[autoreload of %s failed: %s]" % (
251 print("[autoreload of %s failed: %s]" % (
252 modname, traceback.format_exc(1)), file=sys.stderr)
252 modname, traceback.format_exc(1)), file=sys.stderr)
253 self.failed[py_filename] = pymtime
253 self.failed[py_filename] = pymtime
254
254
255 #------------------------------------------------------------------------------
255 #------------------------------------------------------------------------------
256 # superreload
256 # superreload
257 #------------------------------------------------------------------------------
257 #------------------------------------------------------------------------------
258
258
259 if PY3:
259 if PY3:
260 func_attrs = ['__code__', '__defaults__', '__doc__',
260 func_attrs = ['__code__', '__defaults__', '__doc__',
261 '__closure__', '__globals__', '__dict__']
261 '__closure__', '__globals__', '__dict__']
262 else:
262 else:
263 func_attrs = ['func_code', 'func_defaults', 'func_doc',
263 func_attrs = ['func_code', 'func_defaults', 'func_doc',
264 'func_closure', 'func_globals', 'func_dict']
264 'func_closure', 'func_globals', 'func_dict']
265
265
266
266
267 def update_function(old, new):
267 def update_function(old, new):
268 """Upgrade the code object of a function"""
268 """Upgrade the code object of a function"""
269 for name in func_attrs:
269 for name in func_attrs:
270 try:
270 try:
271 setattr(old, name, getattr(new, name))
271 setattr(old, name, getattr(new, name))
272 except (AttributeError, TypeError):
272 except (AttributeError, TypeError):
273 pass
273 pass
274
274
275
275
276 def update_class(old, new):
276 def update_class(old, new):
277 """Replace stuff in the __dict__ of a class, and upgrade
277 """Replace stuff in the __dict__ of a class, and upgrade
278 method code objects"""
278 method code objects"""
279 for key in list(old.__dict__.keys()):
279 for key in list(old.__dict__.keys()):
280 old_obj = getattr(old, key)
280 old_obj = getattr(old, key)
281
281
282 try:
282 try:
283 new_obj = getattr(new, key)
283 new_obj = getattr(new, key)
284 except AttributeError:
284 except AttributeError:
285 # obsolete attribute: remove it
285 # obsolete attribute: remove it
286 try:
286 try:
287 delattr(old, key)
287 delattr(old, key)
288 except (AttributeError, TypeError):
288 except (AttributeError, TypeError):
289 pass
289 pass
290 continue
290 continue
291
291
292 if update_generic(old_obj, new_obj): continue
292 if update_generic(old_obj, new_obj): continue
293
293
294 try:
294 try:
295 setattr(old, key, getattr(new, key))
295 setattr(old, key, getattr(new, key))
296 except (AttributeError, TypeError):
296 except (AttributeError, TypeError):
297 pass # skip non-writable attributes
297 pass # skip non-writable attributes
298
298
299
299
300 def update_property(old, new):
300 def update_property(old, new):
301 """Replace get/set/del functions of a property"""
301 """Replace get/set/del functions of a property"""
302 update_generic(old.fdel, new.fdel)
302 update_generic(old.fdel, new.fdel)
303 update_generic(old.fget, new.fget)
303 update_generic(old.fget, new.fget)
304 update_generic(old.fset, new.fset)
304 update_generic(old.fset, new.fset)
305
305
306
306
307 def isinstance2(a, b, typ):
307 def isinstance2(a, b, typ):
308 return isinstance(a, typ) and isinstance(b, typ)
308 return isinstance(a, typ) and isinstance(b, typ)
309
309
310
310
311 UPDATE_RULES = [
311 UPDATE_RULES = [
312 (lambda a, b: isinstance2(a, b, type),
312 (lambda a, b: isinstance2(a, b, type),
313 update_class),
313 update_class),
314 (lambda a, b: isinstance2(a, b, types.FunctionType),
314 (lambda a, b: isinstance2(a, b, types.FunctionType),
315 update_function),
315 update_function),
316 (lambda a, b: isinstance2(a, b, property),
316 (lambda a, b: isinstance2(a, b, property),
317 update_property),
317 update_property),
318 ]
318 ]
319
319
320
320
321 if PY3:
321 if PY3:
322 UPDATE_RULES.extend([(lambda a, b: isinstance2(a, b, types.MethodType),
322 UPDATE_RULES.extend([(lambda a, b: isinstance2(a, b, types.MethodType),
323 lambda a, b: update_function(a.__func__, b.__func__)),
323 lambda a, b: update_function(a.__func__, b.__func__)),
324 ])
324 ])
325 else:
325 else:
326 UPDATE_RULES.extend([(lambda a, b: isinstance2(a, b, types.ClassType),
326 UPDATE_RULES.extend([(lambda a, b: isinstance2(a, b, types.ClassType),
327 update_class),
327 update_class),
328 (lambda a, b: isinstance2(a, b, types.MethodType),
328 (lambda a, b: isinstance2(a, b, types.MethodType),
329 lambda a, b: update_function(a.__func__, b.__func__)),
329 lambda a, b: update_function(a.__func__, b.__func__)),
330 ])
330 ])
331
331
332
332
333 def update_generic(a, b):
333 def update_generic(a, b):
334 for type_check, update in UPDATE_RULES:
334 for type_check, update in UPDATE_RULES:
335 if type_check(a, b):
335 if type_check(a, b):
336 update(a, b)
336 update(a, b)
337 return True
337 return True
338 return False
338 return False
339
339
340
340
341 class StrongRef(object):
341 class StrongRef(object):
342 def __init__(self, obj):
342 def __init__(self, obj):
343 self.obj = obj
343 self.obj = obj
344 def __call__(self):
344 def __call__(self):
345 return self.obj
345 return self.obj
346
346
347
347
348 def superreload(module, reload=reload, old_objects={}):
348 def superreload(module, reload=reload, old_objects={}):
349 """Enhanced version of the builtin reload function.
349 """Enhanced version of the builtin reload function.
350
350
351 superreload remembers objects previously in the module, and
351 superreload remembers objects previously in the module, and
352
352
353 - upgrades the class dictionary of every old class in the module
353 - upgrades the class dictionary of every old class in the module
354 - upgrades the code object of every old function and method
354 - upgrades the code object of every old function and method
355 - clears the module's namespace before reloading
355 - clears the module's namespace before reloading
356
356
357 """
357 """
358
358
359 # collect old objects in the module
359 # collect old objects in the module
360 for name, obj in list(module.__dict__.items()):
360 for name, obj in list(module.__dict__.items()):
361 if not hasattr(obj, '__module__') or obj.__module__ != module.__name__:
361 if not hasattr(obj, '__module__') or obj.__module__ != module.__name__:
362 continue
362 continue
363 key = (module.__name__, name)
363 key = (module.__name__, name)
364 try:
364 try:
365 old_objects.setdefault(key, []).append(weakref.ref(obj))
365 old_objects.setdefault(key, []).append(weakref.ref(obj))
366 except TypeError:
366 except TypeError:
367 # weakref doesn't work for all types;
367 # weakref doesn't work for all types;
368 # create strong references for 'important' cases
368 # create strong references for 'important' cases
369 if not PY3 and isinstance(obj, types.ClassType):
369 if not PY3 and isinstance(obj, types.ClassType):
370 old_objects.setdefault(key, []).append(StrongRef(obj))
370 old_objects.setdefault(key, []).append(StrongRef(obj))
371
371
372 # reload module
372 # reload module
373 try:
373 try:
374 # clear namespace first from old cruft
374 # clear namespace first from old cruft
375 old_dict = module.__dict__.copy()
375 old_dict = module.__dict__.copy()
376 old_name = module.__name__
376 old_name = module.__name__
377 module.__dict__.clear()
377 module.__dict__.clear()
378 module.__dict__['__name__'] = old_name
378 module.__dict__['__name__'] = old_name
379 module.__dict__['__loader__'] = old_dict['__loader__']
379 module.__dict__['__loader__'] = old_dict['__loader__']
380 except (TypeError, AttributeError, KeyError):
380 except (TypeError, AttributeError, KeyError):
381 pass
381 pass
382
382
383 try:
383 try:
384 module = reload(module)
384 module = reload(module)
385 except:
385 except:
386 # restore module dictionary on failed reload
386 # restore module dictionary on failed reload
387 module.__dict__.update(old_dict)
387 module.__dict__.update(old_dict)
388 raise
388 raise
389
389
390 # iterate over all objects and update functions & classes
390 # iterate over all objects and update functions & classes
391 for name, new_obj in list(module.__dict__.items()):
391 for name, new_obj in list(module.__dict__.items()):
392 key = (module.__name__, name)
392 key = (module.__name__, name)
393 if key not in old_objects: continue
393 if key not in old_objects: continue
394
394
395 new_refs = []
395 new_refs = []
396 for old_ref in old_objects[key]:
396 for old_ref in old_objects[key]:
397 old_obj = old_ref()
397 old_obj = old_ref()
398 if old_obj is None: continue
398 if old_obj is None: continue
399 new_refs.append(old_ref)
399 new_refs.append(old_ref)
400 update_generic(old_obj, new_obj)
400 update_generic(old_obj, new_obj)
401
401
402 if new_refs:
402 if new_refs:
403 old_objects[key] = new_refs
403 old_objects[key] = new_refs
404 else:
404 else:
405 del old_objects[key]
405 del old_objects[key]
406
406
407 return module
407 return module
408
408
409 #------------------------------------------------------------------------------
409 #------------------------------------------------------------------------------
410 # IPython connectivity
410 # IPython connectivity
411 #------------------------------------------------------------------------------
411 #------------------------------------------------------------------------------
412
412
413 from IPython.core.magic import Magics, magics_class, line_magic
413 from IPython.core.magic import Magics, magics_class, line_magic
414
414
415 @magics_class
415 @magics_class
416 class AutoreloadMagics(Magics):
416 class AutoreloadMagics(Magics):
417 def __init__(self, *a, **kw):
417 def __init__(self, *a, **kw):
418 super(AutoreloadMagics, self).__init__(*a, **kw)
418 super(AutoreloadMagics, self).__init__(*a, **kw)
419 self._reloader = ModuleReloader()
419 self._reloader = ModuleReloader()
420 self._reloader.check_all = False
420 self._reloader.check_all = False
421 self.loaded_modules = set(sys.modules)
421 self.loaded_modules = set(sys.modules)
422
422
423 @line_magic
423 @line_magic
424 def autoreload(self, parameter_s=''):
424 def autoreload(self, parameter_s=''):
425 r"""%autoreload => Reload modules automatically
425 r"""%autoreload => Reload modules automatically
426
426
427 %autoreload
427 %autoreload
428 Reload all modules (except those excluded by %aimport) automatically
428 Reload all modules (except those excluded by %aimport) automatically
429 now.
429 now.
430
430
431 %autoreload 0
431 %autoreload 0
432 Disable automatic reloading.
432 Disable automatic reloading.
433
433
434 %autoreload 1
434 %autoreload 1
435 Reload all modules imported with %aimport every time before executing
435 Reload all modules imported with %aimport every time before executing
436 the Python code typed.
436 the Python code typed.
437
437
438 %autoreload 2
438 %autoreload 2
439 Reload all modules (except those excluded by %aimport) every time
439 Reload all modules (except those excluded by %aimport) every time
440 before executing the Python code typed.
440 before executing the Python code typed.
441
441
442 Reloading Python modules in a reliable way is in general
442 Reloading Python modules in a reliable way is in general
443 difficult, and unexpected things may occur. %autoreload tries to
443 difficult, and unexpected things may occur. %autoreload tries to
444 work around common pitfalls by replacing function code objects and
444 work around common pitfalls by replacing function code objects and
445 parts of classes previously in the module with new versions. This
445 parts of classes previously in the module with new versions. This
446 makes the following things to work:
446 makes the following things to work:
447
447
448 - Functions and classes imported via 'from xxx import foo' are upgraded
448 - Functions and classes imported via 'from xxx import foo' are upgraded
449 to new versions when 'xxx' is reloaded.
449 to new versions when 'xxx' is reloaded.
450
450
451 - Methods and properties of classes are upgraded on reload, so that
451 - Methods and properties of classes are upgraded on reload, so that
452 calling 'c.foo()' on an object 'c' created before the reload causes
452 calling 'c.foo()' on an object 'c' created before the reload causes
453 the new code for 'foo' to be executed.
453 the new code for 'foo' to be executed.
454
454
455 Some of the known remaining caveats are:
455 Some of the known remaining caveats are:
456
456
457 - Replacing code objects does not always succeed: changing a @property
457 - Replacing code objects does not always succeed: changing a @property
458 in a class to an ordinary method or a method to a member variable
458 in a class to an ordinary method or a method to a member variable
459 can cause problems (but in old objects only).
459 can cause problems (but in old objects only).
460
460
461 - Functions that are removed (eg. via monkey-patching) from a module
461 - Functions that are removed (eg. via monkey-patching) from a module
462 before it is reloaded are not upgraded.
462 before it is reloaded are not upgraded.
463
463
464 - C extension modules cannot be reloaded, and so cannot be
464 - C extension modules cannot be reloaded, and so cannot be
465 autoreloaded.
465 autoreloaded.
466
466
467 """
467 """
468 if parameter_s == '':
468 if parameter_s == '':
469 self._reloader.check(True)
469 self._reloader.check(True)
470 elif parameter_s == '0':
470 elif parameter_s == '0':
471 self._reloader.enabled = False
471 self._reloader.enabled = False
472 elif parameter_s == '1':
472 elif parameter_s == '1':
473 self._reloader.check_all = False
473 self._reloader.check_all = False
474 self._reloader.enabled = True
474 self._reloader.enabled = True
475 elif parameter_s == '2':
475 elif parameter_s == '2':
476 self._reloader.check_all = True
476 self._reloader.check_all = True
477 self._reloader.enabled = True
477 self._reloader.enabled = True
478
478
479 @line_magic
479 @line_magic
480 def aimport(self, parameter_s='', stream=None):
480 def aimport(self, parameter_s='', stream=None):
481 """%aimport => Import modules for automatic reloading.
481 """%aimport => Import modules for automatic reloading.
482
482
483 %aimport
483 %aimport
484 List modules to automatically import and not to import.
484 List modules to automatically import and not to import.
485
485
486 %aimport foo
486 %aimport foo
487 Import module 'foo' and mark it to be autoreloaded for %autoreload 1
487 Import module 'foo' and mark it to be autoreloaded for %autoreload 1
488
488
489 %aimport -foo
489 %aimport -foo
490 Mark module 'foo' to not be autoreloaded for %autoreload 1
490 Mark module 'foo' to not be autoreloaded for %autoreload 1
491 """
491 """
492 modname = parameter_s
492 modname = parameter_s
493 if not modname:
493 if not modname:
494 to_reload = sorted(self._reloader.modules.keys())
494 to_reload = sorted(self._reloader.modules.keys())
495 to_skip = sorted(self._reloader.skip_modules.keys())
495 to_skip = sorted(self._reloader.skip_modules.keys())
496 if stream is None:
496 if stream is None:
497 stream = sys.stdout
497 stream = sys.stdout
498 if self._reloader.check_all:
498 if self._reloader.check_all:
499 stream.write("Modules to reload:\nall-except-skipped\n")
499 stream.write("Modules to reload:\nall-except-skipped\n")
500 else:
500 else:
501 stream.write("Modules to reload:\n%s\n" % ' '.join(to_reload))
501 stream.write("Modules to reload:\n%s\n" % ' '.join(to_reload))
502 stream.write("\nModules to skip:\n%s\n" % ' '.join(to_skip))
502 stream.write("\nModules to skip:\n%s\n" % ' '.join(to_skip))
503 elif modname.startswith('-'):
503 elif modname.startswith('-'):
504 modname = modname[1:]
504 modname = modname[1:]
505 self._reloader.mark_module_skipped(modname)
505 self._reloader.mark_module_skipped(modname)
506 else:
506 else:
507 top_module, top_name = self._reloader.aimport_module(modname)
507 top_module, top_name = self._reloader.aimport_module(modname)
508
508
509 # Inject module to user namespace
509 # Inject module to user namespace
510 self.shell.push({top_name: top_module})
510 self.shell.push({top_name: top_module})
511
511
512 def pre_run_cell(self):
512 def pre_run_cell(self):
513 if self._reloader.enabled:
513 if self._reloader.enabled:
514 try:
514 try:
515 self._reloader.check()
515 self._reloader.check()
516 except:
516 except:
517 pass
517 pass
518
518
519 def post_execute_hook(self):
519 def post_execute_hook(self):
520 """Cache the modification times of any modules imported in this execution
520 """Cache the modification times of any modules imported in this execution
521 """
521 """
522 newly_loaded_modules = set(sys.modules) - self.loaded_modules
522 newly_loaded_modules = set(sys.modules) - self.loaded_modules
523 for modname in newly_loaded_modules:
523 for modname in newly_loaded_modules:
524 _, pymtime = self._reloader.filename_and_mtime(sys.modules[modname])
524 _, pymtime = self._reloader.filename_and_mtime(sys.modules[modname])
525 if pymtime is not None:
525 if pymtime is not None:
526 self._reloader.modules_mtimes[modname] = pymtime
526 self._reloader.modules_mtimes[modname] = pymtime
527
527
528 self.loaded_modules.update(newly_loaded_modules)
528 self.loaded_modules.update(newly_loaded_modules)
529
529
530
530
531 def load_ipython_extension(ip):
531 def load_ipython_extension(ip):
532 """Load the extension in IPython."""
532 """Load the extension in IPython."""
533 auto_reload = AutoreloadMagics(ip)
533 auto_reload = AutoreloadMagics(ip)
534 ip.register_magics(auto_reload)
534 ip.register_magics(auto_reload)
535 ip.events.register('pre_run_cell', auto_reload.pre_run_cell)
535 ip.events.register('pre_run_cell', auto_reload.pre_run_cell)
536 ip.events.register('post_execute', auto_reload.post_execute_hook)
536 ip.events.register('post_execute', auto_reload.post_execute_hook)
General Comments 0
You need to be logged in to leave comments. Login now