printing.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. """Tools for setting up printing in interactive sessions. """
  2. from sympy.external.importtools import version_tuple
  3. from io import BytesIO
  4. from sympy.printing.latex import latex as default_latex
  5. from sympy.printing.preview import preview
  6. from sympy.utilities.misc import debug
  7. from sympy.printing.defaults import Printable
  8. def _init_python_printing(stringify_func, **settings):
  9. """Setup printing in Python interactive session. """
  10. import sys
  11. import builtins
  12. def _displayhook(arg):
  13. """Python's pretty-printer display hook.
  14. This function was adapted from:
  15. https://www.python.org/dev/peps/pep-0217/
  16. """
  17. if arg is not None:
  18. builtins._ = None
  19. print(stringify_func(arg, **settings))
  20. builtins._ = arg
  21. sys.displayhook = _displayhook
  22. def _init_ipython_printing(ip, stringify_func, use_latex, euler, forecolor,
  23. backcolor, fontsize, latex_mode, print_builtin,
  24. latex_printer, scale, **settings):
  25. """Setup printing in IPython interactive session. """
  26. try:
  27. from IPython.lib.latextools import latex_to_png
  28. except ImportError:
  29. pass
  30. # Guess best font color if none was given based on the ip.colors string.
  31. # From the IPython documentation:
  32. # It has four case-insensitive values: 'nocolor', 'neutral', 'linux',
  33. # 'lightbg'. The default is neutral, which should be legible on either
  34. # dark or light terminal backgrounds. linux is optimised for dark
  35. # backgrounds and lightbg for light ones.
  36. if forecolor is None:
  37. color = ip.colors.lower()
  38. if color == 'lightbg':
  39. forecolor = 'Black'
  40. elif color == 'linux':
  41. forecolor = 'White'
  42. else:
  43. # No idea, go with gray.
  44. forecolor = 'Gray'
  45. debug("init_printing: Automatic foreground color:", forecolor)
  46. if use_latex == "svg":
  47. extra_preamble = "\n\\special{color %s}" % forecolor
  48. else:
  49. extra_preamble = ""
  50. imagesize = 'tight'
  51. offset = "0cm,0cm"
  52. resolution = round(150*scale)
  53. dvi = r"-T %s -D %d -bg %s -fg %s -O %s" % (
  54. imagesize, resolution, backcolor, forecolor, offset)
  55. dvioptions = dvi.split()
  56. svg_scale = 150/72*scale
  57. dvioptions_svg = ["--no-fonts", "--scale={}".format(svg_scale)]
  58. debug("init_printing: DVIOPTIONS:", dvioptions)
  59. debug("init_printing: DVIOPTIONS_SVG:", dvioptions_svg)
  60. latex = latex_printer or default_latex
  61. def _print_plain(arg, p, cycle):
  62. """caller for pretty, for use in IPython 0.11"""
  63. if _can_print(arg):
  64. p.text(stringify_func(arg))
  65. else:
  66. p.text(IPython.lib.pretty.pretty(arg))
  67. def _preview_wrapper(o):
  68. exprbuffer = BytesIO()
  69. try:
  70. preview(o, output='png', viewer='BytesIO', euler=euler,
  71. outputbuffer=exprbuffer, extra_preamble=extra_preamble,
  72. dvioptions=dvioptions, fontsize=fontsize)
  73. except Exception as e:
  74. # IPython swallows exceptions
  75. debug("png printing:", "_preview_wrapper exception raised:",
  76. repr(e))
  77. raise
  78. return exprbuffer.getvalue()
  79. def _svg_wrapper(o):
  80. exprbuffer = BytesIO()
  81. try:
  82. preview(o, output='svg', viewer='BytesIO', euler=euler,
  83. outputbuffer=exprbuffer, extra_preamble=extra_preamble,
  84. dvioptions=dvioptions_svg, fontsize=fontsize)
  85. except Exception as e:
  86. # IPython swallows exceptions
  87. debug("svg printing:", "_preview_wrapper exception raised:",
  88. repr(e))
  89. raise
  90. return exprbuffer.getvalue().decode('utf-8')
  91. def _matplotlib_wrapper(o):
  92. # mathtext can't render some LaTeX commands. For example, it can't
  93. # render any LaTeX environments such as array or matrix. So here we
  94. # ensure that if mathtext fails to render, we return None.
  95. try:
  96. try:
  97. return latex_to_png(o, color=forecolor, scale=scale)
  98. except TypeError: # Old IPython version without color and scale
  99. return latex_to_png(o)
  100. except ValueError as e:
  101. debug('matplotlib exception caught:', repr(e))
  102. return None
  103. # Hook methods for builtin SymPy printers
  104. printing_hooks = ('_latex', '_sympystr', '_pretty', '_sympyrepr')
  105. def _can_print(o):
  106. """Return True if type o can be printed with one of the SymPy printers.
  107. If o is a container type, this is True if and only if every element of
  108. o can be printed in this way.
  109. """
  110. try:
  111. # If you're adding another type, make sure you add it to printable_types
  112. # later in this file as well
  113. builtin_types = (list, tuple, set, frozenset)
  114. if isinstance(o, builtin_types):
  115. # If the object is a custom subclass with a custom str or
  116. # repr, use that instead.
  117. if (type(o).__str__ not in (i.__str__ for i in builtin_types) or
  118. type(o).__repr__ not in (i.__repr__ for i in builtin_types)):
  119. return False
  120. return all(_can_print(i) for i in o)
  121. elif isinstance(o, dict):
  122. return all(_can_print(i) and _can_print(o[i]) for i in o)
  123. elif isinstance(o, bool):
  124. return False
  125. elif isinstance(o, Printable):
  126. # types known to SymPy
  127. return True
  128. elif any(hasattr(o, hook) for hook in printing_hooks):
  129. # types which add support themselves
  130. return True
  131. elif isinstance(o, (float, int)) and print_builtin:
  132. return True
  133. return False
  134. except RuntimeError:
  135. return False
  136. # This is in case maximum recursion depth is reached.
  137. # Since RecursionError is for versions of Python 3.5+
  138. # so this is to guard against RecursionError for older versions.
  139. def _print_latex_png(o):
  140. """
  141. A function that returns a png rendered by an external latex
  142. distribution, falling back to matplotlib rendering
  143. """
  144. if _can_print(o):
  145. s = latex(o, mode=latex_mode, **settings)
  146. if latex_mode == 'plain':
  147. s = '$\\displaystyle %s$' % s
  148. try:
  149. return _preview_wrapper(s)
  150. except RuntimeError as e:
  151. debug('preview failed with:', repr(e),
  152. ' Falling back to matplotlib backend')
  153. if latex_mode != 'inline':
  154. s = latex(o, mode='inline', **settings)
  155. return _matplotlib_wrapper(s)
  156. def _print_latex_svg(o):
  157. """
  158. A function that returns a svg rendered by an external latex
  159. distribution, no fallback available.
  160. """
  161. if _can_print(o):
  162. s = latex(o, mode=latex_mode, **settings)
  163. if latex_mode == 'plain':
  164. s = '$\\displaystyle %s$' % s
  165. try:
  166. return _svg_wrapper(s)
  167. except RuntimeError as e:
  168. debug('preview failed with:', repr(e),
  169. ' No fallback available.')
  170. def _print_latex_matplotlib(o):
  171. """
  172. A function that returns a png rendered by mathtext
  173. """
  174. if _can_print(o):
  175. s = latex(o, mode='inline', **settings)
  176. return _matplotlib_wrapper(s)
  177. def _print_latex_text(o):
  178. """
  179. A function to generate the latex representation of SymPy expressions.
  180. """
  181. if _can_print(o):
  182. s = latex(o, mode=latex_mode, **settings)
  183. if latex_mode == 'plain':
  184. return '$\\displaystyle %s$' % s
  185. return s
  186. def _result_display(self, arg):
  187. """IPython's pretty-printer display hook, for use in IPython 0.10
  188. This function was adapted from:
  189. ipython/IPython/hooks.py:155
  190. """
  191. if self.rc.pprint:
  192. out = stringify_func(arg)
  193. if '\n' in out:
  194. print()
  195. print(out)
  196. else:
  197. print(repr(arg))
  198. import IPython
  199. if version_tuple(IPython.__version__) >= version_tuple('0.11'):
  200. # Printable is our own type, so we handle it with methods instead of
  201. # the approach required by builtin types. This allows downstream
  202. # packages to override the methods in their own subclasses of Printable,
  203. # which avoids the effects of gh-16002.
  204. printable_types = [float, tuple, list, set, frozenset, dict, int]
  205. plaintext_formatter = ip.display_formatter.formatters['text/plain']
  206. # Exception to the rule above: IPython has better dispatching rules
  207. # for plaintext printing (xref ipython/ipython#8938), and we can't
  208. # use `_repr_pretty_` without hitting a recursion error in _print_plain.
  209. for cls in printable_types + [Printable]:
  210. plaintext_formatter.for_type(cls, _print_plain)
  211. svg_formatter = ip.display_formatter.formatters['image/svg+xml']
  212. if use_latex in ('svg', ):
  213. debug("init_printing: using svg formatter")
  214. for cls in printable_types:
  215. svg_formatter.for_type(cls, _print_latex_svg)
  216. Printable._repr_svg_ = _print_latex_svg
  217. else:
  218. debug("init_printing: not using any svg formatter")
  219. for cls in printable_types:
  220. # Better way to set this, but currently does not work in IPython
  221. #png_formatter.for_type(cls, None)
  222. if cls in svg_formatter.type_printers:
  223. svg_formatter.type_printers.pop(cls)
  224. Printable._repr_svg_ = Printable._repr_disabled
  225. png_formatter = ip.display_formatter.formatters['image/png']
  226. if use_latex in (True, 'png'):
  227. debug("init_printing: using png formatter")
  228. for cls in printable_types:
  229. png_formatter.for_type(cls, _print_latex_png)
  230. Printable._repr_png_ = _print_latex_png
  231. elif use_latex == 'matplotlib':
  232. debug("init_printing: using matplotlib formatter")
  233. for cls in printable_types:
  234. png_formatter.for_type(cls, _print_latex_matplotlib)
  235. Printable._repr_png_ = _print_latex_matplotlib
  236. else:
  237. debug("init_printing: not using any png formatter")
  238. for cls in printable_types:
  239. # Better way to set this, but currently does not work in IPython
  240. #png_formatter.for_type(cls, None)
  241. if cls in png_formatter.type_printers:
  242. png_formatter.type_printers.pop(cls)
  243. Printable._repr_png_ = Printable._repr_disabled
  244. latex_formatter = ip.display_formatter.formatters['text/latex']
  245. if use_latex in (True, 'mathjax'):
  246. debug("init_printing: using mathjax formatter")
  247. for cls in printable_types:
  248. latex_formatter.for_type(cls, _print_latex_text)
  249. Printable._repr_latex_ = _print_latex_text
  250. else:
  251. debug("init_printing: not using text/latex formatter")
  252. for cls in printable_types:
  253. # Better way to set this, but currently does not work in IPython
  254. #latex_formatter.for_type(cls, None)
  255. if cls in latex_formatter.type_printers:
  256. latex_formatter.type_printers.pop(cls)
  257. Printable._repr_latex_ = Printable._repr_disabled
  258. else:
  259. ip.set_hook('result_display', _result_display)
  260. def _is_ipython(shell):
  261. """Is a shell instance an IPython shell?"""
  262. # shortcut, so we don't import IPython if we don't have to
  263. from sys import modules
  264. if 'IPython' not in modules:
  265. return False
  266. try:
  267. from IPython.core.interactiveshell import InteractiveShell
  268. except ImportError:
  269. # IPython < 0.11
  270. try:
  271. from IPython.iplib import InteractiveShell
  272. except ImportError:
  273. # Reaching this points means IPython has changed in a backward-incompatible way
  274. # that we don't know about. Warn?
  275. return False
  276. return isinstance(shell, InteractiveShell)
  277. # Used by the doctester to override the default for no_global
  278. NO_GLOBAL = False
  279. def init_printing(pretty_print=True, order=None, use_unicode=None,
  280. use_latex=None, wrap_line=None, num_columns=None,
  281. no_global=False, ip=None, euler=False, forecolor=None,
  282. backcolor='Transparent', fontsize='10pt',
  283. latex_mode='plain', print_builtin=True,
  284. str_printer=None, pretty_printer=None,
  285. latex_printer=None, scale=1.0, **settings):
  286. r"""
  287. Initializes pretty-printer depending on the environment.
  288. Parameters
  289. ==========
  290. pretty_print : bool, default=True
  291. If ``True``, use :func:`~.pretty_print` to stringify or the provided pretty
  292. printer; if ``False``, use :func:`~.sstrrepr` to stringify or the provided string
  293. printer.
  294. order : string or None, default='lex'
  295. There are a few different settings for this parameter:
  296. ``'lex'`` (default), which is lexographic order;
  297. ``'grlex'``, which is graded lexographic order;
  298. ``'grevlex'``, which is reversed graded lexographic order;
  299. ``'old'``, which is used for compatibility reasons and for long expressions;
  300. ``None``, which sets it to lex.
  301. use_unicode : bool or None, default=None
  302. If ``True``, use unicode characters;
  303. if ``False``, do not use unicode characters;
  304. if ``None``, make a guess based on the environment.
  305. use_latex : string, bool, or None, default=None
  306. If ``True``, use default LaTeX rendering in GUI interfaces (png and
  307. mathjax);
  308. if ``False``, do not use LaTeX rendering;
  309. if ``None``, make a guess based on the environment;
  310. if ``'png'``, enable LaTeX rendering with an external LaTeX compiler,
  311. falling back to matplotlib if external compilation fails;
  312. if ``'matplotlib'``, enable LaTeX rendering with matplotlib;
  313. if ``'mathjax'``, enable LaTeX text generation, for example MathJax
  314. rendering in IPython notebook or text rendering in LaTeX documents;
  315. if ``'svg'``, enable LaTeX rendering with an external latex compiler,
  316. no fallback
  317. wrap_line : bool
  318. If True, lines will wrap at the end; if False, they will not wrap
  319. but continue as one line. This is only relevant if ``pretty_print`` is
  320. True.
  321. num_columns : int or None, default=None
  322. If ``int``, number of columns before wrapping is set to num_columns; if
  323. ``None``, number of columns before wrapping is set to terminal width.
  324. This is only relevant if ``pretty_print`` is ``True``.
  325. no_global : bool, default=False
  326. If ``True``, the settings become system wide;
  327. if ``False``, use just for this console/session.
  328. ip : An interactive console
  329. This can either be an instance of IPython,
  330. or a class that derives from code.InteractiveConsole.
  331. euler : bool, optional, default=False
  332. Loads the euler package in the LaTeX preamble for handwritten style
  333. fonts (https://www.ctan.org/pkg/euler).
  334. forecolor : string or None, optional, default=None
  335. DVI setting for foreground color. ``None`` means that either ``'Black'``,
  336. ``'White'``, or ``'Gray'`` will be selected based on a guess of the IPython
  337. terminal color setting. See notes.
  338. backcolor : string, optional, default='Transparent'
  339. DVI setting for background color. See notes.
  340. fontsize : string or int, optional, default='10pt'
  341. A font size to pass to the LaTeX documentclass function in the
  342. preamble. Note that the options are limited by the documentclass.
  343. Consider using scale instead.
  344. latex_mode : string, optional, default='plain'
  345. The mode used in the LaTeX printer. Can be one of:
  346. ``{'inline'|'plain'|'equation'|'equation*'}``.
  347. print_builtin : boolean, optional, default=True
  348. If ``True`` then floats and integers will be printed. If ``False`` the
  349. printer will only print SymPy types.
  350. str_printer : function, optional, default=None
  351. A custom string printer function. This should mimic
  352. :func:`~.sstrrepr()`.
  353. pretty_printer : function, optional, default=None
  354. A custom pretty printer. This should mimic :func:`~.pretty()`.
  355. latex_printer : function, optional, default=None
  356. A custom LaTeX printer. This should mimic :func:`~.latex()`.
  357. scale : float, optional, default=1.0
  358. Scale the LaTeX output when using the ``'png'`` or ``'svg'`` backends.
  359. Useful for high dpi screens.
  360. settings :
  361. Any additional settings for the ``latex`` and ``pretty`` commands can
  362. be used to fine-tune the output.
  363. Examples
  364. ========
  365. >>> from sympy.interactive import init_printing
  366. >>> from sympy import Symbol, sqrt
  367. >>> from sympy.abc import x, y
  368. >>> sqrt(5)
  369. sqrt(5)
  370. >>> init_printing(pretty_print=True) # doctest: +SKIP
  371. >>> sqrt(5) # doctest: +SKIP
  372. ___
  373. \/ 5
  374. >>> theta = Symbol('theta') # doctest: +SKIP
  375. >>> init_printing(use_unicode=True) # doctest: +SKIP
  376. >>> theta # doctest: +SKIP
  377. \u03b8
  378. >>> init_printing(use_unicode=False) # doctest: +SKIP
  379. >>> theta # doctest: +SKIP
  380. theta
  381. >>> init_printing(order='lex') # doctest: +SKIP
  382. >>> str(y + x + y**2 + x**2) # doctest: +SKIP
  383. x**2 + x + y**2 + y
  384. >>> init_printing(order='grlex') # doctest: +SKIP
  385. >>> str(y + x + y**2 + x**2) # doctest: +SKIP
  386. x**2 + x + y**2 + y
  387. >>> init_printing(order='grevlex') # doctest: +SKIP
  388. >>> str(y * x**2 + x * y**2) # doctest: +SKIP
  389. x**2*y + x*y**2
  390. >>> init_printing(order='old') # doctest: +SKIP
  391. >>> str(x**2 + y**2 + x + y) # doctest: +SKIP
  392. x**2 + x + y**2 + y
  393. >>> init_printing(num_columns=10) # doctest: +SKIP
  394. >>> x**2 + x + y**2 + y # doctest: +SKIP
  395. x + y +
  396. x**2 + y**2
  397. Notes
  398. =====
  399. The foreground and background colors can be selected when using ``'png'`` or
  400. ``'svg'`` LaTeX rendering. Note that before the ``init_printing`` command is
  401. executed, the LaTeX rendering is handled by the IPython console and not SymPy.
  402. The colors can be selected among the 68 standard colors known to ``dvips``,
  403. for a list see [1]_. In addition, the background color can be
  404. set to ``'Transparent'`` (which is the default value).
  405. When using the ``'Auto'`` foreground color, the guess is based on the
  406. ``colors`` variable in the IPython console, see [2]_. Hence, if
  407. that variable is set correctly in your IPython console, there is a high
  408. chance that the output will be readable, although manual settings may be
  409. needed.
  410. References
  411. ==========
  412. .. [1] https://en.wikibooks.org/wiki/LaTeX/Colors#The_68_standard_colors_known_to_dvips
  413. .. [2] https://ipython.readthedocs.io/en/stable/config/details.html#terminal-colors
  414. See Also
  415. ========
  416. sympy.printing.latex
  417. sympy.printing.pretty
  418. """
  419. import sys
  420. from sympy.printing.printer import Printer
  421. if pretty_print:
  422. if pretty_printer is not None:
  423. stringify_func = pretty_printer
  424. else:
  425. from sympy.printing import pretty as stringify_func
  426. else:
  427. if str_printer is not None:
  428. stringify_func = str_printer
  429. else:
  430. from sympy.printing import sstrrepr as stringify_func
  431. # Even if ip is not passed, double check that not in IPython shell
  432. in_ipython = False
  433. if ip is None:
  434. try:
  435. ip = get_ipython()
  436. except NameError:
  437. pass
  438. else:
  439. in_ipython = (ip is not None)
  440. if ip and not in_ipython:
  441. in_ipython = _is_ipython(ip)
  442. if in_ipython and pretty_print:
  443. try:
  444. import IPython
  445. # IPython 1.0 deprecates the frontend module, so we import directly
  446. # from the terminal module to prevent a deprecation message from being
  447. # shown.
  448. if version_tuple(IPython.__version__) >= version_tuple('1.0'):
  449. from IPython.terminal.interactiveshell import TerminalInteractiveShell
  450. else:
  451. from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
  452. from code import InteractiveConsole
  453. except ImportError:
  454. pass
  455. else:
  456. # This will be True if we are in the qtconsole or notebook
  457. if not isinstance(ip, (InteractiveConsole, TerminalInteractiveShell)) \
  458. and 'ipython-console' not in ''.join(sys.argv):
  459. if use_unicode is None:
  460. debug("init_printing: Setting use_unicode to True")
  461. use_unicode = True
  462. if use_latex is None:
  463. debug("init_printing: Setting use_latex to True")
  464. use_latex = True
  465. if not NO_GLOBAL and not no_global:
  466. Printer.set_global_settings(order=order, use_unicode=use_unicode,
  467. wrap_line=wrap_line, num_columns=num_columns)
  468. else:
  469. _stringify_func = stringify_func
  470. if pretty_print:
  471. stringify_func = lambda expr, **settings: \
  472. _stringify_func(expr, order=order,
  473. use_unicode=use_unicode,
  474. wrap_line=wrap_line,
  475. num_columns=num_columns,
  476. **settings)
  477. else:
  478. stringify_func = \
  479. lambda expr, **settings: _stringify_func(
  480. expr, order=order, **settings)
  481. if in_ipython:
  482. mode_in_settings = settings.pop("mode", None)
  483. if mode_in_settings:
  484. debug("init_printing: Mode is not able to be set due to internals"
  485. "of IPython printing")
  486. _init_ipython_printing(ip, stringify_func, use_latex, euler,
  487. forecolor, backcolor, fontsize, latex_mode,
  488. print_builtin, latex_printer, scale,
  489. **settings)
  490. else:
  491. _init_python_printing(stringify_func, **settings)