I am done

This commit is contained in:
2024-10-30 22:14:35 +01:00
parent 720dc28c09
commit 40e2a747cf
36901 changed files with 5011519 additions and 0 deletions

View File

@ -0,0 +1,8 @@
"""Helper module for setting up interactive SymPy sessions. """
from .printing import init_printing
from .session import init_session
from .traversal import interactive_traversal
__all__ = ['init_printing', 'init_session', 'interactive_traversal']

View File

@ -0,0 +1,562 @@
"""Tools for setting up printing in interactive sessions. """
from sympy.external.importtools import version_tuple
from io import BytesIO
from sympy.printing.latex import latex as default_latex
from sympy.printing.preview import preview
from sympy.utilities.misc import debug
from sympy.printing.defaults import Printable
def _init_python_printing(stringify_func, **settings):
"""Setup printing in Python interactive session. """
import sys
import builtins
def _displayhook(arg):
"""Python's pretty-printer display hook.
This function was adapted from:
https://www.python.org/dev/peps/pep-0217/
"""
if arg is not None:
builtins._ = None
print(stringify_func(arg, **settings))
builtins._ = arg
sys.displayhook = _displayhook
def _init_ipython_printing(ip, stringify_func, use_latex, euler, forecolor,
backcolor, fontsize, latex_mode, print_builtin,
latex_printer, scale, **settings):
"""Setup printing in IPython interactive session. """
try:
from IPython.lib.latextools import latex_to_png
except ImportError:
pass
# Guess best font color if none was given based on the ip.colors string.
# From the IPython documentation:
# It has four case-insensitive values: 'nocolor', 'neutral', 'linux',
# 'lightbg'. The default is neutral, which should be legible on either
# dark or light terminal backgrounds. linux is optimised for dark
# backgrounds and lightbg for light ones.
if forecolor is None:
color = ip.colors.lower()
if color == 'lightbg':
forecolor = 'Black'
elif color == 'linux':
forecolor = 'White'
else:
# No idea, go with gray.
forecolor = 'Gray'
debug("init_printing: Automatic foreground color:", forecolor)
if use_latex == "svg":
extra_preamble = "\n\\special{color %s}" % forecolor
else:
extra_preamble = ""
imagesize = 'tight'
offset = "0cm,0cm"
resolution = round(150*scale)
dvi = r"-T %s -D %d -bg %s -fg %s -O %s" % (
imagesize, resolution, backcolor, forecolor, offset)
dvioptions = dvi.split()
svg_scale = 150/72*scale
dvioptions_svg = ["--no-fonts", "--scale={}".format(svg_scale)]
debug("init_printing: DVIOPTIONS:", dvioptions)
debug("init_printing: DVIOPTIONS_SVG:", dvioptions_svg)
latex = latex_printer or default_latex
def _print_plain(arg, p, cycle):
"""caller for pretty, for use in IPython 0.11"""
if _can_print(arg):
p.text(stringify_func(arg))
else:
p.text(IPython.lib.pretty.pretty(arg))
def _preview_wrapper(o):
exprbuffer = BytesIO()
try:
preview(o, output='png', viewer='BytesIO', euler=euler,
outputbuffer=exprbuffer, extra_preamble=extra_preamble,
dvioptions=dvioptions, fontsize=fontsize)
except Exception as e:
# IPython swallows exceptions
debug("png printing:", "_preview_wrapper exception raised:",
repr(e))
raise
return exprbuffer.getvalue()
def _svg_wrapper(o):
exprbuffer = BytesIO()
try:
preview(o, output='svg', viewer='BytesIO', euler=euler,
outputbuffer=exprbuffer, extra_preamble=extra_preamble,
dvioptions=dvioptions_svg, fontsize=fontsize)
except Exception as e:
# IPython swallows exceptions
debug("svg printing:", "_preview_wrapper exception raised:",
repr(e))
raise
return exprbuffer.getvalue().decode('utf-8')
def _matplotlib_wrapper(o):
# mathtext can't render some LaTeX commands. For example, it can't
# render any LaTeX environments such as array or matrix. So here we
# ensure that if mathtext fails to render, we return None.
try:
try:
return latex_to_png(o, color=forecolor, scale=scale)
except TypeError: # Old IPython version without color and scale
return latex_to_png(o)
except ValueError as e:
debug('matplotlib exception caught:', repr(e))
return None
# Hook methods for builtin SymPy printers
printing_hooks = ('_latex', '_sympystr', '_pretty', '_sympyrepr')
def _can_print(o):
"""Return True if type o can be printed with one of the SymPy printers.
If o is a container type, this is True if and only if every element of
o can be printed in this way.
"""
try:
# If you're adding another type, make sure you add it to printable_types
# later in this file as well
builtin_types = (list, tuple, set, frozenset)
if isinstance(o, builtin_types):
# If the object is a custom subclass with a custom str or
# repr, use that instead.
if (type(o).__str__ not in (i.__str__ for i in builtin_types) or
type(o).__repr__ not in (i.__repr__ for i in builtin_types)):
return False
return all(_can_print(i) for i in o)
elif isinstance(o, dict):
return all(_can_print(i) and _can_print(o[i]) for i in o)
elif isinstance(o, bool):
return False
elif isinstance(o, Printable):
# types known to SymPy
return True
elif any(hasattr(o, hook) for hook in printing_hooks):
# types which add support themselves
return True
elif isinstance(o, (float, int)) and print_builtin:
return True
return False
except RuntimeError:
return False
# This is in case maximum recursion depth is reached.
# Since RecursionError is for versions of Python 3.5+
# so this is to guard against RecursionError for older versions.
def _print_latex_png(o):
"""
A function that returns a png rendered by an external latex
distribution, falling back to matplotlib rendering
"""
if _can_print(o):
s = latex(o, mode=latex_mode, **settings)
if latex_mode == 'plain':
s = '$\\displaystyle %s$' % s
try:
return _preview_wrapper(s)
except RuntimeError as e:
debug('preview failed with:', repr(e),
' Falling back to matplotlib backend')
if latex_mode != 'inline':
s = latex(o, mode='inline', **settings)
return _matplotlib_wrapper(s)
def _print_latex_svg(o):
"""
A function that returns a svg rendered by an external latex
distribution, no fallback available.
"""
if _can_print(o):
s = latex(o, mode=latex_mode, **settings)
if latex_mode == 'plain':
s = '$\\displaystyle %s$' % s
try:
return _svg_wrapper(s)
except RuntimeError as e:
debug('preview failed with:', repr(e),
' No fallback available.')
def _print_latex_matplotlib(o):
"""
A function that returns a png rendered by mathtext
"""
if _can_print(o):
s = latex(o, mode='inline', **settings)
return _matplotlib_wrapper(s)
def _print_latex_text(o):
"""
A function to generate the latex representation of SymPy expressions.
"""
if _can_print(o):
s = latex(o, mode=latex_mode, **settings)
if latex_mode == 'plain':
return '$\\displaystyle %s$' % s
return s
def _result_display(self, arg):
"""IPython's pretty-printer display hook, for use in IPython 0.10
This function was adapted from:
ipython/IPython/hooks.py:155
"""
if self.rc.pprint:
out = stringify_func(arg)
if '\n' in out:
print()
print(out)
else:
print(repr(arg))
import IPython
if version_tuple(IPython.__version__) >= version_tuple('0.11'):
# Printable is our own type, so we handle it with methods instead of
# the approach required by builtin types. This allows downstream
# packages to override the methods in their own subclasses of Printable,
# which avoids the effects of gh-16002.
printable_types = [float, tuple, list, set, frozenset, dict, int]
plaintext_formatter = ip.display_formatter.formatters['text/plain']
# Exception to the rule above: IPython has better dispatching rules
# for plaintext printing (xref ipython/ipython#8938), and we can't
# use `_repr_pretty_` without hitting a recursion error in _print_plain.
for cls in printable_types + [Printable]:
plaintext_formatter.for_type(cls, _print_plain)
svg_formatter = ip.display_formatter.formatters['image/svg+xml']
if use_latex in ('svg', ):
debug("init_printing: using svg formatter")
for cls in printable_types:
svg_formatter.for_type(cls, _print_latex_svg)
Printable._repr_svg_ = _print_latex_svg
else:
debug("init_printing: not using any svg formatter")
for cls in printable_types:
# Better way to set this, but currently does not work in IPython
#png_formatter.for_type(cls, None)
if cls in svg_formatter.type_printers:
svg_formatter.type_printers.pop(cls)
Printable._repr_svg_ = Printable._repr_disabled
png_formatter = ip.display_formatter.formatters['image/png']
if use_latex in (True, 'png'):
debug("init_printing: using png formatter")
for cls in printable_types:
png_formatter.for_type(cls, _print_latex_png)
Printable._repr_png_ = _print_latex_png
elif use_latex == 'matplotlib':
debug("init_printing: using matplotlib formatter")
for cls in printable_types:
png_formatter.for_type(cls, _print_latex_matplotlib)
Printable._repr_png_ = _print_latex_matplotlib
else:
debug("init_printing: not using any png formatter")
for cls in printable_types:
# Better way to set this, but currently does not work in IPython
#png_formatter.for_type(cls, None)
if cls in png_formatter.type_printers:
png_formatter.type_printers.pop(cls)
Printable._repr_png_ = Printable._repr_disabled
latex_formatter = ip.display_formatter.formatters['text/latex']
if use_latex in (True, 'mathjax'):
debug("init_printing: using mathjax formatter")
for cls in printable_types:
latex_formatter.for_type(cls, _print_latex_text)
Printable._repr_latex_ = _print_latex_text
else:
debug("init_printing: not using text/latex formatter")
for cls in printable_types:
# Better way to set this, but currently does not work in IPython
#latex_formatter.for_type(cls, None)
if cls in latex_formatter.type_printers:
latex_formatter.type_printers.pop(cls)
Printable._repr_latex_ = Printable._repr_disabled
else:
ip.set_hook('result_display', _result_display)
def _is_ipython(shell):
"""Is a shell instance an IPython shell?"""
# shortcut, so we don't import IPython if we don't have to
from sys import modules
if 'IPython' not in modules:
return False
try:
from IPython.core.interactiveshell import InteractiveShell
except ImportError:
# IPython < 0.11
try:
from IPython.iplib import InteractiveShell
except ImportError:
# Reaching this points means IPython has changed in a backward-incompatible way
# that we don't know about. Warn?
return False
return isinstance(shell, InteractiveShell)
# Used by the doctester to override the default for no_global
NO_GLOBAL = False
def init_printing(pretty_print=True, order=None, use_unicode=None,
use_latex=None, wrap_line=None, num_columns=None,
no_global=False, ip=None, euler=False, forecolor=None,
backcolor='Transparent', fontsize='10pt',
latex_mode='plain', print_builtin=True,
str_printer=None, pretty_printer=None,
latex_printer=None, scale=1.0, **settings):
r"""
Initializes pretty-printer depending on the environment.
Parameters
==========
pretty_print : bool, default=True
If ``True``, use :func:`~.pretty_print` to stringify or the provided pretty
printer; if ``False``, use :func:`~.sstrrepr` to stringify or the provided string
printer.
order : string or None, default='lex'
There are a few different settings for this parameter:
``'lex'`` (default), which is lexographic order;
``'grlex'``, which is graded lexographic order;
``'grevlex'``, which is reversed graded lexographic order;
``'old'``, which is used for compatibility reasons and for long expressions;
``None``, which sets it to lex.
use_unicode : bool or None, default=None
If ``True``, use unicode characters;
if ``False``, do not use unicode characters;
if ``None``, make a guess based on the environment.
use_latex : string, bool, or None, default=None
If ``True``, use default LaTeX rendering in GUI interfaces (png and
mathjax);
if ``False``, do not use LaTeX rendering;
if ``None``, make a guess based on the environment;
if ``'png'``, enable LaTeX rendering with an external LaTeX compiler,
falling back to matplotlib if external compilation fails;
if ``'matplotlib'``, enable LaTeX rendering with matplotlib;
if ``'mathjax'``, enable LaTeX text generation, for example MathJax
rendering in IPython notebook or text rendering in LaTeX documents;
if ``'svg'``, enable LaTeX rendering with an external latex compiler,
no fallback
wrap_line : bool
If True, lines will wrap at the end; if False, they will not wrap
but continue as one line. This is only relevant if ``pretty_print`` is
True.
num_columns : int or None, default=None
If ``int``, number of columns before wrapping is set to num_columns; if
``None``, number of columns before wrapping is set to terminal width.
This is only relevant if ``pretty_print`` is ``True``.
no_global : bool, default=False
If ``True``, the settings become system wide;
if ``False``, use just for this console/session.
ip : An interactive console
This can either be an instance of IPython,
or a class that derives from code.InteractiveConsole.
euler : bool, optional, default=False
Loads the euler package in the LaTeX preamble for handwritten style
fonts (https://www.ctan.org/pkg/euler).
forecolor : string or None, optional, default=None
DVI setting for foreground color. ``None`` means that either ``'Black'``,
``'White'``, or ``'Gray'`` will be selected based on a guess of the IPython
terminal color setting. See notes.
backcolor : string, optional, default='Transparent'
DVI setting for background color. See notes.
fontsize : string or int, optional, default='10pt'
A font size to pass to the LaTeX documentclass function in the
preamble. Note that the options are limited by the documentclass.
Consider using scale instead.
latex_mode : string, optional, default='plain'
The mode used in the LaTeX printer. Can be one of:
``{'inline'|'plain'|'equation'|'equation*'}``.
print_builtin : boolean, optional, default=True
If ``True`` then floats and integers will be printed. If ``False`` the
printer will only print SymPy types.
str_printer : function, optional, default=None
A custom string printer function. This should mimic
:func:`~.sstrrepr()`.
pretty_printer : function, optional, default=None
A custom pretty printer. This should mimic :func:`~.pretty()`.
latex_printer : function, optional, default=None
A custom LaTeX printer. This should mimic :func:`~.latex()`.
scale : float, optional, default=1.0
Scale the LaTeX output when using the ``'png'`` or ``'svg'`` backends.
Useful for high dpi screens.
settings :
Any additional settings for the ``latex`` and ``pretty`` commands can
be used to fine-tune the output.
Examples
========
>>> from sympy.interactive import init_printing
>>> from sympy import Symbol, sqrt
>>> from sympy.abc import x, y
>>> sqrt(5)
sqrt(5)
>>> init_printing(pretty_print=True) # doctest: +SKIP
>>> sqrt(5) # doctest: +SKIP
___
\/ 5
>>> theta = Symbol('theta') # doctest: +SKIP
>>> init_printing(use_unicode=True) # doctest: +SKIP
>>> theta # doctest: +SKIP
\u03b8
>>> init_printing(use_unicode=False) # doctest: +SKIP
>>> theta # doctest: +SKIP
theta
>>> init_printing(order='lex') # doctest: +SKIP
>>> str(y + x + y**2 + x**2) # doctest: +SKIP
x**2 + x + y**2 + y
>>> init_printing(order='grlex') # doctest: +SKIP
>>> str(y + x + y**2 + x**2) # doctest: +SKIP
x**2 + x + y**2 + y
>>> init_printing(order='grevlex') # doctest: +SKIP
>>> str(y * x**2 + x * y**2) # doctest: +SKIP
x**2*y + x*y**2
>>> init_printing(order='old') # doctest: +SKIP
>>> str(x**2 + y**2 + x + y) # doctest: +SKIP
x**2 + x + y**2 + y
>>> init_printing(num_columns=10) # doctest: +SKIP
>>> x**2 + x + y**2 + y # doctest: +SKIP
x + y +
x**2 + y**2
Notes
=====
The foreground and background colors can be selected when using ``'png'`` or
``'svg'`` LaTeX rendering. Note that before the ``init_printing`` command is
executed, the LaTeX rendering is handled by the IPython console and not SymPy.
The colors can be selected among the 68 standard colors known to ``dvips``,
for a list see [1]_. In addition, the background color can be
set to ``'Transparent'`` (which is the default value).
When using the ``'Auto'`` foreground color, the guess is based on the
``colors`` variable in the IPython console, see [2]_. Hence, if
that variable is set correctly in your IPython console, there is a high
chance that the output will be readable, although manual settings may be
needed.
References
==========
.. [1] https://en.wikibooks.org/wiki/LaTeX/Colors#The_68_standard_colors_known_to_dvips
.. [2] https://ipython.readthedocs.io/en/stable/config/details.html#terminal-colors
See Also
========
sympy.printing.latex
sympy.printing.pretty
"""
import sys
from sympy.printing.printer import Printer
if pretty_print:
if pretty_printer is not None:
stringify_func = pretty_printer
else:
from sympy.printing import pretty as stringify_func
else:
if str_printer is not None:
stringify_func = str_printer
else:
from sympy.printing import sstrrepr as stringify_func
# Even if ip is not passed, double check that not in IPython shell
in_ipython = False
if ip is None:
try:
ip = get_ipython()
except NameError:
pass
else:
in_ipython = (ip is not None)
if ip and not in_ipython:
in_ipython = _is_ipython(ip)
if in_ipython and pretty_print:
try:
import IPython
# IPython 1.0 deprecates the frontend module, so we import directly
# from the terminal module to prevent a deprecation message from being
# shown.
if version_tuple(IPython.__version__) >= version_tuple('1.0'):
from IPython.terminal.interactiveshell import TerminalInteractiveShell
else:
from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
from code import InteractiveConsole
except ImportError:
pass
else:
# This will be True if we are in the qtconsole or notebook
if not isinstance(ip, (InteractiveConsole, TerminalInteractiveShell)) \
and 'ipython-console' not in ''.join(sys.argv):
if use_unicode is None:
debug("init_printing: Setting use_unicode to True")
use_unicode = True
if use_latex is None:
debug("init_printing: Setting use_latex to True")
use_latex = True
if not NO_GLOBAL and not no_global:
Printer.set_global_settings(order=order, use_unicode=use_unicode,
wrap_line=wrap_line, num_columns=num_columns)
else:
_stringify_func = stringify_func
if pretty_print:
stringify_func = lambda expr, **settings: \
_stringify_func(expr, order=order,
use_unicode=use_unicode,
wrap_line=wrap_line,
num_columns=num_columns,
**settings)
else:
stringify_func = \
lambda expr, **settings: _stringify_func(
expr, order=order, **settings)
if in_ipython:
mode_in_settings = settings.pop("mode", None)
if mode_in_settings:
debug("init_printing: Mode is not able to be set due to internals"
"of IPython printing")
_init_ipython_printing(ip, stringify_func, use_latex, euler,
forecolor, backcolor, fontsize, latex_mode,
print_builtin, latex_printer, scale,
**settings)
else:
_init_python_printing(stringify_func, **settings)

View File

@ -0,0 +1,463 @@
"""Tools for setting up interactive sessions. """
from sympy.external.gmpy import GROUND_TYPES
from sympy.external.importtools import version_tuple
from sympy.interactive.printing import init_printing
from sympy.utilities.misc import ARCH
preexec_source = """\
from sympy import *
x, y, z, t = symbols('x y z t')
k, m, n = symbols('k m n', integer=True)
f, g, h = symbols('f g h', cls=Function)
init_printing()
"""
verbose_message = """\
These commands were executed:
%(source)s
Documentation can be found at https://docs.sympy.org/%(version)s
"""
no_ipython = """\
Could not locate IPython. Having IPython installed is greatly recommended.
See http://ipython.scipy.org for more details. If you use Debian/Ubuntu,
just install the 'ipython' package and start isympy again.
"""
def _make_message(ipython=True, quiet=False, source=None):
"""Create a banner for an interactive session. """
from sympy import __version__ as sympy_version
from sympy import SYMPY_DEBUG
import sys
import os
if quiet:
return ""
python_version = "%d.%d.%d" % sys.version_info[:3]
if ipython:
shell_name = "IPython"
else:
shell_name = "Python"
info = ['ground types: %s' % GROUND_TYPES]
cache = os.getenv('SYMPY_USE_CACHE')
if cache is not None and cache.lower() == 'no':
info.append('cache: off')
if SYMPY_DEBUG:
info.append('debugging: on')
args = shell_name, sympy_version, python_version, ARCH, ', '.join(info)
message = "%s console for SymPy %s (Python %s-%s) (%s)\n" % args
if source is None:
source = preexec_source
_source = ""
for line in source.split('\n')[:-1]:
if not line:
_source += '\n'
else:
_source += '>>> ' + line + '\n'
doc_version = sympy_version
if 'dev' in doc_version:
doc_version = "dev"
else:
doc_version = "%s/" % doc_version
message += '\n' + verbose_message % {'source': _source,
'version': doc_version}
return message
def int_to_Integer(s):
"""
Wrap integer literals with Integer.
This is based on the decistmt example from
https://docs.python.org/3/library/tokenize.html.
Only integer literals are converted. Float literals are left alone.
Examples
========
>>> from sympy import Integer # noqa: F401
>>> from sympy.interactive.session import int_to_Integer
>>> s = '1.2 + 1/2 - 0x12 + a1'
>>> int_to_Integer(s)
'1.2 +Integer (1 )/Integer (2 )-Integer (0x12 )+a1 '
>>> s = 'print (1/2)'
>>> int_to_Integer(s)
'print (Integer (1 )/Integer (2 ))'
>>> exec(s)
0.5
>>> exec(int_to_Integer(s))
1/2
"""
from tokenize import generate_tokens, untokenize, NUMBER, NAME, OP
from io import StringIO
def _is_int(num):
"""
Returns true if string value num (with token NUMBER) represents an integer.
"""
# XXX: Is there something in the standard library that will do this?
if '.' in num or 'j' in num.lower() or 'e' in num.lower():
return False
return True
result = []
g = generate_tokens(StringIO(s).readline) # tokenize the string
for toknum, tokval, _, _, _ in g:
if toknum == NUMBER and _is_int(tokval): # replace NUMBER tokens
result.extend([
(NAME, 'Integer'),
(OP, '('),
(NUMBER, tokval),
(OP, ')')
])
else:
result.append((toknum, tokval))
return untokenize(result)
def enable_automatic_int_sympification(shell):
"""
Allow IPython to automatically convert integer literals to Integer.
"""
import ast
old_run_cell = shell.run_cell
def my_run_cell(cell, *args, **kwargs):
try:
# Check the cell for syntax errors. This way, the syntax error
# will show the original input, not the transformed input. The
# downside here is that IPython magic like %timeit will not work
# with transformed input (but on the other hand, IPython magic
# that doesn't expect transformed input will continue to work).
ast.parse(cell)
except SyntaxError:
pass
else:
cell = int_to_Integer(cell)
return old_run_cell(cell, *args, **kwargs)
shell.run_cell = my_run_cell
def enable_automatic_symbols(shell):
"""Allow IPython to automatically create symbols (``isympy -a``). """
# XXX: This should perhaps use tokenize, like int_to_Integer() above.
# This would avoid re-executing the code, which can lead to subtle
# issues. For example:
#
# In [1]: a = 1
#
# In [2]: for i in range(10):
# ...: a += 1
# ...:
#
# In [3]: a
# Out[3]: 11
#
# In [4]: a = 1
#
# In [5]: for i in range(10):
# ...: a += 1
# ...: print b
# ...:
# b
# b
# b
# b
# b
# b
# b
# b
# b
# b
#
# In [6]: a
# Out[6]: 12
#
# Note how the for loop is executed again because `b` was not defined, but `a`
# was already incremented once, so the result is that it is incremented
# multiple times.
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
finally:
self.run_cell("del %s" % match.group("symbol"),
store_history=False)
stb = self.InteractiveTB.structured_traceback(
etype, value, tb, tb_offset=tb_offset)
self._showtraceback(etype, value, stb)
shell.set_custom_exc((NameError,), _handler)
def init_ipython_session(shell=None, argv=[], auto_symbols=False, auto_int_to_Integer=False):
"""Construct new IPython session. """
import IPython
if version_tuple(IPython.__version__) >= version_tuple('0.11'):
if not shell:
# use an app to parse the command line, and init config
# IPython 1.0 deprecates the frontend module, so we import directly
# from the terminal module to prevent a deprecation message from being
# shown.
if version_tuple(IPython.__version__) >= version_tuple('1.0'):
from IPython.terminal import ipapp
else:
from IPython.frontend.terminal import ipapp
app = ipapp.TerminalIPythonApp()
# don't draw IPython banner during initialization:
app.display_banner = False
app.initialize(argv)
shell = app.shell
if auto_symbols:
enable_automatic_symbols(shell)
if auto_int_to_Integer:
enable_automatic_int_sympification(shell)
return shell
else:
from IPython.Shell import make_IPython
return make_IPython(argv)
def init_python_session():
"""Construct new Python session. """
from code import InteractiveConsole
class SymPyConsole(InteractiveConsole):
"""An interactive console with readline support. """
def __init__(self):
ns_locals = {}
InteractiveConsole.__init__(self, locals=ns_locals)
try:
import rlcompleter
import readline
except ImportError:
pass
else:
import os
import atexit
readline.set_completer(rlcompleter.Completer(ns_locals).complete)
readline.parse_and_bind('tab: complete')
if hasattr(readline, 'read_history_file'):
history = os.path.expanduser('~/.sympy-history')
try:
readline.read_history_file(history)
except OSError:
pass
atexit.register(readline.write_history_file, history)
return SymPyConsole()
def init_session(ipython=None, pretty_print=True, order=None,
use_unicode=None, use_latex=None, quiet=False, auto_symbols=False,
auto_int_to_Integer=False, str_printer=None, pretty_printer=None,
latex_printer=None, argv=[]):
"""
Initialize an embedded IPython or Python session. The IPython session is
initiated with the --pylab option, without the numpy imports, so that
matplotlib plotting can be interactive.
Parameters
==========
pretty_print: boolean
If True, use pretty_print to stringify;
if False, use sstrrepr to stringify.
order: string or None
There are a few different settings for this parameter:
lex (default), which is lexographic order;
grlex, which is graded lexographic order;
grevlex, which is reversed graded lexographic order;
old, which is used for compatibility reasons and for long expressions;
None, which sets it to lex.
use_unicode: boolean or None
If True, use unicode characters;
if False, do not use unicode characters.
use_latex: boolean or None
If True, use latex rendering if IPython GUI's;
if False, do not use latex rendering.
quiet: boolean
If True, init_session will not print messages regarding its status;
if False, init_session will print messages regarding its status.
auto_symbols: boolean
If True, IPython will automatically create symbols for you.
If False, it will not.
The default is False.
auto_int_to_Integer: boolean
If True, IPython will automatically wrap int literals with Integer, so
that things like 1/2 give Rational(1, 2).
If False, it will not.
The default is False.
ipython: boolean or None
If True, printing will initialize for an IPython console;
if False, printing will initialize for a normal console;
The default is None, which automatically determines whether we are in
an ipython instance or not.
str_printer: function, optional, default=None
A custom string printer function. This should mimic
sympy.printing.sstrrepr().
pretty_printer: function, optional, default=None
A custom pretty printer. This should mimic sympy.printing.pretty().
latex_printer: function, optional, default=None
A custom LaTeX printer. This should mimic sympy.printing.latex()
This should mimic sympy.printing.latex().
argv: list of arguments for IPython
See sympy.bin.isympy for options that can be used to initialize IPython.
See Also
========
sympy.interactive.printing.init_printing: for examples and the rest of the parameters.
Examples
========
>>> from sympy import init_session, Symbol, sin, sqrt
>>> sin(x) #doctest: +SKIP
NameError: name 'x' is not defined
>>> init_session() #doctest: +SKIP
>>> sin(x) #doctest: +SKIP
sin(x)
>>> sqrt(5) #doctest: +SKIP
___
\\/ 5
>>> init_session(pretty_print=False) #doctest: +SKIP
>>> sqrt(5) #doctest: +SKIP
sqrt(5)
>>> y + x + y**2 + x**2 #doctest: +SKIP
x**2 + x + y**2 + y
>>> init_session(order='grlex') #doctest: +SKIP
>>> y + x + y**2 + x**2 #doctest: +SKIP
x**2 + y**2 + x + y
>>> init_session(order='grevlex') #doctest: +SKIP
>>> y * x**2 + x * y**2 #doctest: +SKIP
x**2*y + x*y**2
>>> init_session(order='old') #doctest: +SKIP
>>> x**2 + y**2 + x + y #doctest: +SKIP
x + y + x**2 + y**2
>>> theta = Symbol('theta') #doctest: +SKIP
>>> theta #doctest: +SKIP
theta
>>> init_session(use_unicode=True) #doctest: +SKIP
>>> theta # doctest: +SKIP
\u03b8
"""
import sys
in_ipython = False
if ipython is not False:
try:
import IPython
except ImportError:
if ipython is True:
raise RuntimeError("IPython is not available on this system")
ip = None
else:
try:
from IPython import get_ipython
ip = get_ipython()
except ImportError:
ip = None
in_ipython = bool(ip)
if ipython is None:
ipython = in_ipython
if ipython is False:
ip = init_python_session()
mainloop = ip.interact
else:
ip = init_ipython_session(ip, argv=argv, auto_symbols=auto_symbols,
auto_int_to_Integer=auto_int_to_Integer)
if version_tuple(IPython.__version__) >= version_tuple('0.11'):
# runsource is gone, use run_cell instead, which doesn't
# take a symbol arg. The second arg is `store_history`,
# and False means don't add the line to IPython's history.
ip.runsource = lambda src, symbol='exec': ip.run_cell(src, False)
# Enable interactive plotting using pylab.
try:
ip.enable_pylab(import_all=False)
except Exception:
# Causes an import error if matplotlib is not installed.
# Causes other errors (depending on the backend) if there
# is no display, or if there is some problem in the
# backend, so we have a bare "except Exception" here
pass
if not in_ipython:
mainloop = ip.mainloop
if auto_symbols and (not ipython or version_tuple(IPython.__version__) < version_tuple('0.11')):
raise RuntimeError("automatic construction of symbols is possible only in IPython 0.11 or above")
if auto_int_to_Integer and (not ipython or version_tuple(IPython.__version__) < version_tuple('0.11')):
raise RuntimeError("automatic int to Integer transformation is possible only in IPython 0.11 or above")
_preexec_source = preexec_source
ip.runsource(_preexec_source, symbol='exec')
init_printing(pretty_print=pretty_print, order=order,
use_unicode=use_unicode, use_latex=use_latex, ip=ip,
str_printer=str_printer, pretty_printer=pretty_printer,
latex_printer=latex_printer)
message = _make_message(ipython, quiet, _preexec_source)
if not in_ipython:
print(message)
mainloop()
sys.exit('Exiting ...')
else:
print(message)
import atexit
atexit.register(lambda: print("Exiting ...\n"))

View File

@ -0,0 +1,10 @@
from sympy.interactive.session import int_to_Integer
def test_int_to_Integer():
assert int_to_Integer("1 + 2.2 + 0x3 + 40") == \
'Integer (1 )+2.2 +Integer (0x3 )+Integer (40 )'
assert int_to_Integer("0b101") == 'Integer (0b101 )'
assert int_to_Integer("ab1 + 1 + '1 + 2'") == "ab1 +Integer (1 )+'1 + 2'"
assert int_to_Integer("(2 + \n3)") == '(Integer (2 )+\nInteger (3 ))'
assert int_to_Integer("2 + 2.0 + 2j + 2e-10") == 'Integer (2 )+2.0 +2j +2e-10 '

View File

@ -0,0 +1,278 @@
"""Tests of tools for setting up interactive IPython sessions. """
from sympy.interactive.session import (init_ipython_session,
enable_automatic_symbols, enable_automatic_int_sympification)
from sympy.core import Symbol, Rational, Integer
from sympy.external import import_module
from sympy.testing.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
# WARNING: These tests will modify the existing IPython environment. IPython
# uses a single instance for its interpreter, so there is no way to isolate
# the test from another IPython session. It also means that if this test is
# run twice in the same Python session it will fail. This isn't usually a
# problem because the test suite is run in a subprocess by default, but if the
# tests are run with subprocess=False it can pollute the current IPython
# session. See the discussion in issue #15149.
def test_automatic_symbols():
# NOTE: Because of the way the hook works, you have to use run_cell(code,
# True). This means that the code must have no Out, or it will be printed
# during the tests.
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("a = %s" % symbol, True)
assert symbol not in app.user_ns
app.run_cell("a = type(%s)" % symbol, True)
assert app.user_ns['a'] == Symbol
app.run_cell("%s = Symbol('%s')" % (symbol, symbol), True)
assert symbol in app.user_ns
# Check that built-in names aren't overridden
app.run_cell("a = all == __builtin__.all", True)
assert "all" not in app.user_ns
assert app.user_ns['a'] is True
# Check that SymPy names aren't overridden
app.run_cell("import sympy")
app.run_cell("a = factorial == sympy.factorial", True)
assert app.user_ns['a'] is True
def test_int_to_Integer():
# XXX: Warning, don't test with == here. 0.5 == Rational(1, 2) is True!
app = init_ipython_session()
app.run_cell("from sympy import Integer")
app.run_cell("a = 1")
assert isinstance(app.user_ns['a'], int)
enable_automatic_int_sympification(app)
app.run_cell("a = 1/2")
assert isinstance(app.user_ns['a'], Rational)
app.run_cell("a = 1")
assert isinstance(app.user_ns['a'], Integer)
app.run_cell("a = int(1)")
assert isinstance(app.user_ns['a'], int)
app.run_cell("a = (1/\n2)")
assert app.user_ns['a'] == Rational(1, 2)
# TODO: How can we test that the output of a SyntaxError is the original
# input, not the transformed input?
def test_ipythonprinting():
# Initialize and setup IPython session
app = init_ipython_session()
app.run_cell("ip = get_ipython()")
app.run_cell("inst = ip.instance()")
app.run_cell("format = inst.display_formatter.format")
app.run_cell("from sympy import Symbol")
# Printing without printing extension
app.run_cell("a = format(Symbol('pi'))")
app.run_cell("a2 = format(Symbol('pi')**2)")
# Deal with API change starting at IPython 1.0
if int(ipython.__version__.split(".")[0]) < 1:
assert app.user_ns['a']['text/plain'] == "pi"
assert app.user_ns['a2']['text/plain'] == "pi**2"
else:
assert app.user_ns['a'][0]['text/plain'] == "pi"
assert app.user_ns['a2'][0]['text/plain'] == "pi**2"
# Load printing extension
app.run_cell("from sympy import init_printing")
app.run_cell("init_printing()")
# Printing with printing extension
app.run_cell("a = format(Symbol('pi'))")
app.run_cell("a2 = format(Symbol('pi')**2)")
# Deal with API change starting at IPython 1.0
if int(ipython.__version__.split(".")[0]) < 1:
assert app.user_ns['a']['text/plain'] in ('\N{GREEK SMALL LETTER PI}', 'pi')
assert app.user_ns['a2']['text/plain'] in (' 2\n\N{GREEK SMALL LETTER PI} ', ' 2\npi ')
else:
assert app.user_ns['a'][0]['text/plain'] in ('\N{GREEK SMALL LETTER PI}', 'pi')
assert app.user_ns['a2'][0]['text/plain'] in (' 2\n\N{GREEK SMALL LETTER PI} ', ' 2\npi ')
def test_print_builtin_option():
# Initialize and setup IPython session
app = init_ipython_session()
app.run_cell("ip = get_ipython()")
app.run_cell("inst = ip.instance()")
app.run_cell("format = inst.display_formatter.format")
app.run_cell("from sympy import Symbol")
app.run_cell("from sympy import init_printing")
app.run_cell("a = format({Symbol('pi'): 3.14, Symbol('n_i'): 3})")
# Deal with API change starting at IPython 1.0
if int(ipython.__version__.split(".")[0]) < 1:
text = app.user_ns['a']['text/plain']
raises(KeyError, lambda: app.user_ns['a']['text/latex'])
else:
text = app.user_ns['a'][0]['text/plain']
raises(KeyError, lambda: app.user_ns['a'][0]['text/latex'])
# XXX: How can we make this ignore the terminal width? This test fails if
# the terminal is too narrow.
assert text in ("{pi: 3.14, n_i: 3}",
'{n\N{LATIN SUBSCRIPT SMALL LETTER I}: 3, \N{GREEK SMALL LETTER PI}: 3.14}',
"{n_i: 3, pi: 3.14}",
'{\N{GREEK SMALL LETTER PI}: 3.14, n\N{LATIN SUBSCRIPT SMALL LETTER I}: 3}')
# If we enable the default printing, then the dictionary's should render
# as a LaTeX version of the whole dict: ${\pi: 3.14, n_i: 3}$
app.run_cell("inst.display_formatter.formatters['text/latex'].enabled = True")
app.run_cell("init_printing(use_latex=True)")
app.run_cell("a = format({Symbol('pi'): 3.14, Symbol('n_i'): 3})")
# Deal with API change starting at IPython 1.0
if int(ipython.__version__.split(".")[0]) < 1:
text = app.user_ns['a']['text/plain']
latex = app.user_ns['a']['text/latex']
else:
text = app.user_ns['a'][0]['text/plain']
latex = app.user_ns['a'][0]['text/latex']
assert text in ("{pi: 3.14, n_i: 3}",
'{n\N{LATIN SUBSCRIPT SMALL LETTER I}: 3, \N{GREEK SMALL LETTER PI}: 3.14}',
"{n_i: 3, pi: 3.14}",
'{\N{GREEK SMALL LETTER PI}: 3.14, n\N{LATIN SUBSCRIPT SMALL LETTER I}: 3}')
assert latex == r'$\displaystyle \left\{ n_{i} : 3, \ \pi : 3.14\right\}$'
# Objects with an _latex overload should also be handled by our tuple
# printer.
app.run_cell("""\
class WithOverload:
def _latex(self, printer):
return r"\\LaTeX"
""")
app.run_cell("a = format((WithOverload(),))")
# Deal with API change starting at IPython 1.0
if int(ipython.__version__.split(".")[0]) < 1:
latex = app.user_ns['a']['text/latex']
else:
latex = app.user_ns['a'][0]['text/latex']
assert latex == r'$\displaystyle \left( \LaTeX,\right)$'
app.run_cell("inst.display_formatter.formatters['text/latex'].enabled = True")
app.run_cell("init_printing(use_latex=True, print_builtin=False)")
app.run_cell("a = format({Symbol('pi'): 3.14, Symbol('n_i'): 3})")
# Deal with API change starting at IPython 1.0
if int(ipython.__version__.split(".")[0]) < 1:
text = app.user_ns['a']['text/plain']
raises(KeyError, lambda: app.user_ns['a']['text/latex'])
else:
text = app.user_ns['a'][0]['text/plain']
raises(KeyError, lambda: app.user_ns['a'][0]['text/latex'])
# Note : In Python 3 we have one text type: str which holds Unicode data
# and two byte types bytes and bytearray.
# Python 3.3.3 + IPython 0.13.2 gives: '{n_i: 3, pi: 3.14}'
# Python 3.3.3 + IPython 1.1.0 gives: '{n_i: 3, pi: 3.14}'
assert text in ("{pi: 3.14, n_i: 3}", "{n_i: 3, pi: 3.14}")
def test_builtin_containers():
# Initialize and setup IPython session
app = init_ipython_session()
app.run_cell("ip = get_ipython()")
app.run_cell("inst = ip.instance()")
app.run_cell("format = inst.display_formatter.format")
app.run_cell("inst.display_formatter.formatters['text/latex'].enabled = True")
app.run_cell("from sympy import init_printing, Matrix")
app.run_cell('init_printing(use_latex=True, use_unicode=False)')
# Make sure containers that shouldn't pretty print don't.
app.run_cell('a = format((True, False))')
app.run_cell('import sys')
app.run_cell('b = format(sys.flags)')
app.run_cell('c = format((Matrix([1, 2]),))')
# Deal with API change starting at IPython 1.0
if int(ipython.__version__.split(".")[0]) < 1:
assert app.user_ns['a']['text/plain'] == '(True, False)'
assert 'text/latex' not in app.user_ns['a']
assert app.user_ns['b']['text/plain'][:10] == 'sys.flags('
assert 'text/latex' not in app.user_ns['b']
assert app.user_ns['c']['text/plain'] == \
"""\
[1] \n\
([ ],)
[2] \
"""
assert app.user_ns['c']['text/latex'] == '$\\displaystyle \\left( \\left[\\begin{matrix}1\\\\2\\end{matrix}\\right],\\right)$'
else:
assert app.user_ns['a'][0]['text/plain'] == '(True, False)'
assert 'text/latex' not in app.user_ns['a'][0]
assert app.user_ns['b'][0]['text/plain'][:10] == 'sys.flags('
assert 'text/latex' not in app.user_ns['b'][0]
assert app.user_ns['c'][0]['text/plain'] == \
"""\
[1] \n\
([ ],)
[2] \
"""
assert app.user_ns['c'][0]['text/latex'] == '$\\displaystyle \\left( \\left[\\begin{matrix}1\\\\2\\end{matrix}\\right],\\right)$'
def test_matplotlib_bad_latex():
# Initialize and setup IPython session
app = init_ipython_session()
app.run_cell("import IPython")
app.run_cell("ip = get_ipython()")
app.run_cell("inst = ip.instance()")
app.run_cell("format = inst.display_formatter.format")
app.run_cell("from sympy import init_printing, Matrix")
app.run_cell("init_printing(use_latex='matplotlib')")
# The png formatter is not enabled by default in this context
app.run_cell("inst.display_formatter.formatters['image/png'].enabled = True")
# Make sure no warnings are raised by IPython
app.run_cell("import warnings")
# IPython.core.formatters.FormatterWarning was introduced in IPython 2.0
if int(ipython.__version__.split(".")[0]) < 2:
app.run_cell("warnings.simplefilter('error')")
else:
app.run_cell("warnings.simplefilter('error', IPython.core.formatters.FormatterWarning)")
# This should not raise an exception
app.run_cell("a = format(Matrix([1, 2, 3]))")
# issue 9799
app.run_cell("from sympy import Piecewise, Symbol, Eq")
app.run_cell("x = Symbol('x'); pw = format(Piecewise((1, Eq(x, 0)), (0, True)))")
def test_override_repr_latex():
# Initialize and setup IPython session
app = init_ipython_session()
app.run_cell("import IPython")
app.run_cell("ip = get_ipython()")
app.run_cell("inst = ip.instance()")
app.run_cell("format = inst.display_formatter.format")
app.run_cell("inst.display_formatter.formatters['text/latex'].enabled = True")
app.run_cell("from sympy import init_printing")
app.run_cell("from sympy import Symbol")
app.run_cell("init_printing(use_latex=True)")
app.run_cell("""\
class SymbolWithOverload(Symbol):
def _repr_latex_(self):
return r"Hello " + super()._repr_latex_() + " world"
""")
app.run_cell("a = format(SymbolWithOverload('s'))")
if int(ipython.__version__.split(".")[0]) < 1:
latex = app.user_ns['a']['text/latex']
else:
latex = app.user_ns['a'][0]['text/latex']
assert latex == r'Hello $\displaystyle s$ world'

View File

@ -0,0 +1,95 @@
from sympy.core.basic import Basic
from sympy.printing import pprint
import random
def interactive_traversal(expr):
"""Traverse a tree asking a user which branch to choose. """
RED, BRED = '\033[0;31m', '\033[1;31m'
GREEN, BGREEN = '\033[0;32m', '\033[1;32m'
YELLOW, BYELLOW = '\033[0;33m', '\033[1;33m' # noqa
BLUE, BBLUE = '\033[0;34m', '\033[1;34m' # noqa
MAGENTA, BMAGENTA = '\033[0;35m', '\033[1;35m'# noqa
CYAN, BCYAN = '\033[0;36m', '\033[1;36m' # noqa
END = '\033[0m'
def cprint(*args):
print("".join(map(str, args)) + END)
def _interactive_traversal(expr, stage):
if stage > 0:
print()
cprint("Current expression (stage ", BYELLOW, stage, END, "):")
print(BCYAN)
pprint(expr)
print(END)
if isinstance(expr, Basic):
if expr.is_Add:
args = expr.as_ordered_terms()
elif expr.is_Mul:
args = expr.as_ordered_factors()
else:
args = expr.args
elif hasattr(expr, "__iter__"):
args = list(expr)
else:
return expr
n_args = len(args)
if not n_args:
return expr
for i, arg in enumerate(args):
cprint(GREEN, "[", BGREEN, i, GREEN, "] ", BLUE, type(arg), END)
pprint(arg)
print()
if n_args == 1:
choices = '0'
else:
choices = '0-%d' % (n_args - 1)
try:
choice = input("Your choice [%s,f,l,r,d,?]: " % choices)
except EOFError:
result = expr
print()
else:
if choice == '?':
cprint(RED, "%s - select subexpression with the given index" %
choices)
cprint(RED, "f - select the first subexpression")
cprint(RED, "l - select the last subexpression")
cprint(RED, "r - select a random subexpression")
cprint(RED, "d - done\n")
result = _interactive_traversal(expr, stage)
elif choice in ('d', ''):
result = expr
elif choice == 'f':
result = _interactive_traversal(args[0], stage + 1)
elif choice == 'l':
result = _interactive_traversal(args[-1], stage + 1)
elif choice == 'r':
result = _interactive_traversal(random.choice(args), stage + 1)
else:
try:
choice = int(choice)
except ValueError:
cprint(BRED,
"Choice must be a number in %s range\n" % choices)
result = _interactive_traversal(expr, stage)
else:
if choice < 0 or choice >= n_args:
cprint(BRED, "Choice must be in %s range\n" % choices)
result = _interactive_traversal(expr, stage)
else:
result = _interactive_traversal(args[choice], stage + 1)
return result
return _interactive_traversal(expr, 0)