printing.py 21 KB

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