autoreload.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  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``
  20. Reload all modules (except those excluded by ``%aimport``)
  21. automatically now.
  22. ``%autoreload 0``
  23. Disable automatic reloading.
  24. ``%autoreload 1``
  25. Reload all modules imported with ``%aimport`` every time before
  26. executing the Python code typed.
  27. ``%autoreload 2``
  28. Reload all modules (except those excluded by ``%aimport``) every
  29. time before executing the Python code typed.
  30. ``%aimport``
  31. List modules which are to be automatically imported or not to be imported.
  32. ``%aimport foo``
  33. Import module 'foo' and mark it to be autoreloaded for ``%autoreload 1``
  34. ``%aimport foo, bar``
  35. Import modules 'foo', 'bar' and mark them to be autoreloaded for ``%autoreload 1``
  36. ``%aimport -foo``
  37. Mark module 'foo' to not be autoreloaded.
  38. Caveats
  39. =======
  40. Reloading Python modules in a reliable way is in general difficult,
  41. and unexpected things may occur. ``%autoreload`` tries to work around
  42. common pitfalls by replacing function code objects and parts of
  43. classes previously in the module with new versions. This makes the
  44. following things to work:
  45. - Functions and classes imported via 'from xxx import foo' are upgraded
  46. to new versions when 'xxx' is reloaded.
  47. - Methods and properties of classes are upgraded on reload, so that
  48. calling 'c.foo()' on an object 'c' created before the reload causes
  49. the new code for 'foo' to be executed.
  50. Some of the known remaining caveats are:
  51. - Replacing code objects does not always succeed: changing a @property
  52. in a class to an ordinary method or a method to a member variable
  53. can cause problems (but in old objects only).
  54. - Functions that are removed (eg. via monkey-patching) from a module
  55. before it is reloaded are not upgraded.
  56. - C extension modules cannot be reloaded, and so cannot be autoreloaded.
  57. """
  58. skip_doctest = True
  59. #-----------------------------------------------------------------------------
  60. # Copyright (C) 2000 Thomas Heller
  61. # Copyright (C) 2008 Pauli Virtanen <pav@iki.fi>
  62. # Copyright (C) 2012 The IPython Development Team
  63. #
  64. # Distributed under the terms of the BSD License. The full license is in
  65. # the file COPYING, distributed as part of this software.
  66. #-----------------------------------------------------------------------------
  67. #
  68. # This IPython module is written by Pauli Virtanen, based on the autoreload
  69. # code by Thomas Heller.
  70. #-----------------------------------------------------------------------------
  71. # Imports
  72. #-----------------------------------------------------------------------------
  73. import os
  74. import sys
  75. import traceback
  76. import types
  77. import weakref
  78. import gc
  79. from importlib import import_module
  80. from importlib.util import source_from_cache
  81. from imp import reload
  82. #------------------------------------------------------------------------------
  83. # Autoreload functionality
  84. #------------------------------------------------------------------------------
  85. class ModuleReloader(object):
  86. enabled = False
  87. """Whether this reloader is enabled"""
  88. check_all = True
  89. """Autoreload all modules, not just those listed in 'modules'"""
  90. def __init__(self):
  91. # Modules that failed to reload: {module: mtime-on-failed-reload, ...}
  92. self.failed = {}
  93. # Modules specially marked as autoreloadable.
  94. self.modules = {}
  95. # Modules specially marked as not autoreloadable.
  96. self.skip_modules = {}
  97. # (module-name, name) -> weakref, for replacing old code objects
  98. self.old_objects = {}
  99. # Module modification timestamps
  100. self.modules_mtimes = {}
  101. # Cache module modification times
  102. self.check(check_all=True, do_reload=False)
  103. def mark_module_skipped(self, module_name):
  104. """Skip reloading the named module in the future"""
  105. try:
  106. del self.modules[module_name]
  107. except KeyError:
  108. pass
  109. self.skip_modules[module_name] = True
  110. def mark_module_reloadable(self, module_name):
  111. """Reload the named module in the future (if it is imported)"""
  112. try:
  113. del self.skip_modules[module_name]
  114. except KeyError:
  115. pass
  116. self.modules[module_name] = True
  117. def aimport_module(self, module_name):
  118. """Import a module, and mark it reloadable
  119. Returns
  120. -------
  121. top_module : module
  122. The imported module if it is top-level, or the top-level
  123. top_name : module
  124. Name of top_module
  125. """
  126. self.mark_module_reloadable(module_name)
  127. import_module(module_name)
  128. top_name = module_name.split('.')[0]
  129. top_module = sys.modules[top_name]
  130. return top_module, top_name
  131. def filename_and_mtime(self, module):
  132. if not hasattr(module, '__file__') or module.__file__ is None:
  133. return None, None
  134. if getattr(module, '__name__', None) in [None, '__mp_main__', '__main__']:
  135. # we cannot reload(__main__) or reload(__mp_main__)
  136. return None, None
  137. filename = module.__file__
  138. path, ext = os.path.splitext(filename)
  139. if ext.lower() == '.py':
  140. py_filename = filename
  141. else:
  142. try:
  143. py_filename = source_from_cache(filename)
  144. except ValueError:
  145. return None, None
  146. try:
  147. pymtime = os.stat(py_filename).st_mtime
  148. except OSError:
  149. return None, None
  150. return py_filename, pymtime
  151. def check(self, check_all=False, do_reload=True):
  152. """Check whether some modules need to be reloaded."""
  153. if not self.enabled and not check_all:
  154. return
  155. if check_all or self.check_all:
  156. modules = list(sys.modules.keys())
  157. else:
  158. modules = list(self.modules.keys())
  159. for modname in modules:
  160. m = sys.modules.get(modname, None)
  161. if modname in self.skip_modules:
  162. continue
  163. py_filename, pymtime = self.filename_and_mtime(m)
  164. if py_filename is None:
  165. continue
  166. try:
  167. if pymtime <= self.modules_mtimes[modname]:
  168. continue
  169. except KeyError:
  170. self.modules_mtimes[modname] = pymtime
  171. continue
  172. else:
  173. if self.failed.get(py_filename, None) == pymtime:
  174. continue
  175. self.modules_mtimes[modname] = pymtime
  176. # If we've reached this point, we should try to reload the module
  177. if do_reload:
  178. try:
  179. superreload(m, reload, self.old_objects)
  180. if py_filename in self.failed:
  181. del self.failed[py_filename]
  182. except:
  183. print("[autoreload of %s failed: %s]" % (
  184. modname, traceback.format_exc(10)), file=sys.stderr)
  185. self.failed[py_filename] = pymtime
  186. #------------------------------------------------------------------------------
  187. # superreload
  188. #------------------------------------------------------------------------------
  189. func_attrs = ['__code__', '__defaults__', '__doc__',
  190. '__closure__', '__globals__', '__dict__']
  191. def update_function(old, new):
  192. """Upgrade the code object of a function"""
  193. for name in func_attrs:
  194. try:
  195. setattr(old, name, getattr(new, name))
  196. except (AttributeError, TypeError):
  197. pass
  198. def update_instances(old, new):
  199. """Use garbage collector to find all instances that refer to the old
  200. class definition and update their __class__ to point to the new class
  201. definition"""
  202. refs = gc.get_referrers(old)
  203. for ref in refs:
  204. if type(ref) is old:
  205. ref.__class__ = new
  206. def update_class(old, new):
  207. """Replace stuff in the __dict__ of a class, and upgrade
  208. method code objects, and add new methods, if any"""
  209. for key in list(old.__dict__.keys()):
  210. old_obj = getattr(old, key)
  211. try:
  212. new_obj = getattr(new, key)
  213. # explicitly checking that comparison returns True to handle
  214. # cases where `==` doesn't return a boolean.
  215. if (old_obj == new_obj) is True:
  216. continue
  217. except AttributeError:
  218. # obsolete attribute: remove it
  219. try:
  220. delattr(old, key)
  221. except (AttributeError, TypeError):
  222. pass
  223. continue
  224. if update_generic(old_obj, new_obj): continue
  225. try:
  226. setattr(old, key, getattr(new, key))
  227. except (AttributeError, TypeError):
  228. pass # skip non-writable attributes
  229. for key in list(new.__dict__.keys()):
  230. if key not in list(old.__dict__.keys()):
  231. try:
  232. setattr(old, key, getattr(new, key))
  233. except (AttributeError, TypeError):
  234. pass # skip non-writable attributes
  235. # update all instances of class
  236. update_instances(old, new)
  237. def update_property(old, new):
  238. """Replace get/set/del functions of a property"""
  239. update_generic(old.fdel, new.fdel)
  240. update_generic(old.fget, new.fget)
  241. update_generic(old.fset, new.fset)
  242. def isinstance2(a, b, typ):
  243. return isinstance(a, typ) and isinstance(b, typ)
  244. UPDATE_RULES = [
  245. (lambda a, b: isinstance2(a, b, type),
  246. update_class),
  247. (lambda a, b: isinstance2(a, b, types.FunctionType),
  248. update_function),
  249. (lambda a, b: isinstance2(a, b, property),
  250. update_property),
  251. ]
  252. UPDATE_RULES.extend([(lambda a, b: isinstance2(a, b, types.MethodType),
  253. lambda a, b: update_function(a.__func__, b.__func__)),
  254. ])
  255. def update_generic(a, b):
  256. for type_check, update in UPDATE_RULES:
  257. if type_check(a, b):
  258. update(a, b)
  259. return True
  260. return False
  261. class StrongRef(object):
  262. def __init__(self, obj):
  263. self.obj = obj
  264. def __call__(self):
  265. return self.obj
  266. def superreload(module, reload=reload, old_objects=None):
  267. """Enhanced version of the builtin reload function.
  268. superreload remembers objects previously in the module, and
  269. - upgrades the class dictionary of every old class in the module
  270. - upgrades the code object of every old function and method
  271. - clears the module's namespace before reloading
  272. """
  273. if old_objects is None:
  274. old_objects = {}
  275. # collect old objects in the module
  276. for name, obj in list(module.__dict__.items()):
  277. if not hasattr(obj, '__module__') or obj.__module__ != module.__name__:
  278. continue
  279. key = (module.__name__, name)
  280. try:
  281. old_objects.setdefault(key, []).append(weakref.ref(obj))
  282. except TypeError:
  283. pass
  284. # reload module
  285. try:
  286. # clear namespace first from old cruft
  287. old_dict = module.__dict__.copy()
  288. old_name = module.__name__
  289. module.__dict__.clear()
  290. module.__dict__['__name__'] = old_name
  291. module.__dict__['__loader__'] = old_dict['__loader__']
  292. except (TypeError, AttributeError, KeyError):
  293. pass
  294. try:
  295. module = reload(module)
  296. except:
  297. # restore module dictionary on failed reload
  298. module.__dict__.update(old_dict)
  299. raise
  300. # iterate over all objects and update functions & classes
  301. for name, new_obj in list(module.__dict__.items()):
  302. key = (module.__name__, name)
  303. if key not in old_objects: continue
  304. new_refs = []
  305. for old_ref in old_objects[key]:
  306. old_obj = old_ref()
  307. if old_obj is None: continue
  308. new_refs.append(old_ref)
  309. update_generic(old_obj, new_obj)
  310. if new_refs:
  311. old_objects[key] = new_refs
  312. else:
  313. del old_objects[key]
  314. return module
  315. #------------------------------------------------------------------------------
  316. # IPython connectivity
  317. #------------------------------------------------------------------------------
  318. from IPython.core.magic import Magics, magics_class, line_magic
  319. @magics_class
  320. class AutoreloadMagics(Magics):
  321. def __init__(self, *a, **kw):
  322. super(AutoreloadMagics, self).__init__(*a, **kw)
  323. self._reloader = ModuleReloader()
  324. self._reloader.check_all = False
  325. self.loaded_modules = set(sys.modules)
  326. @line_magic
  327. def autoreload(self, parameter_s=''):
  328. r"""%autoreload => Reload modules automatically
  329. %autoreload
  330. Reload all modules (except those excluded by %aimport) automatically
  331. now.
  332. %autoreload 0
  333. Disable automatic reloading.
  334. %autoreload 1
  335. Reload all modules imported with %aimport every time before executing
  336. the Python code typed.
  337. %autoreload 2
  338. Reload all modules (except those excluded by %aimport) every time
  339. before executing the Python code typed.
  340. Reloading Python modules in a reliable way is in general
  341. difficult, and unexpected things may occur. %autoreload tries to
  342. work around common pitfalls by replacing function code objects and
  343. parts of classes previously in the module with new versions. This
  344. makes the following things to work:
  345. - Functions and classes imported via 'from xxx import foo' are upgraded
  346. to new versions when 'xxx' is reloaded.
  347. - Methods and properties of classes are upgraded on reload, so that
  348. calling 'c.foo()' on an object 'c' created before the reload causes
  349. the new code for 'foo' to be executed.
  350. Some of the known remaining caveats are:
  351. - Replacing code objects does not always succeed: changing a @property
  352. in a class to an ordinary method or a method to a member variable
  353. can cause problems (but in old objects only).
  354. - Functions that are removed (eg. via monkey-patching) from a module
  355. before it is reloaded are not upgraded.
  356. - C extension modules cannot be reloaded, and so cannot be
  357. autoreloaded.
  358. """
  359. if parameter_s == '':
  360. self._reloader.check(True)
  361. elif parameter_s == '0':
  362. self._reloader.enabled = False
  363. elif parameter_s == '1':
  364. self._reloader.check_all = False
  365. self._reloader.enabled = True
  366. elif parameter_s == '2':
  367. self._reloader.check_all = True
  368. self._reloader.enabled = True
  369. @line_magic
  370. def aimport(self, parameter_s='', stream=None):
  371. """%aimport => Import modules for automatic reloading.
  372. %aimport
  373. List modules to automatically import and not to import.
  374. %aimport foo
  375. Import module 'foo' and mark it to be autoreloaded for %autoreload 1
  376. %aimport foo, bar
  377. Import modules 'foo', 'bar' and mark them to be autoreloaded for %autoreload 1
  378. %aimport -foo
  379. Mark module 'foo' to not be autoreloaded for %autoreload 1
  380. """
  381. modname = parameter_s
  382. if not modname:
  383. to_reload = sorted(self._reloader.modules.keys())
  384. to_skip = sorted(self._reloader.skip_modules.keys())
  385. if stream is None:
  386. stream = sys.stdout
  387. if self._reloader.check_all:
  388. stream.write("Modules to reload:\nall-except-skipped\n")
  389. else:
  390. stream.write("Modules to reload:\n%s\n" % ' '.join(to_reload))
  391. stream.write("\nModules to skip:\n%s\n" % ' '.join(to_skip))
  392. elif modname.startswith('-'):
  393. modname = modname[1:]
  394. self._reloader.mark_module_skipped(modname)
  395. else:
  396. for _module in ([_.strip() for _ in modname.split(',')]):
  397. top_module, top_name = self._reloader.aimport_module(_module)
  398. # Inject module to user namespace
  399. self.shell.push({top_name: top_module})
  400. def pre_run_cell(self):
  401. if self._reloader.enabled:
  402. try:
  403. self._reloader.check()
  404. except:
  405. pass
  406. def post_execute_hook(self):
  407. """Cache the modification times of any modules imported in this execution
  408. """
  409. newly_loaded_modules = set(sys.modules) - self.loaded_modules
  410. for modname in newly_loaded_modules:
  411. _, pymtime = self._reloader.filename_and_mtime(sys.modules[modname])
  412. if pymtime is not None:
  413. self._reloader.modules_mtimes[modname] = pymtime
  414. self.loaded_modules.update(newly_loaded_modules)
  415. def load_ipython_extension(ip):
  416. """Load the extension in IPython."""
  417. auto_reload = AutoreloadMagics(ip)
  418. ip.register_magics(auto_reload)
  419. ip.events.register('pre_run_cell', auto_reload.pre_run_cell)
  420. ip.events.register('post_execute', auto_reload.post_execute_hook)