From 6a14ef398a8dac02d3ade3eb7b282e60390ea4b3 2013-09-18 16:24:48 From: Thomas Kluyver Date: 2013-09-18 16:24:48 Subject: [PATCH] Replace FakeModule with ModuleType in InteractiveShell --- diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 9aea028..5a9cc38 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -47,7 +47,6 @@ from IPython.core.displayhook import DisplayHook from IPython.core.displaypub import DisplayPublisher from IPython.core.error import UsageError from IPython.core.extensions import ExtensionManager -from IPython.core.fakemodule import FakeModule, init_fakemod_dict from IPython.core.formatters import DisplayFormatter from IPython.core.history import HistoryManager from IPython.core.inputsplitter import IPythonInputSplitter, ESC_MAGIC, ESC_MAGIC2 @@ -826,15 +825,18 @@ class InteractiveShell(SingletonConfigurable): # Things related to the "main" module #------------------------------------------------------------------------- - def new_main_mod(self, filename): + def new_main_mod(self, filename, modname): """Return a new 'main' module object for user code execution. ``filename`` should be the path of the script which will be run in the module. Requests with the same filename will get the same module, with its namespace cleared. + ``modname`` should be the module name - normally either '__main__' or + the basename of the file without the extension. + When scripts are executed via %run, we must keep a reference to their - __main__ module (a FakeModule instance) around so that Python doesn't + __main__ module around so that Python doesn't clear it, rendering references to module globals useless. This method keeps said reference in a private dict, keyed by the @@ -847,9 +849,16 @@ class InteractiveShell(SingletonConfigurable): try: main_mod = self._main_mod_cache[filename] except KeyError: - main_mod = self._main_mod_cache[filename] = FakeModule() + main_mod = self._main_mod_cache[filename] = types.ModuleType(modname, + doc="Module created for script run in IPython") else: - init_fakemod_dict(main_mod) + main_mod.__dict__.clear() + main_mod.__name__ = modname + + main_mod.__file__ = filename + # It seems pydoc (and perhaps others) needs any module instance to + # implement a __nonzero__ method + main_mod.__nonzero__ = lambda : True return main_mod @@ -863,7 +872,7 @@ class InteractiveShell(SingletonConfigurable): In [15]: import IPython - In [16]: m = _ip.new_main_mod(IPython.__file__) + In [16]: m = _ip.new_main_mod(IPython.__file__, 'IPython') In [17]: len(_ip._main_mod_cache) > 0 Out[17]: True diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py index e01c978..28a6c69 100644 --- a/IPython/core/magics/execution.py +++ b/IPython/core/magics/execution.py @@ -550,6 +550,11 @@ python-profiler package from non-free.""") __name__save = self.shell.user_ns['__name__'] prog_ns['__name__'] = '__main__' main_mod = self.shell.user_module + + # Since '%run foo' emulates 'python foo.py' at the cmd line, we must + # set the __file__ global in the script's namespace + # TK: Is this necessary in interactive mode? + prog_ns['__file__'] = filename else: # Run in a fresh, empty namespace if 'n' in opts: @@ -560,13 +565,8 @@ python-profiler package from non-free.""") # The shell MUST hold a reference to prog_ns so after %run # exits, the python deletion mechanism doesn't zero it out # (leaving dangling references). See interactiveshell for details - main_mod = self.shell.new_main_mod(filename) + main_mod = self.shell.new_main_mod(filename, name) prog_ns = main_mod.__dict__ - prog_ns['__name__'] = name - - # Since '%run foo' emulates 'python foo.py' at the cmd line, we must - # set the __file__ global in the script's namespace - prog_ns['__file__'] = filename # pickle fix. See interactiveshell for an explanation. But we need to # make sure that, if we overwrite __main__, we replace it at the end