Skip to content

Commit

Permalink
Merge pull request sympy#1205 from mattpap/issue3048
Browse files Browse the repository at this point in the history
Fixed isympy -a and added a test (#3048)
  • Loading branch information
asmeurer committed Apr 6, 2012
2 parents 2ff52fc + 4903deb commit 85c3335
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 29 deletions.
63 changes: 34 additions & 29 deletions sympy/interactive/session.py
Expand Up @@ -68,7 +68,35 @@ def _make_message(ipython=True, quiet=False, source=None):

return message

def _init_ipython_session(argv=[], auto=False):
def enable_automatic_symbols(app):
"""Allow IPython to automatially create symbols (``isympy -a``). """
import re
re_nameerror = re.compile("name '(?P<symbol>[A-Za-z_][A-Za-z0-9_]*)' is not defined")

def _handler(self, etype, value, tb, tb_offset=None):
"""Handle :exc:`NameError` exception and allow injection of missing symbols. """
if etype is NameError and tb.tb_next and not tb.tb_next.tb_next:
match = re_nameerror.match(str(value))

if match is not None:
# XXX: Make sure Symbol is in scope. Otherwise you'll get infinite recursion.
self.run_cell("%(symbol)s = Symbol('%(symbol)s')" %
{'symbol': match.group("symbol")}, store_history=False)

try:
code = self.user_ns['In'][-1]
except (KeyError, IndexError):
pass
else:
self.run_cell(code, store_history=False)
return None

stb = self.InteractiveTB.structured_traceback(etype, value, tb, tb_offset=tb_offset)
self._showtraceback(etype, value, stb)

app.shell.set_custom_exc((NameError,), _handler)

def init_ipython_session(argv=[], auto=False):
"""Construct new IPython session. """
import IPython

Expand All @@ -81,38 +109,15 @@ def _init_ipython_session(argv=[], auto=False):
app.display_banner = False
app.initialize(argv)

import re
re_nameerror = re.compile("name '(?P<symbol>[A-Za-z_][A-Za-z0-9_]*)' is not defined")

def _handler(self, etype, value, tb, tb_offset=None):
"""Handle :exc:`NameError` exception and allow injection of missing symbols. """
if etype is NameError and tb.tb_next and not tb.tb_next.tb_next:
match = re_nameerror.match(str(value))

if match is not None:
self.run_cell("%(symbol)s = Symbol('%(symbol)s')" %
{'symbol': match.group("symbol")}, store_history=False)

try:
code = self.user_ns_hidden['In'][-1]
except (KeyError, IndexError):
pass
else:
self.run_cell(code, store_history=False)
return None

stb = self.InteractiveTB.structured_traceback(etype, value, tb, tb_offset=tb_offset)
self._showtraceback(etype, value, stb)

if auto:
app.shell.set_custom_exc((NameError,), _handler)
enable_automatic_symbols(app)

return app.shell
else:
from IPython.Shell import make_IPython
return make_IPython(argv)

def _init_python_session():
def init_python_session():
"""Construct new Python session. """
from code import InteractiveConsole

Expand Down Expand Up @@ -222,7 +227,7 @@ def init_session(ipython=None, pretty_print=True, order=None,
in_ipython = False

if ipython is False:
ip = _init_python_session()
ip = init_python_session()
mainloop = ip.interact
else:
try:
Expand All @@ -231,7 +236,7 @@ def init_session(ipython=None, pretty_print=True, order=None,
if ipython is not True:
if not quiet:
print no_ipython
ip = _init_python_session()
ip = init_python_session()
mainloop = ip.interact
else:
raise RuntimeError("IPython is not available on this system")
Expand All @@ -251,7 +256,7 @@ def init_session(ipython=None, pretty_print=True, order=None,
if ip is not None:
in_ipython = True
else:
ip = _init_ipython_session(argv=argv, auto=auto)
ip = init_ipython_session(argv=argv, auto=auto)

if IPython.__version__ >= '0.11':
# runsource is gone, use run_cell instead, which doesn't
Expand Down
33 changes: 33 additions & 0 deletions sympy/interactive/tests/test_ipython.py
@@ -0,0 +1,33 @@
"""Tests of tools for setting up interactive IPython sessions. """

from sympy.interactive.session import init_ipython_session, enable_automatic_symbols

from sympy.core import Symbol
from sympy.external import import_module
from sympy.utilities.pytest import raises

# TODO: The code below could be made more granular with something like:
#
# @requires('IPython', version=">=0.11")
# def test_automatic_symbols(ipython):

ipython = import_module("IPython", min_module_version="0.11")

if not ipython:
#bin/test will not execute any tests now
disabled = True

# TODO: Add tests that would verify that enable_automatic_symbols() doesn't
# break anything. For example typing `factorial` or `all` in an interpreter
# shouldn't result in a new symbol.
def test_automatic_symbols():
app = init_ipython_session()
app.run_cell("from sympy import *")

enable_automatic_symbols(app)

symbol = "verylongsymbolname"
assert symbol not in app.user_ns
app.run_cell(symbol, False)
assert symbol in app.user_ns
assert isinstance(app.user_ns[symbol], Symbol)

0 comments on commit 85c3335

Please sign in to comment.