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