add read me
This commit is contained in:
@@ -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']
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
532
venv/lib/python3.12/site-packages/sympy/interactive/printing.py
Normal file
532
venv/lib/python3.12/site-packages/sympy/interactive/printing.py
Normal file
@@ -0,0 +1,532 @@
|
||||
"""Tools for setting up printing in interactive sessions. """
|
||||
|
||||
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
|
||||
from sympy.external import import_module
|
||||
|
||||
|
||||
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. """
|
||||
IPython = import_module("IPython", min_module_version="1.0")
|
||||
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
|
||||
|
||||
# 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
|
||||
|
||||
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:
|
||||
from IPython.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)
|
||||
463
venv/lib/python3.12/site-packages/sympy/interactive/session.py
Normal file
463
venv/lib/python3.12/site-packages/sympy/interactive/session.py
Normal 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"))
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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 '
|
||||
@@ -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=">=1.0")
|
||||
# def test_automatic_symbols(ipython):
|
||||
|
||||
ipython = import_module("IPython", min_module_version="1.0")
|
||||
|
||||
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'
|
||||
@@ -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)
|
||||
Reference in New Issue
Block a user