Skip to content

Commit

Permalink
Merge pull request #3622 from takluyver/drop-fakemodule
Browse files Browse the repository at this point in the history
Drop fakemodule

After PR #3555, I don't think we have any need for our FakeModule class, so this removes it in favour of just using ModuleType.

There shouldn't be any user-visible benefit, so we could leave this until after release if we're going into stability mode. On the other hand, it changes an (undocumented) API, so we might prefer to do this before 1.0.
  • Loading branch information
minrk committed Sep 18, 2013
2 parents fbb0174 + 3af175d commit 2e41dab
Show file tree
Hide file tree
Showing 9 changed files with 51 additions and 101 deletions.
66 changes: 0 additions & 66 deletions IPython/core/fakemodule.py

This file was deleted.

21 changes: 15 additions & 6 deletions IPython/core/interactiveshell.py
Expand Up @@ -47,7 +47,6 @@
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
Expand Down Expand Up @@ -826,15 +825,18 @@ def register_post_execute(self, func):
# 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
Expand All @@ -847,9 +849,16 @@ def new_main_mod(self, filename):
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

Expand All @@ -863,7 +872,7 @@ def clear_main_mod_cache(self):
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
Expand Down
12 changes: 6 additions & 6 deletions IPython/core/magics/execution.py
Expand Up @@ -550,6 +550,11 @@ def run(self, parameter_s='', runner=None,
__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:
Expand All @@ -560,13 +565,8 @@ def run(self, parameter_s='', runner=None,
# 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
Expand Down
17 changes: 0 additions & 17 deletions IPython/core/tests/test_fakemodule.py

This file was deleted.

3 changes: 0 additions & 3 deletions IPython/core/tests/test_imports.py
Expand Up @@ -9,9 +9,6 @@ def test_import_crashhandler():
def test_import_debugger():
from IPython.core import debugger

def test_import_fakemodule():
from IPython.core import fakemodule

def test_import_excolors():
from IPython.core import excolors

Expand Down
26 changes: 26 additions & 0 deletions IPython/core/tests/test_run.py
Expand Up @@ -15,6 +15,7 @@

import functools
import os
from os.path import join as pjoin
import random
import sys
import tempfile
Expand Down Expand Up @@ -359,6 +360,17 @@ def test_run_formatting(self):
self.mktmp(src)
_ip.magic('run -t -N 1 %s' % self.fname)
_ip.magic('run -t -N 10 %s' % self.fname)

def test_ignore_sys_exit(self):
"""Test the -e option to ignore sys.exit()"""
src = "import sys; sys.exit(1)"
self.mktmp(src)
with tt.AssertPrints('SystemExit'):
_ip.magic('run %s' % self.fname)

with tt.AssertNotPrints('SystemExit'):
_ip.magic('run -e %s' % self.fname)



class TestMagicRunWithPackage(unittest.TestCase):
Expand Down Expand Up @@ -398,6 +410,7 @@ def tearDown(self):
self.tempdir.cleanup()

def check_run_submodule(self, submodule, opts=''):
_ip.user_ns.pop('x', None)
_ip.magic('run {2} -m {0}.{1}'.format(self.package, submodule, opts))
self.assertEqual(_ip.user_ns['x'], self.value,
'Variable `x` is not loaded from module `{0}`.'
Expand Down Expand Up @@ -430,3 +443,16 @@ def test_debug_run_submodule_with_absolute_import(self):
@with_fake_debugger
def test_debug_run_submodule_with_relative_import(self):
self.check_run_submodule('relative', '-d')

def test_run__name__():
with TemporaryDirectory() as td:
path = pjoin(td, 'foo.py')
with open(path, 'w') as f:
f.write("q = __name__")

_ip.user_ns.pop('q', None)
_ip.magic('run {}'.format(path))
nt.assert_equal(_ip.user_ns.pop('q'), '__main__')

_ip.magic('run -n {}'.format(path))
nt.assert_equal(_ip.user_ns.pop('q'), 'foo')
4 changes: 2 additions & 2 deletions IPython/extensions/storemagic.py
Expand Up @@ -27,7 +27,6 @@
# Our own
from IPython.config.configurable import Configurable
from IPython.core.error import UsageError
from IPython.core.fakemodule import FakeModule
from IPython.core.magic import Magics, magics_class, line_magic
from IPython.testing.skipdoctest import skip_doctest
from IPython.utils.traitlets import Bool
Expand Down Expand Up @@ -224,7 +223,8 @@ def store(self, parameter_s=''):
raise UsageError("Unknown variable '%s'" % args[0])

else:
if isinstance(inspect.getmodule(obj), FakeModule):
modname = getattr(inspect.getmodule(obj), '__name__', '')
if modname == '__main__':
print textwrap.dedent("""\
Warning:%s is %s
Proper storage of interactively declared classes (or instances
Expand Down
2 changes: 1 addition & 1 deletion docs/autogen_api.py
Expand Up @@ -35,7 +35,7 @@
r'\.zmq',
]

docwriter.module_skip_patterns += [ r'\.core\.fakemodule',
docwriter.module_skip_patterns += [
r'\.testing\.iptest',
# Keeping these disabled is OK
r'\.parallel\.controller\.mongodb',
Expand Down
1 change: 1 addition & 0 deletions docs/source/whatsnew/pr/incompat-drop-fakemodule.rst
@@ -0,0 +1 @@
* The module ``IPython.core.fakemodule`` has been removed.

0 comments on commit 2e41dab

Please sign in to comment.