printing.py 22 KB

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