autoreload.py 23 KB

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