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