Show More
@@ -130,6 +130,7 b' from imp import reload' | |||
|
130 | 130 | # Autoreload functionality |
|
131 | 131 | #------------------------------------------------------------------------------ |
|
132 | 132 | |
|
133 | ||
|
133 | 134 | class ModuleReloader: |
|
134 | 135 | enabled = False |
|
135 | 136 | """Whether this reloader is enabled""" |
@@ -186,22 +187,22 b' class ModuleReloader:' | |||
|
186 | 187 | self.mark_module_reloadable(module_name) |
|
187 | 188 | |
|
188 | 189 | import_module(module_name) |
|
189 |
top_name = module_name.split( |
|
|
190 | top_name = module_name.split(".")[0] | |
|
190 | 191 | top_module = sys.modules[top_name] |
|
191 | 192 | return top_module, top_name |
|
192 | 193 | |
|
193 | 194 | def filename_and_mtime(self, module): |
|
194 |
if not hasattr(module, |
|
|
195 | if not hasattr(module, "__file__") or module.__file__ is None: | |
|
195 | 196 | return None, None |
|
196 | 197 | |
|
197 |
if getattr(module, |
|
|
198 | if getattr(module, "__name__", None) in [None, "__mp_main__", "__main__"]: | |
|
198 | 199 | # we cannot reload(__main__) or reload(__mp_main__) |
|
199 | 200 | return None, None |
|
200 | 201 | |
|
201 | 202 | filename = module.__file__ |
|
202 | 203 | path, ext = os.path.splitext(filename) |
|
203 | 204 | |
|
204 |
if ext.lower() == |
|
|
205 | if ext.lower() == ".py": | |
|
205 | 206 | py_filename = filename |
|
206 | 207 | else: |
|
207 | 208 | try: |
@@ -259,17 +260,28 b' class ModuleReloader:' | |||
|
259 | 260 | if py_filename in self.failed: |
|
260 | 261 | del self.failed[py_filename] |
|
261 | 262 | except: |
|
262 | print("[autoreload of {} failed: {}]".format( | |
|
263 | modname, traceback.format_exc(10)), file=sys.stderr) | |
|
263 | print( | |
|
264 | "[autoreload of {} failed: {}]".format( | |
|
265 | modname, traceback.format_exc(10) | |
|
266 | ), | |
|
267 | file=sys.stderr, | |
|
268 | ) | |
|
264 | 269 | self.failed[py_filename] = pymtime |
|
265 | 270 | |
|
271 | ||
|
266 | 272 | #------------------------------------------------------------------------------ |
|
267 | 273 | # superreload |
|
268 | 274 | #------------------------------------------------------------------------------ |
|
269 | 275 | |
|
270 | 276 | |
|
271 | func_attrs = ['__code__', '__defaults__', '__doc__', | |
|
272 | '__closure__', '__globals__', '__dict__'] | |
|
277 | func_attrs = [ | |
|
278 | "__code__", | |
|
279 | "__defaults__", | |
|
280 | "__doc__", | |
|
281 | "__closure__", | |
|
282 | "__globals__", | |
|
283 | "__dict__", | |
|
284 | ] | |
|
273 | 285 | |
|
274 | 286 | |
|
275 | 287 | def update_function(old, new): |
@@ -312,7 +324,8 b' def update_class(old, new):' | |||
|
312 | 324 | pass |
|
313 | 325 | continue |
|
314 | 326 | |
|
315 |
if update_generic(old_obj, new_obj): |
|
|
327 | if update_generic(old_obj, new_obj): | |
|
328 | continue | |
|
316 | 329 | |
|
317 | 330 | try: |
|
318 | 331 | setattr(old, key, getattr(new, key)) |
@@ -342,16 +355,18 b' def isinstance2(a, b, typ):' | |||
|
342 | 355 | |
|
343 | 356 | |
|
344 | 357 | UPDATE_RULES = [ |
|
345 | (lambda a, b: isinstance2(a, b, type), | |
|
346 | update_class), | |
|
347 |
(lambda a, b: isinstance2(a, b, |
|
|
348 | update_function), | |
|
349 | (lambda a, b: isinstance2(a, b, property), | |
|
350 | update_property), | |
|
358 | (lambda a, b: isinstance2(a, b, type), update_class), | |
|
359 | (lambda a, b: isinstance2(a, b, types.FunctionType), update_function), | |
|
360 | (lambda a, b: isinstance2(a, b, property), update_property), | |
|
361 | ] | |
|
362 | UPDATE_RULES.extend( | |
|
363 | [ | |
|
364 | ( | |
|
365 | lambda a, b: isinstance2(a, b, types.MethodType), | |
|
366 | lambda a, b: update_function(a.__func__, b.__func__), | |
|
367 | ), | |
|
351 | 368 | ] |
|
352 | UPDATE_RULES.extend([(lambda a, b: isinstance2(a, b, types.MethodType), | |
|
353 | lambda a, b: update_function(a.__func__, b.__func__)), | |
|
354 | ]) | |
|
369 | ) | |
|
355 | 370 | |
|
356 | 371 | |
|
357 | 372 | def update_generic(a, b): |
@@ -365,15 +380,16 b' def update_generic(a, b):' | |||
|
365 | 380 | class StrongRef: |
|
366 | 381 | def __init__(self, obj): |
|
367 | 382 | self.obj = obj |
|
383 | ||
|
368 | 384 | def __call__(self): |
|
369 | 385 | return self.obj |
|
370 | 386 | |
|
371 | 387 | |
|
372 | 388 | def append_obj(module, d, name, obj, autoload=False): |
|
373 |
not_in_mod = not hasattr(obj, |
|
|
389 | not_in_mod = not hasattr(obj, "__module__") or obj.__module__ != module.__name__ | |
|
374 | 390 | if autoload: |
|
375 | 391 | # check needed for module global built-ins (int, str, dict,..) |
|
376 |
if name.startswith( |
|
|
392 | if name.startswith("__") and not_in_mod: | |
|
377 | 393 | return False |
|
378 | 394 | else: |
|
379 | 395 | if not_in_mod: |
@@ -416,8 +432,8 b' def superreload(module, reload=reload, old_objects=None, shell=None):' | |||
|
416 | 432 | old_dict = module.__dict__.copy() |
|
417 | 433 | old_name = module.__name__ |
|
418 | 434 | module.__dict__.clear() |
|
419 |
module.__dict__[ |
|
|
420 |
module.__dict__[ |
|
|
435 | module.__dict__["__name__"] = old_name | |
|
436 | module.__dict__["__loader__"] = old_dict["__loader__"] | |
|
421 | 437 | except (TypeError, AttributeError, KeyError): |
|
422 | 438 | pass |
|
423 | 439 | |
@@ -434,9 +450,9 b' def superreload(module, reload=reload, old_objects=None, shell=None):' | |||
|
434 | 450 | if key not in old_objects: |
|
435 | 451 | # here 'shell' acts both as a flag and as an output var |
|
436 | 452 | if ( |
|
437 |
shell is None |
|
|
438 |
name == |
|
|
439 | not append_obj(module, old_objects, name, new_obj, True) | |
|
453 | shell is None | |
|
454 | or name == "Enum" | |
|
455 | or not append_obj(module, old_objects, name, new_obj, True) | |
|
440 | 456 | ): |
|
441 | 457 | continue |
|
442 | 458 | shell.user_ns[name] = new_obj |
@@ -444,7 +460,8 b' def superreload(module, reload=reload, old_objects=None, shell=None):' | |||
|
444 | 460 | new_refs = [] |
|
445 | 461 | for old_ref in old_objects[key]: |
|
446 | 462 | old_obj = old_ref() |
|
447 |
if old_obj is None: |
|
|
463 | if old_obj is None: | |
|
464 | continue | |
|
448 | 465 | new_refs.append(old_ref) |
|
449 | 466 | update_generic(old_obj, new_obj) |
|
450 | 467 | |
@@ -455,12 +472,14 b' def superreload(module, reload=reload, old_objects=None, shell=None):' | |||
|
455 | 472 | |
|
456 | 473 | return module |
|
457 | 474 | |
|
475 | ||
|
458 | 476 | #------------------------------------------------------------------------------ |
|
459 | 477 | # IPython connectivity |
|
460 | 478 | #------------------------------------------------------------------------------ |
|
461 | 479 | |
|
462 | 480 | from IPython.core.magic import Magics, magics_class, line_magic |
|
463 | 481 | |
|
482 | ||
|
464 | 483 | @magics_class |
|
465 | 484 | class AutoreloadMagics(Magics): |
|
466 | 485 | def __init__(self, *a, **kw): |
@@ -471,7 +490,7 b' class AutoreloadMagics(Magics):' | |||
|
471 | 490 | self.loaded_modules = set(sys.modules) |
|
472 | 491 | |
|
473 | 492 | @line_magic |
|
474 |
def autoreload(self, parameter_s= |
|
|
493 | def autoreload(self, parameter_s=""): | |
|
475 | 494 | r"""%autoreload => Reload modules automatically |
|
476 | 495 | |
|
477 | 496 | %autoreload |
@@ -515,24 +534,24 b' class AutoreloadMagics(Magics):' | |||
|
515 | 534 | autoreloaded. |
|
516 | 535 | |
|
517 | 536 | """ |
|
518 |
if parameter_s == |
|
|
537 | if parameter_s == "": | |
|
519 | 538 | self._reloader.check(True) |
|
520 |
elif parameter_s == |
|
|
539 | elif parameter_s == "0": | |
|
521 | 540 | self._reloader.enabled = False |
|
522 |
elif parameter_s == |
|
|
541 | elif parameter_s == "1": | |
|
523 | 542 | self._reloader.check_all = False |
|
524 | 543 | self._reloader.enabled = True |
|
525 |
elif parameter_s == |
|
|
544 | elif parameter_s == "2": | |
|
526 | 545 | self._reloader.check_all = True |
|
527 | 546 | self._reloader.enabled = True |
|
528 | 547 | self._reloader.enabled = True |
|
529 |
elif parameter_s == |
|
|
548 | elif parameter_s == "3": | |
|
530 | 549 | self._reloader.check_all = True |
|
531 | 550 | self._reloader.enabled = True |
|
532 | 551 | self._reloader.autoload_obj = True |
|
533 | 552 | |
|
534 | 553 | @line_magic |
|
535 |
def aimport(self, parameter_s= |
|
|
554 | def aimport(self, parameter_s="", stream=None): | |
|
536 | 555 | """%aimport => Import modules for automatic reloading. |
|
537 | 556 | |
|
538 | 557 | %aimport |
@@ -556,13 +575,13 b' class AutoreloadMagics(Magics):' | |||
|
556 | 575 | if self._reloader.check_all: |
|
557 | 576 | stream.write("Modules to reload:\nall-except-skipped\n") |
|
558 | 577 | else: |
|
559 |
stream.write("Modules to reload:\n%s\n" % |
|
|
560 |
stream.write("\nModules to skip:\n%s\n" % |
|
|
561 |
elif modname.startswith( |
|
|
578 | stream.write("Modules to reload:\n%s\n" % " ".join(to_reload)) | |
|
579 | stream.write("\nModules to skip:\n%s\n" % " ".join(to_skip)) | |
|
580 | elif modname.startswith("-"): | |
|
562 | 581 | modname = modname[1:] |
|
563 | 582 | self._reloader.mark_module_skipped(modname) |
|
564 | 583 | else: |
|
565 |
for _module in |
|
|
584 | for _module in [_.strip() for _ in modname.split(",")]: | |
|
566 | 585 | top_module, top_name = self._reloader.aimport_module(_module) |
|
567 | 586 | |
|
568 | 587 | # Inject module to user namespace |
@@ -576,8 +595,7 b' class AutoreloadMagics(Magics):' | |||
|
576 | 595 | pass |
|
577 | 596 | |
|
578 | 597 | def post_execute_hook(self): |
|
579 | """Cache the modification times of any modules imported in this execution | |
|
580 | """ | |
|
598 | """Cache the modification times of any modules imported in this execution""" | |
|
581 | 599 | newly_loaded_modules = set(sys.modules) - self.loaded_modules |
|
582 | 600 | for modname in newly_loaded_modules: |
|
583 | 601 | _, pymtime = self._reloader.filename_and_mtime(sys.modules[modname]) |
@@ -591,5 +609,5 b' def load_ipython_extension(ip):' | |||
|
591 | 609 | """Load the extension in IPython.""" |
|
592 | 610 | auto_reload = AutoreloadMagics(ip) |
|
593 | 611 | ip.register_magics(auto_reload) |
|
594 |
ip.events.register( |
|
|
595 |
ip.events.register( |
|
|
612 | ip.events.register("pre_run_cell", auto_reload.pre_run_cell) | |
|
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