1"""Tests that the IPython printing module is properly loaded. """
2
3from sympy.interactive.session import init_ipython_session
4from sympy.external import import_module
5from sympy.testing.pytest import raises
6
7# run_cell was added in IPython 0.11
8ipython = import_module("IPython", min_module_version="0.11")
9
10# disable tests if ipython is not present
11if not ipython:
12    disabled = True
13
14
15def test_ipythonprinting():
16    # Initialize and setup IPython session
17    app = init_ipython_session()
18    app.run_cell("ip = get_ipython()")
19    app.run_cell("inst = ip.instance()")
20    app.run_cell("format = inst.display_formatter.format")
21    app.run_cell("from sympy import Symbol")
22
23    # Printing without printing extension
24    app.run_cell("a = format(Symbol('pi'))")
25    app.run_cell("a2 = format(Symbol('pi')**2)")
26    # Deal with API change starting at IPython 1.0
27    if int(ipython.__version__.split(".")[0]) < 1:
28        assert app.user_ns['a']['text/plain'] == "pi"
29        assert app.user_ns['a2']['text/plain'] == "pi**2"
30    else:
31        assert app.user_ns['a'][0]['text/plain'] == "pi"
32        assert app.user_ns['a2'][0]['text/plain'] == "pi**2"
33
34    # Load printing extension
35    app.run_cell("from sympy import init_printing")
36    app.run_cell("init_printing()")
37    # Printing with printing extension
38    app.run_cell("a = format(Symbol('pi'))")
39    app.run_cell("a2 = format(Symbol('pi')**2)")
40    # Deal with API change starting at IPython 1.0
41    if int(ipython.__version__.split(".")[0]) < 1:
42        assert app.user_ns['a']['text/plain'] in ('\N{GREEK SMALL LETTER PI}', 'pi')
43        assert app.user_ns['a2']['text/plain'] in (' 2\n\N{GREEK SMALL LETTER PI} ', '  2\npi ')
44    else:
45        assert app.user_ns['a'][0]['text/plain'] in ('\N{GREEK SMALL LETTER PI}', 'pi')
46        assert app.user_ns['a2'][0]['text/plain'] in (' 2\n\N{GREEK SMALL LETTER PI} ', '  2\npi ')
47
48
49def test_print_builtin_option():
50    # Initialize and setup IPython session
51    app = init_ipython_session()
52    app.run_cell("ip = get_ipython()")
53    app.run_cell("inst = ip.instance()")
54    app.run_cell("format = inst.display_formatter.format")
55    app.run_cell("from sympy import Symbol")
56    app.run_cell("from sympy import init_printing")
57
58    app.run_cell("a = format({Symbol('pi'): 3.14, Symbol('n_i'): 3})")
59    # Deal with API change starting at IPython 1.0
60    if int(ipython.__version__.split(".")[0]) < 1:
61        text = app.user_ns['a']['text/plain']
62        raises(KeyError, lambda: app.user_ns['a']['text/latex'])
63    else:
64        text = app.user_ns['a'][0]['text/plain']
65        raises(KeyError, lambda: app.user_ns['a'][0]['text/latex'])
66    # Note : Unicode of Python2 is equivalent to str in Python3. In Python 3 we have one
67    # text type: str which holds Unicode data and two byte types bytes and bytearray.
68    # XXX: How can we make this ignore the terminal width? This test fails if
69    # the terminal is too narrow.
70    assert text in ("{pi: 3.14, n_i: 3}",
71                    '{n\N{LATIN SUBSCRIPT SMALL LETTER I}: 3, \N{GREEK SMALL LETTER PI}: 3.14}',
72                    "{n_i: 3, pi: 3.14}",
73                    '{\N{GREEK SMALL LETTER PI}: 3.14, n\N{LATIN SUBSCRIPT SMALL LETTER I}: 3}')
74
75    # If we enable the default printing, then the dictionary's should render
76    # as a LaTeX version of the whole dict: ${\pi: 3.14, n_i: 3}$
77    app.run_cell("inst.display_formatter.formatters['text/latex'].enabled = True")
78    app.run_cell("init_printing(use_latex=True)")
79    app.run_cell("a = format({Symbol('pi'): 3.14, Symbol('n_i'): 3})")
80    # Deal with API change starting at IPython 1.0
81    if int(ipython.__version__.split(".")[0]) < 1:
82        text = app.user_ns['a']['text/plain']
83        latex = app.user_ns['a']['text/latex']
84    else:
85        text = app.user_ns['a'][0]['text/plain']
86        latex = app.user_ns['a'][0]['text/latex']
87    assert text in ("{pi: 3.14, n_i: 3}",
88                    '{n\N{LATIN SUBSCRIPT SMALL LETTER I}: 3, \N{GREEK SMALL LETTER PI}: 3.14}',
89                    "{n_i: 3, pi: 3.14}",
90                    '{\N{GREEK SMALL LETTER PI}: 3.14, n\N{LATIN SUBSCRIPT SMALL LETTER I}: 3}')
91    assert latex == r'$\displaystyle \left\{ n_{i} : 3, \  \pi : 3.14\right\}$'
92
93    # Objects with an _latex overload should also be handled by our tuple
94    # printer.
95    app.run_cell("""\
96    class WithOverload:
97        def _latex(self, printer):
98            return r"\\LaTeX"
99    """)
100    app.run_cell("a = format((WithOverload(),))")
101    # Deal with API change starting at IPython 1.0
102    if int(ipython.__version__.split(".")[0]) < 1:
103        latex = app.user_ns['a']['text/latex']
104    else:
105        latex = app.user_ns['a'][0]['text/latex']
106    assert latex == r'$\displaystyle \left( \LaTeX,\right)$'
107
108    app.run_cell("inst.display_formatter.formatters['text/latex'].enabled = True")
109    app.run_cell("init_printing(use_latex=True, print_builtin=False)")
110    app.run_cell("a = format({Symbol('pi'): 3.14, Symbol('n_i'): 3})")
111    # Deal with API change starting at IPython 1.0
112    if int(ipython.__version__.split(".")[0]) < 1:
113        text = app.user_ns['a']['text/plain']
114        raises(KeyError, lambda: app.user_ns['a']['text/latex'])
115    else:
116        text = app.user_ns['a'][0]['text/plain']
117        raises(KeyError, lambda: app.user_ns['a'][0]['text/latex'])
118    # Note : In Python 3 we have one text type: str which holds Unicode data
119    # and two byte types bytes and bytearray.
120    # Python 3.3.3 + IPython 0.13.2 gives: '{n_i: 3, pi: 3.14}'
121    # Python 3.3.3 + IPython 1.1.0 gives: '{n_i: 3, pi: 3.14}'
122    assert text in ("{pi: 3.14, n_i: 3}", "{n_i: 3, pi: 3.14}")
123
124
125def test_builtin_containers():
126    # Initialize and setup IPython session
127    app = init_ipython_session()
128    app.run_cell("ip = get_ipython()")
129    app.run_cell("inst = ip.instance()")
130    app.run_cell("format = inst.display_formatter.format")
131    app.run_cell("inst.display_formatter.formatters['text/latex'].enabled = True")
132    app.run_cell("from sympy import init_printing, Matrix")
133    app.run_cell('init_printing(use_latex=True, use_unicode=False)')
134
135    # Make sure containers that shouldn't pretty print don't.
136    app.run_cell('a = format((True, False))')
137    app.run_cell('import sys')
138    app.run_cell('b = format(sys.flags)')
139    app.run_cell('c = format((Matrix([1, 2]),))')
140    # Deal with API change starting at IPython 1.0
141    if int(ipython.__version__.split(".")[0]) < 1:
142        assert app.user_ns['a']['text/plain'] ==  '(True, False)'
143        assert 'text/latex' not in app.user_ns['a']
144        assert app.user_ns['b']['text/plain'][:10] == 'sys.flags('
145        assert 'text/latex' not in app.user_ns['b']
146        assert app.user_ns['c']['text/plain'] == \
147"""\
148 [1]  \n\
149([ ],)
150 [2]  \
151"""
152        assert app.user_ns['c']['text/latex'] == '$\\displaystyle \\left( \\left[\\begin{matrix}1\\\\2\\end{matrix}\\right],\\right)$'
153    else:
154        assert app.user_ns['a'][0]['text/plain'] ==  '(True, False)'
155        assert 'text/latex' not in app.user_ns['a'][0]
156        assert app.user_ns['b'][0]['text/plain'][:10] == 'sys.flags('
157        assert 'text/latex' not in app.user_ns['b'][0]
158        assert app.user_ns['c'][0]['text/plain'] == \
159"""\
160 [1]  \n\
161([ ],)
162 [2]  \
163"""
164        assert app.user_ns['c'][0]['text/latex'] == '$\\displaystyle \\left( \\left[\\begin{matrix}1\\\\2\\end{matrix}\\right],\\right)$'
165
166def test_matplotlib_bad_latex():
167    # Initialize and setup IPython session
168    app = init_ipython_session()
169    app.run_cell("import IPython")
170    app.run_cell("ip = get_ipython()")
171    app.run_cell("inst = ip.instance()")
172    app.run_cell("format = inst.display_formatter.format")
173    app.run_cell("from sympy import init_printing, Matrix")
174    app.run_cell("init_printing(use_latex='matplotlib')")
175
176    # The png formatter is not enabled by default in this context
177    app.run_cell("inst.display_formatter.formatters['image/png'].enabled = True")
178
179    # Make sure no warnings are raised by IPython
180    app.run_cell("import warnings")
181    # IPython.core.formatters.FormatterWarning was introduced in IPython 2.0
182    if int(ipython.__version__.split(".")[0]) < 2:
183        app.run_cell("warnings.simplefilter('error')")
184    else:
185        app.run_cell("warnings.simplefilter('error', IPython.core.formatters.FormatterWarning)")
186
187    # This should not raise an exception
188    app.run_cell("a = format(Matrix([1, 2, 3]))")
189
190    # issue 9799
191    app.run_cell("from sympy import Piecewise, Symbol, Eq")
192    app.run_cell("x = Symbol('x'); pw = format(Piecewise((1, Eq(x, 0)), (0, True)))")
193
194
195def test_override_repr_latex():
196    # Initialize and setup IPython session
197    app = init_ipython_session()
198    app.run_cell("import IPython")
199    app.run_cell("ip = get_ipython()")
200    app.run_cell("inst = ip.instance()")
201    app.run_cell("format = inst.display_formatter.format")
202    app.run_cell("inst.display_formatter.formatters['text/latex'].enabled = True")
203    app.run_cell("from sympy import init_printing")
204    app.run_cell("from sympy import Symbol")
205    app.run_cell("init_printing(use_latex=True)")
206    app.run_cell("""\
207    class SymbolWithOverload(Symbol):
208        def _repr_latex_(self):
209            return r"Hello " + super()._repr_latex_() + " world"
210    """)
211    app.run_cell("a = format(SymbolWithOverload('s'))")
212
213    if int(ipython.__version__.split(".")[0]) < 1:
214        latex = app.user_ns['a']['text/latex']
215    else:
216        latex = app.user_ns['a'][0]['text/latex']
217    assert latex == r'Hello $\displaystyle s$ world'
218