Spaces:
Sleeping
Sleeping
| """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")) | |