diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index a1c15bf..decdd07 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -1410,7 +1410,7 @@ class InteractiveShell(SingletonConfigurable): return [self.user_ns, self.user_global_ns, self.user_ns_hidden] + \ [m.__dict__ for m in self._main_mod_cache.values()] - def reset(self, new_session=True): + def reset(self, new_session=True, aggressive=False): """Clear all internal namespaces, and attempt to release references to user objects. @@ -1447,6 +1447,15 @@ class InteractiveShell(SingletonConfigurable): # Restore the user namespaces to minimal usability self.init_user_ns() + if aggressive and not hasattr(self, "_sys_modules_keys"): + print("Cannot restore sys.module, no snapshot") + elif aggressive: + print("culling sys module...") + current_keys = set(sys.modules.keys()) + for k in current_keys - self._sys_modules_keys: + if k.startswith("multiprocessing"): + continue + del sys.modules[k] # Restore the default and user aliases self.alias_manager.clear_aliases() diff --git a/IPython/core/magics/namespace.py b/IPython/core/magics/namespace.py index 0f232a7..2118d8f 100644 --- a/IPython/core/magics/namespace.py +++ b/IPython/core/magics/namespace.py @@ -491,6 +491,10 @@ class NamespaceMagics(Magics): we do a 'hard' reset, giving you a new session and removing all references to objects from the current session. + --aggressive: Try to aggressively remove modules from sys.modules ; this + may allow you to reimport Python modules that have been updated and + pick up changes, but can have unattended consequences. + in : reset input history out : reset output history @@ -533,8 +537,8 @@ class NamespaceMagics(Magics): such as the ipython notebook interface, will reset the namespace without confirmation. """ - opts, args = self.parse_options(parameter_s,'sf', mode='list') - if 'f' in opts: + opts, args = self.parse_options(parameter_s, "sf", "aggressive", mode="list") + if "f" in opts: ans = True else: try: @@ -552,7 +556,7 @@ class NamespaceMagics(Magics): for i in self.who_ls(): del(user_ns[i]) elif len(args) == 0: # Hard reset - self.shell.reset(new_session = False) + self.shell.reset(new_session=False, aggressive=("aggressive" in opts)) # reset in/out/dhist/array: previously extensinions/clearcmd.py ip = self.shell diff --git a/IPython/core/shellapp.py b/IPython/core/shellapp.py index ee65d3a..c442658 100644 --- a/IPython/core/shellapp.py +++ b/IPython/core/shellapp.py @@ -331,6 +331,7 @@ class InteractiveShellApp(Configurable): # flush output, so itwon't be attached to the first cell sys.stdout.flush() sys.stderr.flush() + self.shell._sys_modules_keys = set(sys.modules.keys()) def _run_exec_lines(self): """Run lines of code in IPythonApp.exec_lines in the user's namespace."""