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