From 0e4733cdb0c7805be6dcdab7039cd909db48d68a 2011-08-30 12:49:21 From: Pauli Virtanen Date: 2011-08-30 12:49:21 Subject: [PATCH] ENH: extensions: port autoreload to current API --- diff --git a/IPython/quarantine/ipy_autoreload.py b/IPython/extensions/autoreload.py similarity index 84% rename from IPython/quarantine/ipy_autoreload.py rename to IPython/extensions/autoreload.py index 3976551..111c2b2 100644 --- a/IPython/quarantine/ipy_autoreload.py +++ b/IPython/extensions/autoreload.py @@ -219,132 +219,140 @@ def superreload(module, reload=reload, old_objects={}): return module -reloader = ModuleReloader() - #------------------------------------------------------------------------------ # IPython connectivity #------------------------------------------------------------------------------ -from IPython.core import ipapi -from IPython.core.error import TryNext - -ip = ipapi.get() - -autoreload_enabled = False - -def runcode_hook(self): - if not autoreload_enabled: - raise TryNext - try: - reloader.check() - except: - pass - -def enable_autoreload(): - global autoreload_enabled - autoreload_enabled = True - -def disable_autoreload(): - global autoreload_enabled - autoreload_enabled = False - -def autoreload_f(self, parameter_s=''): - r""" %autoreload => Reload modules automatically - - %autoreload - Reload all modules (except those excluded by %aimport) automatically now. - - %autoreload 0 - Disable automatic reloading. - - %autoreload 1 - Reload all modules imported with %aimport every time before executing - the Python code typed. - - %autoreload 2 - Reload all modules (except those excluded by %aimport) every time - before executing the Python code typed. - - Reloading Python modules in a reliable way is in general - difficult, and unexpected things may occur. %autoreload tries to - work around common pitfalls by replacing function code objects and - parts of classes previously in the module with new versions. This - makes the following things to work: - - Functions and classes imported via 'from xxx import foo' are upgraded - to new versions when 'xxx' is reloaded. +from IPython.core.plugin import Plugin +from IPython.core.hooks import TryNext - - Methods and properties of classes are upgraded on reload, so that - calling 'c.foo()' on an object 'c' created before the reload causes - the new code for 'foo' to be executed. +class Autoreload(Plugin): + def __init__(self, shell=None, config=None): + super(Autoreload, self).__init__(shell=shell, config=config) - Some of the known remaining caveats are: + self.shell.define_magic('autoreload', self.magic_autoreload) + self.shell.define_magic('aimport', self.magic_aimport) + self.shell.set_hook('pre_run_code_hook', self.pre_run_code_hook) - - Replacing code objects does not always succeed: changing a @property - in a class to an ordinary method or a method to a member variable - can cause problems (but in old objects only). + self._enabled = False + self._reloader = ModuleReloader() + self._reloader.check_all = False - - Functions that are removed (eg. via monkey-patching) from a module - before it is reloaded are not upgraded. - - - C extension modules cannot be reloaded, and so cannot be - autoreloaded. - - """ - if parameter_s == '': - reloader.check(True) - elif parameter_s == '0': - disable_autoreload() - elif parameter_s == '1': - reloader.check_all = False - enable_autoreload() - elif parameter_s == '2': - reloader.check_all = True - enable_autoreload() - -def aimport_f(self, parameter_s=''): - """%aimport => Import modules for automatic reloading. + def pre_run_code_hook(self, ipself): + if not self._enabled: + raise TryNext + try: + self._reloader.check() + except: + pass - %aimport - List modules to automatically import and not to import. + def magic_autoreload(self, ipself, parameter_s=''): + r"""%autoreload => Reload modules automatically + + %autoreload + Reload all modules (except those excluded by %aimport) automatically + now. + + %autoreload 0 + Disable automatic reloading. + + %autoreload 1 + Reload all modules imported with %aimport every time before executing + the Python code typed. + + %autoreload 2 + Reload all modules (except those excluded by %aimport) every time + before executing the Python code typed. + + Reloading Python modules in a reliable way is in general + difficult, and unexpected things may occur. %autoreload tries to + work around common pitfalls by replacing function code objects and + parts of classes previously in the module with new versions. This + makes the following things to work: + + - Functions and classes imported via 'from xxx import foo' are upgraded + to new versions when 'xxx' is reloaded. + + - Methods and properties of classes are upgraded on reload, so that + calling 'c.foo()' on an object 'c' created before the reload causes + the new code for 'foo' to be executed. + + Some of the known remaining caveats are: + + - Replacing code objects does not always succeed: changing a @property + in a class to an ordinary method or a method to a member variable + can cause problems (but in old objects only). + + - Functions that are removed (eg. via monkey-patching) from a module + before it is reloaded are not upgraded. + + - C extension modules cannot be reloaded, and so cannot be + autoreloaded. + + """ + if parameter_s == '': + self._reloader.check(True) + elif parameter_s == '0': + self._enabled = False + elif parameter_s == '1': + self._reloader.check_all = False + self._enabled = True + elif parameter_s == '2': + self._reloader.check_all = True + self._enabled = True + + def magic_aimport(self, ipself, parameter_s=''): + """%aimport => Import modules for automatic reloading. + + %aimport + List modules to automatically import and not to import. + + %aimport foo + Import module 'foo' and mark it to be autoreloaded for %autoreload 1 + + %aimport -foo + Mark module 'foo' to not be autoreloaded for %autoreload 1 + + """ + + modname = parameter_s + if not modname: + to_reload = self._reloader.modules.keys() + to_reload.sort() + to_skip = self._reloader.skip_modules.keys() + to_skip.sort() + if self._reloader.check_all: + print "Modules to reload:\nall-expect-skipped" + else: + print "Modules to reload:\n%s" % ' '.join(to_reload) + print "\nModules to skip:\n%s" % ' '.join(to_skip) + elif modname.startswith('-'): + modname = modname[1:] + try: + del self._reloader.modules[modname] + except KeyError: + pass + self._reloader.skip_modules[modname] = True + else: + try: + del self._reloader.skip_modules[modname] + except KeyError: + pass + self._reloader.modules[modname] = True - %aimport foo - Import module 'foo' and mark it to be autoreloaded for %autoreload 1 + # Inject module to user namespace; handle also submodules properly + __import__(modname) + basename = modname.split('.')[0] + mod = sys.modules[basename] + ipself.push({basename: mod}) - %aimport -foo - Mark module 'foo' to not be autoreloaded for %autoreload 1 - """ +_loaded = False - modname = parameter_s - if not modname: - to_reload = reloader.modules.keys() - to_reload.sort() - to_skip = reloader.skip_modules.keys() - to_skip.sort() - if reloader.check_all: - print "Modules to reload:\nall-expect-skipped" - else: - print "Modules to reload:\n%s" % ' '.join(to_reload) - print "\nModules to skip:\n%s" % ' '.join(to_skip) - elif modname.startswith('-'): - modname = modname[1:] - try: del reloader.modules[modname] - except KeyError: pass - reloader.skip_modules[modname] = True - else: - try: del reloader.skip_modules[modname] - except KeyError: pass - reloader.modules[modname] = True - - # Inject module to user namespace; handle also submodules properly - __import__(modname) - basename = modname.split('.')[0] - mod = sys.modules[basename] - ip.push({basename: mod}) - -def init(): - ip.define_magic('autoreload', autoreload_f) - ip.define_magic('aimport', aimport_f) - ip.set_hook('pre_runcode_hook', runcode_hook) - -init() +def load_ipython_extension(ip): + """Load the extension in IPython.""" + global _loaded + if not _loaded: + plugin = Autoreload(shell=ip, config=ip.config) + ip.plugin_manager.register_plugin('autoreload', plugin) + _loaded = True