autoreload.py 17 KB

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