##// END OF EJS Templates
Merge pull request #13303 from Kojoley/remove-skip_iptest_but_not_pytest...
Matthias Bussonnier -
r27111:6a25628e merge
parent child Browse files
Show More
@@ -1,388 +1,385
1 """Tests for the token-based transformers in IPython.core.inputtransformer2
1 """Tests for the token-based transformers in IPython.core.inputtransformer2
2
2
3 Line-based transformers are the simpler ones; token-based transformers are
3 Line-based transformers are the simpler ones; token-based transformers are
4 more complex. See test_inputtransformer2_line for tests for line-based
4 more complex. See test_inputtransformer2_line for tests for line-based
5 transformations.
5 transformations.
6 """
6 """
7 import string
7 import string
8 import sys
8 import sys
9 from textwrap import dedent
9 from textwrap import dedent
10
10
11 import pytest
11 import pytest
12
12
13 from IPython.core import inputtransformer2 as ipt2
13 from IPython.core import inputtransformer2 as ipt2
14 from IPython.core.inputtransformer2 import _find_assign_op, make_tokens_by_line
14 from IPython.core.inputtransformer2 import _find_assign_op, make_tokens_by_line
15 from IPython.testing.decorators import skip_iptest_but_not_pytest
16
15
17 MULTILINE_MAGIC = ("""\
16 MULTILINE_MAGIC = ("""\
18 a = f()
17 a = f()
19 %foo \\
18 %foo \\
20 bar
19 bar
21 g()
20 g()
22 """.splitlines(keepends=True), (2, 0), """\
21 """.splitlines(keepends=True), (2, 0), """\
23 a = f()
22 a = f()
24 get_ipython().run_line_magic('foo', ' bar')
23 get_ipython().run_line_magic('foo', ' bar')
25 g()
24 g()
26 """.splitlines(keepends=True))
25 """.splitlines(keepends=True))
27
26
28 INDENTED_MAGIC = ("""\
27 INDENTED_MAGIC = ("""\
29 for a in range(5):
28 for a in range(5):
30 %ls
29 %ls
31 """.splitlines(keepends=True), (2, 4), """\
30 """.splitlines(keepends=True), (2, 4), """\
32 for a in range(5):
31 for a in range(5):
33 get_ipython().run_line_magic('ls', '')
32 get_ipython().run_line_magic('ls', '')
34 """.splitlines(keepends=True))
33 """.splitlines(keepends=True))
35
34
36 CRLF_MAGIC = ([
35 CRLF_MAGIC = ([
37 "a = f()\n",
36 "a = f()\n",
38 "%ls\r\n",
37 "%ls\r\n",
39 "g()\n"
38 "g()\n"
40 ], (2, 0), [
39 ], (2, 0), [
41 "a = f()\n",
40 "a = f()\n",
42 "get_ipython().run_line_magic('ls', '')\n",
41 "get_ipython().run_line_magic('ls', '')\n",
43 "g()\n"
42 "g()\n"
44 ])
43 ])
45
44
46 MULTILINE_MAGIC_ASSIGN = ("""\
45 MULTILINE_MAGIC_ASSIGN = ("""\
47 a = f()
46 a = f()
48 b = %foo \\
47 b = %foo \\
49 bar
48 bar
50 g()
49 g()
51 """.splitlines(keepends=True), (2, 4), """\
50 """.splitlines(keepends=True), (2, 4), """\
52 a = f()
51 a = f()
53 b = get_ipython().run_line_magic('foo', ' bar')
52 b = get_ipython().run_line_magic('foo', ' bar')
54 g()
53 g()
55 """.splitlines(keepends=True))
54 """.splitlines(keepends=True))
56
55
57 MULTILINE_SYSTEM_ASSIGN = ("""\
56 MULTILINE_SYSTEM_ASSIGN = ("""\
58 a = f()
57 a = f()
59 b = !foo \\
58 b = !foo \\
60 bar
59 bar
61 g()
60 g()
62 """.splitlines(keepends=True), (2, 4), """\
61 """.splitlines(keepends=True), (2, 4), """\
63 a = f()
62 a = f()
64 b = get_ipython().getoutput('foo bar')
63 b = get_ipython().getoutput('foo bar')
65 g()
64 g()
66 """.splitlines(keepends=True))
65 """.splitlines(keepends=True))
67
66
68 #####
67 #####
69
68
70 MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT = ("""\
69 MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT = ("""\
71 def test():
70 def test():
72 for i in range(1):
71 for i in range(1):
73 print(i)
72 print(i)
74 res =! ls
73 res =! ls
75 """.splitlines(keepends=True), (4, 7), '''\
74 """.splitlines(keepends=True), (4, 7), '''\
76 def test():
75 def test():
77 for i in range(1):
76 for i in range(1):
78 print(i)
77 print(i)
79 res =get_ipython().getoutput(\' ls\')
78 res =get_ipython().getoutput(\' ls\')
80 '''.splitlines(keepends=True))
79 '''.splitlines(keepends=True))
81
80
82 ######
81 ######
83
82
84 AUTOCALL_QUOTE = (
83 AUTOCALL_QUOTE = (
85 [",f 1 2 3\n"], (1, 0),
84 [",f 1 2 3\n"], (1, 0),
86 ['f("1", "2", "3")\n']
85 ['f("1", "2", "3")\n']
87 )
86 )
88
87
89 AUTOCALL_QUOTE2 = (
88 AUTOCALL_QUOTE2 = (
90 [";f 1 2 3\n"], (1, 0),
89 [";f 1 2 3\n"], (1, 0),
91 ['f("1 2 3")\n']
90 ['f("1 2 3")\n']
92 )
91 )
93
92
94 AUTOCALL_PAREN = (
93 AUTOCALL_PAREN = (
95 ["/f 1 2 3\n"], (1, 0),
94 ["/f 1 2 3\n"], (1, 0),
96 ['f(1, 2, 3)\n']
95 ['f(1, 2, 3)\n']
97 )
96 )
98
97
99 SIMPLE_HELP = (
98 SIMPLE_HELP = (
100 ["foo?\n"], (1, 0),
99 ["foo?\n"], (1, 0),
101 ["get_ipython().run_line_magic('pinfo', 'foo')\n"]
100 ["get_ipython().run_line_magic('pinfo', 'foo')\n"]
102 )
101 )
103
102
104 DETAILED_HELP = (
103 DETAILED_HELP = (
105 ["foo??\n"], (1, 0),
104 ["foo??\n"], (1, 0),
106 ["get_ipython().run_line_magic('pinfo2', 'foo')\n"]
105 ["get_ipython().run_line_magic('pinfo2', 'foo')\n"]
107 )
106 )
108
107
109 MAGIC_HELP = (
108 MAGIC_HELP = (
110 ["%foo?\n"], (1, 0),
109 ["%foo?\n"], (1, 0),
111 ["get_ipython().run_line_magic('pinfo', '%foo')\n"]
110 ["get_ipython().run_line_magic('pinfo', '%foo')\n"]
112 )
111 )
113
112
114 HELP_IN_EXPR = (
113 HELP_IN_EXPR = (
115 ["a = b + c?\n"], (1, 0),
114 ["a = b + c?\n"], (1, 0),
116 ["get_ipython().set_next_input('a = b + c');"
115 ["get_ipython().set_next_input('a = b + c');"
117 "get_ipython().run_line_magic('pinfo', 'c')\n"]
116 "get_ipython().run_line_magic('pinfo', 'c')\n"]
118 )
117 )
119
118
120 HELP_CONTINUED_LINE = ("""\
119 HELP_CONTINUED_LINE = ("""\
121 a = \\
120 a = \\
122 zip?
121 zip?
123 """.splitlines(keepends=True), (1, 0),
122 """.splitlines(keepends=True), (1, 0),
124 [r"get_ipython().set_next_input('a = \\\nzip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
123 [r"get_ipython().set_next_input('a = \\\nzip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
125 )
124 )
126
125
127 HELP_MULTILINE = ("""\
126 HELP_MULTILINE = ("""\
128 (a,
127 (a,
129 b) = zip?
128 b) = zip?
130 """.splitlines(keepends=True), (1, 0),
129 """.splitlines(keepends=True), (1, 0),
131 [r"get_ipython().set_next_input('(a,\nb) = zip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
130 [r"get_ipython().set_next_input('(a,\nb) = zip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
132 )
131 )
133
132
134 HELP_UNICODE = (
133 HELP_UNICODE = (
135 ["Ο€.foo?\n"], (1, 0),
134 ["Ο€.foo?\n"], (1, 0),
136 ["get_ipython().run_line_magic('pinfo', 'Ο€.foo')\n"]
135 ["get_ipython().run_line_magic('pinfo', 'Ο€.foo')\n"]
137 )
136 )
138
137
139
138
140 def null_cleanup_transformer(lines):
139 def null_cleanup_transformer(lines):
141 """
140 """
142 A cleanup transform that returns an empty list.
141 A cleanup transform that returns an empty list.
143 """
142 """
144 return []
143 return []
145
144
146
145
147 def test_check_make_token_by_line_never_ends_empty():
146 def test_check_make_token_by_line_never_ends_empty():
148 """
147 """
149 Check that not sequence of single or double characters ends up leading to en empty list of tokens
148 Check that not sequence of single or double characters ends up leading to en empty list of tokens
150 """
149 """
151 from string import printable
150 from string import printable
152 for c in printable:
151 for c in printable:
153 assert make_tokens_by_line(c)[-1] != []
152 assert make_tokens_by_line(c)[-1] != []
154 for k in printable:
153 for k in printable:
155 assert make_tokens_by_line(c + k)[-1] != []
154 assert make_tokens_by_line(c + k)[-1] != []
156
155
157
156
158 def check_find(transformer, case, match=True):
157 def check_find(transformer, case, match=True):
159 sample, expected_start, _ = case
158 sample, expected_start, _ = case
160 tbl = make_tokens_by_line(sample)
159 tbl = make_tokens_by_line(sample)
161 res = transformer.find(tbl)
160 res = transformer.find(tbl)
162 if match:
161 if match:
163 # start_line is stored 0-indexed, expected values are 1-indexed
162 # start_line is stored 0-indexed, expected values are 1-indexed
164 assert (res.start_line + 1, res.start_col) == expected_start
163 assert (res.start_line + 1, res.start_col) == expected_start
165 return res
164 return res
166 else:
165 else:
167 assert res is None
166 assert res is None
168
167
169 def check_transform(transformer_cls, case):
168 def check_transform(transformer_cls, case):
170 lines, start, expected = case
169 lines, start, expected = case
171 transformer = transformer_cls(start)
170 transformer = transformer_cls(start)
172 assert transformer.transform(lines) == expected
171 assert transformer.transform(lines) == expected
173
172
174 def test_continued_line():
173 def test_continued_line():
175 lines = MULTILINE_MAGIC_ASSIGN[0]
174 lines = MULTILINE_MAGIC_ASSIGN[0]
176 assert ipt2.find_end_of_continued_line(lines, 1) == 2
175 assert ipt2.find_end_of_continued_line(lines, 1) == 2
177
176
178 assert ipt2.assemble_continued_line(lines, (1, 5), 2) == "foo bar"
177 assert ipt2.assemble_continued_line(lines, (1, 5), 2) == "foo bar"
179
178
180 def test_find_assign_magic():
179 def test_find_assign_magic():
181 check_find(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
180 check_find(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
182 check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN, match=False)
181 check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN, match=False)
183 check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT, match=False)
182 check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT, match=False)
184
183
185 def test_transform_assign_magic():
184 def test_transform_assign_magic():
186 check_transform(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
185 check_transform(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
187
186
188 def test_find_assign_system():
187 def test_find_assign_system():
189 check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
188 check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
190 check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
189 check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
191 check_find(ipt2.SystemAssign, (["a = !ls\n"], (1, 5), None))
190 check_find(ipt2.SystemAssign, (["a = !ls\n"], (1, 5), None))
192 check_find(ipt2.SystemAssign, (["a=!ls\n"], (1, 2), None))
191 check_find(ipt2.SystemAssign, (["a=!ls\n"], (1, 2), None))
193 check_find(ipt2.SystemAssign, MULTILINE_MAGIC_ASSIGN, match=False)
192 check_find(ipt2.SystemAssign, MULTILINE_MAGIC_ASSIGN, match=False)
194
193
195 def test_transform_assign_system():
194 def test_transform_assign_system():
196 check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
195 check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
197 check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
196 check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
198
197
199 def test_find_magic_escape():
198 def test_find_magic_escape():
200 check_find(ipt2.EscapedCommand, MULTILINE_MAGIC)
199 check_find(ipt2.EscapedCommand, MULTILINE_MAGIC)
201 check_find(ipt2.EscapedCommand, INDENTED_MAGIC)
200 check_find(ipt2.EscapedCommand, INDENTED_MAGIC)
202 check_find(ipt2.EscapedCommand, MULTILINE_MAGIC_ASSIGN, match=False)
201 check_find(ipt2.EscapedCommand, MULTILINE_MAGIC_ASSIGN, match=False)
203
202
204 def test_transform_magic_escape():
203 def test_transform_magic_escape():
205 check_transform(ipt2.EscapedCommand, MULTILINE_MAGIC)
204 check_transform(ipt2.EscapedCommand, MULTILINE_MAGIC)
206 check_transform(ipt2.EscapedCommand, INDENTED_MAGIC)
205 check_transform(ipt2.EscapedCommand, INDENTED_MAGIC)
207 check_transform(ipt2.EscapedCommand, CRLF_MAGIC)
206 check_transform(ipt2.EscapedCommand, CRLF_MAGIC)
208
207
209 def test_find_autocalls():
208 def test_find_autocalls():
210 for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
209 for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
211 print("Testing %r" % case[0])
210 print("Testing %r" % case[0])
212 check_find(ipt2.EscapedCommand, case)
211 check_find(ipt2.EscapedCommand, case)
213
212
214 def test_transform_autocall():
213 def test_transform_autocall():
215 for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
214 for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
216 print("Testing %r" % case[0])
215 print("Testing %r" % case[0])
217 check_transform(ipt2.EscapedCommand, case)
216 check_transform(ipt2.EscapedCommand, case)
218
217
219 def test_find_help():
218 def test_find_help():
220 for case in [SIMPLE_HELP, DETAILED_HELP, MAGIC_HELP, HELP_IN_EXPR]:
219 for case in [SIMPLE_HELP, DETAILED_HELP, MAGIC_HELP, HELP_IN_EXPR]:
221 check_find(ipt2.HelpEnd, case)
220 check_find(ipt2.HelpEnd, case)
222
221
223 tf = check_find(ipt2.HelpEnd, HELP_CONTINUED_LINE)
222 tf = check_find(ipt2.HelpEnd, HELP_CONTINUED_LINE)
224 assert tf.q_line == 1
223 assert tf.q_line == 1
225 assert tf.q_col == 3
224 assert tf.q_col == 3
226
225
227 tf = check_find(ipt2.HelpEnd, HELP_MULTILINE)
226 tf = check_find(ipt2.HelpEnd, HELP_MULTILINE)
228 assert tf.q_line == 1
227 assert tf.q_line == 1
229 assert tf.q_col == 8
228 assert tf.q_col == 8
230
229
231 # ? in a comment does not trigger help
230 # ? in a comment does not trigger help
232 check_find(ipt2.HelpEnd, (["foo # bar?\n"], None, None), match=False)
231 check_find(ipt2.HelpEnd, (["foo # bar?\n"], None, None), match=False)
233 # Nor in a string
232 # Nor in a string
234 check_find(ipt2.HelpEnd, (["foo = '''bar?\n"], None, None), match=False)
233 check_find(ipt2.HelpEnd, (["foo = '''bar?\n"], None, None), match=False)
235
234
236 def test_transform_help():
235 def test_transform_help():
237 tf = ipt2.HelpEnd((1, 0), (1, 9))
236 tf = ipt2.HelpEnd((1, 0), (1, 9))
238 assert tf.transform(HELP_IN_EXPR[0]) == HELP_IN_EXPR[2]
237 assert tf.transform(HELP_IN_EXPR[0]) == HELP_IN_EXPR[2]
239
238
240 tf = ipt2.HelpEnd((1, 0), (2, 3))
239 tf = ipt2.HelpEnd((1, 0), (2, 3))
241 assert tf.transform(HELP_CONTINUED_LINE[0]) == HELP_CONTINUED_LINE[2]
240 assert tf.transform(HELP_CONTINUED_LINE[0]) == HELP_CONTINUED_LINE[2]
242
241
243 tf = ipt2.HelpEnd((1, 0), (2, 8))
242 tf = ipt2.HelpEnd((1, 0), (2, 8))
244 assert tf.transform(HELP_MULTILINE[0]) == HELP_MULTILINE[2]
243 assert tf.transform(HELP_MULTILINE[0]) == HELP_MULTILINE[2]
245
244
246 tf = ipt2.HelpEnd((1, 0), (1, 0))
245 tf = ipt2.HelpEnd((1, 0), (1, 0))
247 assert tf.transform(HELP_UNICODE[0]) == HELP_UNICODE[2]
246 assert tf.transform(HELP_UNICODE[0]) == HELP_UNICODE[2]
248
247
249 def test_find_assign_op_dedent():
248 def test_find_assign_op_dedent():
250 """
249 """
251 be careful that empty token like dedent are not counted as parens
250 be careful that empty token like dedent are not counted as parens
252 """
251 """
253 class Tk:
252 class Tk:
254 def __init__(self, s):
253 def __init__(self, s):
255 self.string = s
254 self.string = s
256
255
257 assert _find_assign_op([Tk(s) for s in ("", "a", "=", "b")]) == 2
256 assert _find_assign_op([Tk(s) for s in ("", "a", "=", "b")]) == 2
258 assert (
257 assert (
259 _find_assign_op([Tk(s) for s in ("", "(", "a", "=", "b", ")", "=", "5")]) == 6
258 _find_assign_op([Tk(s) for s in ("", "(", "a", "=", "b", ")", "=", "5")]) == 6
260 )
259 )
261
260
262
261
263 examples = [
262 examples = [
264 pytest.param("a = 1", "complete", None),
263 pytest.param("a = 1", "complete", None),
265 pytest.param("for a in range(5):", "incomplete", 4),
264 pytest.param("for a in range(5):", "incomplete", 4),
266 pytest.param("for a in range(5):\n if a > 0:", "incomplete", 8),
265 pytest.param("for a in range(5):\n if a > 0:", "incomplete", 8),
267 pytest.param("raise = 2", "invalid", None),
266 pytest.param("raise = 2", "invalid", None),
268 pytest.param("a = [1,\n2,", "incomplete", 0),
267 pytest.param("a = [1,\n2,", "incomplete", 0),
269 pytest.param("(\n))", "incomplete", 0),
268 pytest.param("(\n))", "incomplete", 0),
270 pytest.param("\\\r\n", "incomplete", 0),
269 pytest.param("\\\r\n", "incomplete", 0),
271 pytest.param("a = '''\n hi", "incomplete", 3),
270 pytest.param("a = '''\n hi", "incomplete", 3),
272 pytest.param("def a():\n x=1\n global x", "invalid", None),
271 pytest.param("def a():\n x=1\n global x", "invalid", None),
273 pytest.param(
272 pytest.param(
274 "a \\ ",
273 "a \\ ",
275 "invalid",
274 "invalid",
276 None,
275 None,
277 marks=pytest.mark.xfail(
276 marks=pytest.mark.xfail(
278 reason="Bug in python 3.9.8 – bpo 45738",
277 reason="Bug in python 3.9.8 – bpo 45738",
279 condition=sys.version_info[:3] == (3, 9, 8),
278 condition=sys.version_info[:3] == (3, 9, 8),
280 raises=SystemError,
279 raises=SystemError,
281 strict=True,
280 strict=True,
282 ),
281 ),
283 ), # Nothing allowed after backslash,
282 ), # Nothing allowed after backslash,
284 pytest.param("1\\\n+2", "complete", None),
283 pytest.param("1\\\n+2", "complete", None),
285 ]
284 ]
286
285
287
286
288 @skip_iptest_but_not_pytest
289 @pytest.mark.parametrize("code, expected, number", examples)
287 @pytest.mark.parametrize("code, expected, number", examples)
290 def test_check_complete_param(code, expected, number):
288 def test_check_complete_param(code, expected, number):
291 cc = ipt2.TransformerManager().check_complete
289 cc = ipt2.TransformerManager().check_complete
292 assert cc(code) == (expected, number)
290 assert cc(code) == (expected, number)
293
291
294
292
295 @skip_iptest_but_not_pytest
296 @pytest.mark.xfail(
293 @pytest.mark.xfail(
297 reason="Bug in python 3.9.8 – bpo 45738",
294 reason="Bug in python 3.9.8 – bpo 45738",
298 condition=sys.version_info[:3] == (3, 9, 8),
295 condition=sys.version_info[:3] == (3, 9, 8),
299 )
296 )
300 def test_check_complete():
297 def test_check_complete():
301 cc = ipt2.TransformerManager().check_complete
298 cc = ipt2.TransformerManager().check_complete
302
299
303 example = dedent("""
300 example = dedent("""
304 if True:
301 if True:
305 a=1""" )
302 a=1""" )
306
303
307 assert cc(example) == ("incomplete", 4)
304 assert cc(example) == ("incomplete", 4)
308 assert cc(example + "\n") == ("complete", None)
305 assert cc(example + "\n") == ("complete", None)
309 assert cc(example + "\n ") == ("complete", None)
306 assert cc(example + "\n ") == ("complete", None)
310
307
311 # no need to loop on all the letters/numbers.
308 # no need to loop on all the letters/numbers.
312 short = '12abAB'+string.printable[62:]
309 short = '12abAB'+string.printable[62:]
313 for c in short:
310 for c in short:
314 # test does not raise:
311 # test does not raise:
315 cc(c)
312 cc(c)
316 for k in short:
313 for k in short:
317 cc(c+k)
314 cc(c+k)
318
315
319 assert cc("def f():\n x=0\n \\\n ") == ("incomplete", 2)
316 assert cc("def f():\n x=0\n \\\n ") == ("incomplete", 2)
320
317
321
318
322 def test_check_complete_II():
319 def test_check_complete_II():
323 """
320 """
324 Test that multiple line strings are properly handled.
321 Test that multiple line strings are properly handled.
325
322
326 Separate test function for convenience
323 Separate test function for convenience
327
324
328 """
325 """
329 cc = ipt2.TransformerManager().check_complete
326 cc = ipt2.TransformerManager().check_complete
330 assert cc('''def foo():\n """''') == ("incomplete", 4)
327 assert cc('''def foo():\n """''') == ("incomplete", 4)
331
328
332
329
333 def test_check_complete_invalidates_sunken_brackets():
330 def test_check_complete_invalidates_sunken_brackets():
334 """
331 """
335 Test that a single line with more closing brackets than the opening ones is
332 Test that a single line with more closing brackets than the opening ones is
336 interpreted as invalid
333 interpreted as invalid
337 """
334 """
338 cc = ipt2.TransformerManager().check_complete
335 cc = ipt2.TransformerManager().check_complete
339 assert cc(")") == ("invalid", None)
336 assert cc(")") == ("invalid", None)
340 assert cc("]") == ("invalid", None)
337 assert cc("]") == ("invalid", None)
341 assert cc("}") == ("invalid", None)
338 assert cc("}") == ("invalid", None)
342 assert cc(")(") == ("invalid", None)
339 assert cc(")(") == ("invalid", None)
343 assert cc("][") == ("invalid", None)
340 assert cc("][") == ("invalid", None)
344 assert cc("}{") == ("invalid", None)
341 assert cc("}{") == ("invalid", None)
345 assert cc("]()(") == ("invalid", None)
342 assert cc("]()(") == ("invalid", None)
346 assert cc("())(") == ("invalid", None)
343 assert cc("())(") == ("invalid", None)
347 assert cc(")[](") == ("invalid", None)
344 assert cc(")[](") == ("invalid", None)
348 assert cc("()](") == ("invalid", None)
345 assert cc("()](") == ("invalid", None)
349
346
350
347
351 def test_null_cleanup_transformer():
348 def test_null_cleanup_transformer():
352 manager = ipt2.TransformerManager()
349 manager = ipt2.TransformerManager()
353 manager.cleanup_transforms.insert(0, null_cleanup_transformer)
350 manager.cleanup_transforms.insert(0, null_cleanup_transformer)
354 assert manager.transform_cell("") == ""
351 assert manager.transform_cell("") == ""
355
352
356
353
357
354
358
355
359 def test_side_effects_I():
356 def test_side_effects_I():
360 count = 0
357 count = 0
361 def counter(lines):
358 def counter(lines):
362 nonlocal count
359 nonlocal count
363 count += 1
360 count += 1
364 return lines
361 return lines
365
362
366 counter.has_side_effects = True
363 counter.has_side_effects = True
367
364
368 manager = ipt2.TransformerManager()
365 manager = ipt2.TransformerManager()
369 manager.cleanup_transforms.insert(0, counter)
366 manager.cleanup_transforms.insert(0, counter)
370 assert manager.check_complete("a=1\n") == ('complete', None)
367 assert manager.check_complete("a=1\n") == ('complete', None)
371 assert count == 0
368 assert count == 0
372
369
373
370
374
371
375
372
376 def test_side_effects_II():
373 def test_side_effects_II():
377 count = 0
374 count = 0
378 def counter(lines):
375 def counter(lines):
379 nonlocal count
376 nonlocal count
380 count += 1
377 count += 1
381 return lines
378 return lines
382
379
383 counter.has_side_effects = True
380 counter.has_side_effects = True
384
381
385 manager = ipt2.TransformerManager()
382 manager = ipt2.TransformerManager()
386 manager.line_transforms.insert(0, counter)
383 manager.line_transforms.insert(0, counter)
387 assert manager.check_complete("b=1\n") == ('complete', None)
384 assert manager.check_complete("b=1\n") == ('complete', None)
388 assert count == 0
385 assert count == 0
@@ -1,1364 +1,1358
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for various magic functions."""
2 """Tests for various magic functions."""
3
3
4 import asyncio
4 import asyncio
5 import io
5 import io
6 import os
6 import os
7 import re
7 import re
8 import shlex
8 import shlex
9 import sys
9 import sys
10 import warnings
10 import warnings
11 from importlib import invalidate_caches
11 from importlib import invalidate_caches
12 from io import StringIO
12 from io import StringIO
13 from pathlib import Path
13 from pathlib import Path
14 from textwrap import dedent
14 from textwrap import dedent
15 from unittest import TestCase, mock
15 from unittest import TestCase, mock
16
16
17 import pytest
17 import pytest
18
18
19 from IPython import get_ipython
19 from IPython import get_ipython
20 from IPython.core import magic
20 from IPython.core import magic
21 from IPython.core.error import UsageError
21 from IPython.core.error import UsageError
22 from IPython.core.magic import (
22 from IPython.core.magic import (
23 Magics,
23 Magics,
24 cell_magic,
24 cell_magic,
25 line_magic,
25 line_magic,
26 magics_class,
26 magics_class,
27 register_cell_magic,
27 register_cell_magic,
28 register_line_magic,
28 register_line_magic,
29 )
29 )
30 from IPython.core.magics import code, execution, logging, osm, script
30 from IPython.core.magics import code, execution, logging, osm, script
31 from IPython.testing import decorators as dec
31 from IPython.testing import decorators as dec
32 from IPython.testing import tools as tt
32 from IPython.testing import tools as tt
33 from IPython.utils.io import capture_output
33 from IPython.utils.io import capture_output
34 from IPython.utils.process import find_cmd
34 from IPython.utils.process import find_cmd
35 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
35 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
36
36
37 from .test_debugger import PdbTestInput
37 from .test_debugger import PdbTestInput
38
38
39
39
40 @magic.magics_class
40 @magic.magics_class
41 class DummyMagics(magic.Magics): pass
41 class DummyMagics(magic.Magics): pass
42
42
43 def test_extract_code_ranges():
43 def test_extract_code_ranges():
44 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
44 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
45 expected = [
45 expected = [
46 (0, 1),
46 (0, 1),
47 (2, 3),
47 (2, 3),
48 (4, 6),
48 (4, 6),
49 (6, 9),
49 (6, 9),
50 (9, 14),
50 (9, 14),
51 (16, None),
51 (16, None),
52 (None, 9),
52 (None, 9),
53 (9, None),
53 (9, None),
54 (None, 13),
54 (None, 13),
55 (None, None),
55 (None, None),
56 ]
56 ]
57 actual = list(code.extract_code_ranges(instr))
57 actual = list(code.extract_code_ranges(instr))
58 assert actual == expected
58 assert actual == expected
59
59
60 def test_extract_symbols():
60 def test_extract_symbols():
61 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
61 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
62 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
62 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
63 expected = [([], ['a']),
63 expected = [([], ['a']),
64 (["def b():\n return 42\n"], []),
64 (["def b():\n return 42\n"], []),
65 (["class A: pass\n"], []),
65 (["class A: pass\n"], []),
66 (["class A: pass\n", "def b():\n return 42\n"], []),
66 (["class A: pass\n", "def b():\n return 42\n"], []),
67 (["class A: pass\n"], ['a']),
67 (["class A: pass\n"], ['a']),
68 ([], ['z'])]
68 ([], ['z'])]
69 for symbols, exp in zip(symbols_args, expected):
69 for symbols, exp in zip(symbols_args, expected):
70 assert code.extract_symbols(source, symbols) == exp
70 assert code.extract_symbols(source, symbols) == exp
71
71
72
72
73 def test_extract_symbols_raises_exception_with_non_python_code():
73 def test_extract_symbols_raises_exception_with_non_python_code():
74 source = ("=begin A Ruby program :)=end\n"
74 source = ("=begin A Ruby program :)=end\n"
75 "def hello\n"
75 "def hello\n"
76 "puts 'Hello world'\n"
76 "puts 'Hello world'\n"
77 "end")
77 "end")
78 with pytest.raises(SyntaxError):
78 with pytest.raises(SyntaxError):
79 code.extract_symbols(source, "hello")
79 code.extract_symbols(source, "hello")
80
80
81
81
82 def test_magic_not_found():
82 def test_magic_not_found():
83 # magic not found raises UsageError
83 # magic not found raises UsageError
84 with pytest.raises(UsageError):
84 with pytest.raises(UsageError):
85 _ip.magic('doesntexist')
85 _ip.magic('doesntexist')
86
86
87 # ensure result isn't success when a magic isn't found
87 # ensure result isn't success when a magic isn't found
88 result = _ip.run_cell('%doesntexist')
88 result = _ip.run_cell('%doesntexist')
89 assert isinstance(result.error_in_exec, UsageError)
89 assert isinstance(result.error_in_exec, UsageError)
90
90
91
91
92 def test_cell_magic_not_found():
92 def test_cell_magic_not_found():
93 # magic not found raises UsageError
93 # magic not found raises UsageError
94 with pytest.raises(UsageError):
94 with pytest.raises(UsageError):
95 _ip.run_cell_magic('doesntexist', 'line', 'cell')
95 _ip.run_cell_magic('doesntexist', 'line', 'cell')
96
96
97 # ensure result isn't success when a magic isn't found
97 # ensure result isn't success when a magic isn't found
98 result = _ip.run_cell('%%doesntexist')
98 result = _ip.run_cell('%%doesntexist')
99 assert isinstance(result.error_in_exec, UsageError)
99 assert isinstance(result.error_in_exec, UsageError)
100
100
101
101
102 def test_magic_error_status():
102 def test_magic_error_status():
103 def fail(shell):
103 def fail(shell):
104 1/0
104 1/0
105 _ip.register_magic_function(fail)
105 _ip.register_magic_function(fail)
106 result = _ip.run_cell('%fail')
106 result = _ip.run_cell('%fail')
107 assert isinstance(result.error_in_exec, ZeroDivisionError)
107 assert isinstance(result.error_in_exec, ZeroDivisionError)
108
108
109
109
110 def test_config():
110 def test_config():
111 """ test that config magic does not raise
111 """ test that config magic does not raise
112 can happen if Configurable init is moved too early into
112 can happen if Configurable init is moved too early into
113 Magics.__init__ as then a Config object will be registered as a
113 Magics.__init__ as then a Config object will be registered as a
114 magic.
114 magic.
115 """
115 """
116 ## should not raise.
116 ## should not raise.
117 _ip.magic('config')
117 _ip.magic('config')
118
118
119 def test_config_available_configs():
119 def test_config_available_configs():
120 """ test that config magic prints available configs in unique and
120 """ test that config magic prints available configs in unique and
121 sorted order. """
121 sorted order. """
122 with capture_output() as captured:
122 with capture_output() as captured:
123 _ip.magic('config')
123 _ip.magic('config')
124
124
125 stdout = captured.stdout
125 stdout = captured.stdout
126 config_classes = stdout.strip().split('\n')[1:]
126 config_classes = stdout.strip().split('\n')[1:]
127 assert config_classes == sorted(set(config_classes))
127 assert config_classes == sorted(set(config_classes))
128
128
129 def test_config_print_class():
129 def test_config_print_class():
130 """ test that config with a classname prints the class's options. """
130 """ test that config with a classname prints the class's options. """
131 with capture_output() as captured:
131 with capture_output() as captured:
132 _ip.magic('config TerminalInteractiveShell')
132 _ip.magic('config TerminalInteractiveShell')
133
133
134 stdout = captured.stdout
134 stdout = captured.stdout
135 assert re.match(
135 assert re.match(
136 "TerminalInteractiveShell.* options", stdout.splitlines()[0]
136 "TerminalInteractiveShell.* options", stdout.splitlines()[0]
137 ), f"{stdout}\n\n1st line of stdout not like 'TerminalInteractiveShell.* options'"
137 ), f"{stdout}\n\n1st line of stdout not like 'TerminalInteractiveShell.* options'"
138
138
139
139
140 def test_rehashx():
140 def test_rehashx():
141 # clear up everything
141 # clear up everything
142 _ip.alias_manager.clear_aliases()
142 _ip.alias_manager.clear_aliases()
143 del _ip.db['syscmdlist']
143 del _ip.db['syscmdlist']
144
144
145 _ip.magic('rehashx')
145 _ip.magic('rehashx')
146 # Practically ALL ipython development systems will have more than 10 aliases
146 # Practically ALL ipython development systems will have more than 10 aliases
147
147
148 assert len(_ip.alias_manager.aliases) > 10
148 assert len(_ip.alias_manager.aliases) > 10
149 for name, cmd in _ip.alias_manager.aliases:
149 for name, cmd in _ip.alias_manager.aliases:
150 # we must strip dots from alias names
150 # we must strip dots from alias names
151 assert "." not in name
151 assert "." not in name
152
152
153 # rehashx must fill up syscmdlist
153 # rehashx must fill up syscmdlist
154 scoms = _ip.db['syscmdlist']
154 scoms = _ip.db['syscmdlist']
155 assert len(scoms) > 10
155 assert len(scoms) > 10
156
156
157
157
158 def test_magic_parse_options():
158 def test_magic_parse_options():
159 """Test that we don't mangle paths when parsing magic options."""
159 """Test that we don't mangle paths when parsing magic options."""
160 ip = get_ipython()
160 ip = get_ipython()
161 path = 'c:\\x'
161 path = 'c:\\x'
162 m = DummyMagics(ip)
162 m = DummyMagics(ip)
163 opts = m.parse_options('-f %s' % path,'f:')[0]
163 opts = m.parse_options('-f %s' % path,'f:')[0]
164 # argv splitting is os-dependent
164 # argv splitting is os-dependent
165 if os.name == 'posix':
165 if os.name == 'posix':
166 expected = 'c:x'
166 expected = 'c:x'
167 else:
167 else:
168 expected = path
168 expected = path
169 assert opts["f"] == expected
169 assert opts["f"] == expected
170
170
171
171
172 def test_magic_parse_long_options():
172 def test_magic_parse_long_options():
173 """Magic.parse_options can handle --foo=bar long options"""
173 """Magic.parse_options can handle --foo=bar long options"""
174 ip = get_ipython()
174 ip = get_ipython()
175 m = DummyMagics(ip)
175 m = DummyMagics(ip)
176 opts, _ = m.parse_options("--foo --bar=bubble", "a", "foo", "bar=")
176 opts, _ = m.parse_options("--foo --bar=bubble", "a", "foo", "bar=")
177 assert "foo" in opts
177 assert "foo" in opts
178 assert "bar" in opts
178 assert "bar" in opts
179 assert opts["bar"] == "bubble"
179 assert opts["bar"] == "bubble"
180
180
181
181
182 def doctest_hist_f():
182 def doctest_hist_f():
183 """Test %hist -f with temporary filename.
183 """Test %hist -f with temporary filename.
184
184
185 In [9]: import tempfile
185 In [9]: import tempfile
186
186
187 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
187 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
188
188
189 In [11]: %hist -nl -f $tfile 3
189 In [11]: %hist -nl -f $tfile 3
190
190
191 In [13]: import os; os.unlink(tfile)
191 In [13]: import os; os.unlink(tfile)
192 """
192 """
193
193
194
194
195 def doctest_hist_op():
195 def doctest_hist_op():
196 """Test %hist -op
196 """Test %hist -op
197
197
198 In [1]: class b(float):
198 In [1]: class b(float):
199 ...: pass
199 ...: pass
200 ...:
200 ...:
201
201
202 In [2]: class s(object):
202 In [2]: class s(object):
203 ...: def __str__(self):
203 ...: def __str__(self):
204 ...: return 's'
204 ...: return 's'
205 ...:
205 ...:
206
206
207 In [3]:
207 In [3]:
208
208
209 In [4]: class r(b):
209 In [4]: class r(b):
210 ...: def __repr__(self):
210 ...: def __repr__(self):
211 ...: return 'r'
211 ...: return 'r'
212 ...:
212 ...:
213
213
214 In [5]: class sr(s,r): pass
214 In [5]: class sr(s,r): pass
215 ...:
215 ...:
216
216
217 In [6]:
217 In [6]:
218
218
219 In [7]: bb=b()
219 In [7]: bb=b()
220
220
221 In [8]: ss=s()
221 In [8]: ss=s()
222
222
223 In [9]: rr=r()
223 In [9]: rr=r()
224
224
225 In [10]: ssrr=sr()
225 In [10]: ssrr=sr()
226
226
227 In [11]: 4.5
227 In [11]: 4.5
228 Out[11]: 4.5
228 Out[11]: 4.5
229
229
230 In [12]: str(ss)
230 In [12]: str(ss)
231 Out[12]: 's'
231 Out[12]: 's'
232
232
233 In [13]:
233 In [13]:
234
234
235 In [14]: %hist -op
235 In [14]: %hist -op
236 >>> class b:
236 >>> class b:
237 ... pass
237 ... pass
238 ...
238 ...
239 >>> class s(b):
239 >>> class s(b):
240 ... def __str__(self):
240 ... def __str__(self):
241 ... return 's'
241 ... return 's'
242 ...
242 ...
243 >>>
243 >>>
244 >>> class r(b):
244 >>> class r(b):
245 ... def __repr__(self):
245 ... def __repr__(self):
246 ... return 'r'
246 ... return 'r'
247 ...
247 ...
248 >>> class sr(s,r): pass
248 >>> class sr(s,r): pass
249 >>>
249 >>>
250 >>> bb=b()
250 >>> bb=b()
251 >>> ss=s()
251 >>> ss=s()
252 >>> rr=r()
252 >>> rr=r()
253 >>> ssrr=sr()
253 >>> ssrr=sr()
254 >>> 4.5
254 >>> 4.5
255 4.5
255 4.5
256 >>> str(ss)
256 >>> str(ss)
257 's'
257 's'
258 >>>
258 >>>
259 """
259 """
260
260
261 def test_hist_pof():
261 def test_hist_pof():
262 ip = get_ipython()
262 ip = get_ipython()
263 ip.run_cell("1+2", store_history=True)
263 ip.run_cell("1+2", store_history=True)
264 #raise Exception(ip.history_manager.session_number)
264 #raise Exception(ip.history_manager.session_number)
265 #raise Exception(list(ip.history_manager._get_range_session()))
265 #raise Exception(list(ip.history_manager._get_range_session()))
266 with TemporaryDirectory() as td:
266 with TemporaryDirectory() as td:
267 tf = os.path.join(td, 'hist.py')
267 tf = os.path.join(td, 'hist.py')
268 ip.run_line_magic('history', '-pof %s' % tf)
268 ip.run_line_magic('history', '-pof %s' % tf)
269 assert os.path.isfile(tf)
269 assert os.path.isfile(tf)
270
270
271
271
272 def test_macro():
272 def test_macro():
273 ip = get_ipython()
273 ip = get_ipython()
274 ip.history_manager.reset() # Clear any existing history.
274 ip.history_manager.reset() # Clear any existing history.
275 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
275 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
276 for i, cmd in enumerate(cmds, start=1):
276 for i, cmd in enumerate(cmds, start=1):
277 ip.history_manager.store_inputs(i, cmd)
277 ip.history_manager.store_inputs(i, cmd)
278 ip.magic("macro test 1-3")
278 ip.magic("macro test 1-3")
279 assert ip.user_ns["test"].value == "\n".join(cmds) + "\n"
279 assert ip.user_ns["test"].value == "\n".join(cmds) + "\n"
280
280
281 # List macros
281 # List macros
282 assert "test" in ip.magic("macro")
282 assert "test" in ip.magic("macro")
283
283
284
284
285 def test_macro_run():
285 def test_macro_run():
286 """Test that we can run a multi-line macro successfully."""
286 """Test that we can run a multi-line macro successfully."""
287 ip = get_ipython()
287 ip = get_ipython()
288 ip.history_manager.reset()
288 ip.history_manager.reset()
289 cmds = ["a=10", "a+=1", "print(a)", "%macro test 2-3"]
289 cmds = ["a=10", "a+=1", "print(a)", "%macro test 2-3"]
290 for cmd in cmds:
290 for cmd in cmds:
291 ip.run_cell(cmd, store_history=True)
291 ip.run_cell(cmd, store_history=True)
292 assert ip.user_ns["test"].value == "a+=1\nprint(a)\n"
292 assert ip.user_ns["test"].value == "a+=1\nprint(a)\n"
293 with tt.AssertPrints("12"):
293 with tt.AssertPrints("12"):
294 ip.run_cell("test")
294 ip.run_cell("test")
295 with tt.AssertPrints("13"):
295 with tt.AssertPrints("13"):
296 ip.run_cell("test")
296 ip.run_cell("test")
297
297
298
298
299 def test_magic_magic():
299 def test_magic_magic():
300 """Test %magic"""
300 """Test %magic"""
301 ip = get_ipython()
301 ip = get_ipython()
302 with capture_output() as captured:
302 with capture_output() as captured:
303 ip.magic("magic")
303 ip.magic("magic")
304
304
305 stdout = captured.stdout
305 stdout = captured.stdout
306 assert "%magic" in stdout
306 assert "%magic" in stdout
307 assert "IPython" in stdout
307 assert "IPython" in stdout
308 assert "Available" in stdout
308 assert "Available" in stdout
309
309
310
310
311 @dec.skipif_not_numpy
311 @dec.skipif_not_numpy
312 def test_numpy_reset_array_undec():
312 def test_numpy_reset_array_undec():
313 "Test '%reset array' functionality"
313 "Test '%reset array' functionality"
314 _ip.ex("import numpy as np")
314 _ip.ex("import numpy as np")
315 _ip.ex("a = np.empty(2)")
315 _ip.ex("a = np.empty(2)")
316 assert "a" in _ip.user_ns
316 assert "a" in _ip.user_ns
317 _ip.magic("reset -f array")
317 _ip.magic("reset -f array")
318 assert "a" not in _ip.user_ns
318 assert "a" not in _ip.user_ns
319
319
320
320
321 def test_reset_out():
321 def test_reset_out():
322 "Test '%reset out' magic"
322 "Test '%reset out' magic"
323 _ip.run_cell("parrot = 'dead'", store_history=True)
323 _ip.run_cell("parrot = 'dead'", store_history=True)
324 # test '%reset -f out', make an Out prompt
324 # test '%reset -f out', make an Out prompt
325 _ip.run_cell("parrot", store_history=True)
325 _ip.run_cell("parrot", store_history=True)
326 assert "dead" in [_ip.user_ns[x] for x in ("_", "__", "___")]
326 assert "dead" in [_ip.user_ns[x] for x in ("_", "__", "___")]
327 _ip.magic("reset -f out")
327 _ip.magic("reset -f out")
328 assert "dead" not in [_ip.user_ns[x] for x in ("_", "__", "___")]
328 assert "dead" not in [_ip.user_ns[x] for x in ("_", "__", "___")]
329 assert len(_ip.user_ns["Out"]) == 0
329 assert len(_ip.user_ns["Out"]) == 0
330
330
331
331
332 def test_reset_in():
332 def test_reset_in():
333 "Test '%reset in' magic"
333 "Test '%reset in' magic"
334 # test '%reset -f in'
334 # test '%reset -f in'
335 _ip.run_cell("parrot", store_history=True)
335 _ip.run_cell("parrot", store_history=True)
336 assert "parrot" in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
336 assert "parrot" in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
337 _ip.magic("%reset -f in")
337 _ip.magic("%reset -f in")
338 assert "parrot" not in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
338 assert "parrot" not in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
339 assert len(set(_ip.user_ns["In"])) == 1
339 assert len(set(_ip.user_ns["In"])) == 1
340
340
341
341
342 def test_reset_dhist():
342 def test_reset_dhist():
343 "Test '%reset dhist' magic"
343 "Test '%reset dhist' magic"
344 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
344 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
345 _ip.magic("cd " + os.path.dirname(pytest.__file__))
345 _ip.magic("cd " + os.path.dirname(pytest.__file__))
346 _ip.magic("cd -")
346 _ip.magic("cd -")
347 assert len(_ip.user_ns["_dh"]) > 0
347 assert len(_ip.user_ns["_dh"]) > 0
348 _ip.magic("reset -f dhist")
348 _ip.magic("reset -f dhist")
349 assert len(_ip.user_ns["_dh"]) == 0
349 assert len(_ip.user_ns["_dh"]) == 0
350 _ip.run_cell("_dh = [d for d in tmp]") # restore
350 _ip.run_cell("_dh = [d for d in tmp]") # restore
351
351
352
352
353 def test_reset_in_length():
353 def test_reset_in_length():
354 "Test that '%reset in' preserves In[] length"
354 "Test that '%reset in' preserves In[] length"
355 _ip.run_cell("print 'foo'")
355 _ip.run_cell("print 'foo'")
356 _ip.run_cell("reset -f in")
356 _ip.run_cell("reset -f in")
357 assert len(_ip.user_ns["In"]) == _ip.displayhook.prompt_count + 1
357 assert len(_ip.user_ns["In"]) == _ip.displayhook.prompt_count + 1
358
358
359
359
360 class TestResetErrors(TestCase):
360 class TestResetErrors(TestCase):
361
361
362 def test_reset_redefine(self):
362 def test_reset_redefine(self):
363
363
364 @magics_class
364 @magics_class
365 class KernelMagics(Magics):
365 class KernelMagics(Magics):
366 @line_magic
366 @line_magic
367 def less(self, shell): pass
367 def less(self, shell): pass
368
368
369 _ip.register_magics(KernelMagics)
369 _ip.register_magics(KernelMagics)
370
370
371 with self.assertLogs() as cm:
371 with self.assertLogs() as cm:
372 # hack, we want to just capture logs, but assertLogs fails if not
372 # hack, we want to just capture logs, but assertLogs fails if not
373 # logs get produce.
373 # logs get produce.
374 # so log one things we ignore.
374 # so log one things we ignore.
375 import logging as log_mod
375 import logging as log_mod
376 log = log_mod.getLogger()
376 log = log_mod.getLogger()
377 log.info('Nothing')
377 log.info('Nothing')
378 # end hack.
378 # end hack.
379 _ip.run_cell("reset -f")
379 _ip.run_cell("reset -f")
380
380
381 assert len(cm.output) == 1
381 assert len(cm.output) == 1
382 for out in cm.output:
382 for out in cm.output:
383 assert "Invalid alias" not in out
383 assert "Invalid alias" not in out
384
384
385 def test_tb_syntaxerror():
385 def test_tb_syntaxerror():
386 """test %tb after a SyntaxError"""
386 """test %tb after a SyntaxError"""
387 ip = get_ipython()
387 ip = get_ipython()
388 ip.run_cell("for")
388 ip.run_cell("for")
389
389
390 # trap and validate stdout
390 # trap and validate stdout
391 save_stdout = sys.stdout
391 save_stdout = sys.stdout
392 try:
392 try:
393 sys.stdout = StringIO()
393 sys.stdout = StringIO()
394 ip.run_cell("%tb")
394 ip.run_cell("%tb")
395 out = sys.stdout.getvalue()
395 out = sys.stdout.getvalue()
396 finally:
396 finally:
397 sys.stdout = save_stdout
397 sys.stdout = save_stdout
398 # trim output, and only check the last line
398 # trim output, and only check the last line
399 last_line = out.rstrip().splitlines()[-1].strip()
399 last_line = out.rstrip().splitlines()[-1].strip()
400 assert last_line == "SyntaxError: invalid syntax"
400 assert last_line == "SyntaxError: invalid syntax"
401
401
402
402
403 def test_time():
403 def test_time():
404 ip = get_ipython()
404 ip = get_ipython()
405
405
406 with tt.AssertPrints("Wall time: "):
406 with tt.AssertPrints("Wall time: "):
407 ip.run_cell("%time None")
407 ip.run_cell("%time None")
408
408
409 ip.run_cell("def f(kmjy):\n"
409 ip.run_cell("def f(kmjy):\n"
410 " %time print (2*kmjy)")
410 " %time print (2*kmjy)")
411
411
412 with tt.AssertPrints("Wall time: "):
412 with tt.AssertPrints("Wall time: "):
413 with tt.AssertPrints("hihi", suppress=False):
413 with tt.AssertPrints("hihi", suppress=False):
414 ip.run_cell("f('hi')")
414 ip.run_cell("f('hi')")
415
415
416 def test_time_last_not_expression():
416 def test_time_last_not_expression():
417 ip.run_cell("%%time\n"
417 ip.run_cell("%%time\n"
418 "var_1 = 1\n"
418 "var_1 = 1\n"
419 "var_2 = 2\n")
419 "var_2 = 2\n")
420 assert ip.user_ns['var_1'] == 1
420 assert ip.user_ns['var_1'] == 1
421 del ip.user_ns['var_1']
421 del ip.user_ns['var_1']
422 assert ip.user_ns['var_2'] == 2
422 assert ip.user_ns['var_2'] == 2
423 del ip.user_ns['var_2']
423 del ip.user_ns['var_2']
424
424
425
425
426 @dec.skip_win32
426 @dec.skip_win32
427 def test_time2():
427 def test_time2():
428 ip = get_ipython()
428 ip = get_ipython()
429
429
430 with tt.AssertPrints("CPU times: user "):
430 with tt.AssertPrints("CPU times: user "):
431 ip.run_cell("%time None")
431 ip.run_cell("%time None")
432
432
433 def test_time3():
433 def test_time3():
434 """Erroneous magic function calls, issue gh-3334"""
434 """Erroneous magic function calls, issue gh-3334"""
435 ip = get_ipython()
435 ip = get_ipython()
436 ip.user_ns.pop('run', None)
436 ip.user_ns.pop('run', None)
437
437
438 with tt.AssertNotPrints("not found", channel='stderr'):
438 with tt.AssertNotPrints("not found", channel='stderr'):
439 ip.run_cell("%%time\n"
439 ip.run_cell("%%time\n"
440 "run = 0\n"
440 "run = 0\n"
441 "run += 1")
441 "run += 1")
442
442
443 def test_multiline_time():
443 def test_multiline_time():
444 """Make sure last statement from time return a value."""
444 """Make sure last statement from time return a value."""
445 ip = get_ipython()
445 ip = get_ipython()
446 ip.user_ns.pop('run', None)
446 ip.user_ns.pop('run', None)
447
447
448 ip.run_cell(dedent("""\
448 ip.run_cell(dedent("""\
449 %%time
449 %%time
450 a = "ho"
450 a = "ho"
451 b = "hey"
451 b = "hey"
452 a+b
452 a+b
453 """
453 """
454 )
454 )
455 )
455 )
456 assert ip.user_ns_hidden["_"] == "hohey"
456 assert ip.user_ns_hidden["_"] == "hohey"
457
457
458
458
459 def test_time_local_ns():
459 def test_time_local_ns():
460 """
460 """
461 Test that local_ns is actually global_ns when running a cell magic
461 Test that local_ns is actually global_ns when running a cell magic
462 """
462 """
463 ip = get_ipython()
463 ip = get_ipython()
464 ip.run_cell("%%time\n" "myvar = 1")
464 ip.run_cell("%%time\n" "myvar = 1")
465 assert ip.user_ns["myvar"] == 1
465 assert ip.user_ns["myvar"] == 1
466 del ip.user_ns["myvar"]
466 del ip.user_ns["myvar"]
467
467
468
468
469 def test_doctest_mode():
469 def test_doctest_mode():
470 "Toggle doctest_mode twice, it should be a no-op and run without error"
470 "Toggle doctest_mode twice, it should be a no-op and run without error"
471 _ip.magic('doctest_mode')
471 _ip.magic('doctest_mode')
472 _ip.magic('doctest_mode')
472 _ip.magic('doctest_mode')
473
473
474
474
475 def test_parse_options():
475 def test_parse_options():
476 """Tests for basic options parsing in magics."""
476 """Tests for basic options parsing in magics."""
477 # These are only the most minimal of tests, more should be added later. At
477 # These are only the most minimal of tests, more should be added later. At
478 # the very least we check that basic text/unicode calls work OK.
478 # the very least we check that basic text/unicode calls work OK.
479 m = DummyMagics(_ip)
479 m = DummyMagics(_ip)
480 assert m.parse_options("foo", "")[1] == "foo"
480 assert m.parse_options("foo", "")[1] == "foo"
481 assert m.parse_options("foo", "")[1] == "foo"
481 assert m.parse_options("foo", "")[1] == "foo"
482
482
483
483
484 def test_parse_options_preserve_non_option_string():
484 def test_parse_options_preserve_non_option_string():
485 """Test to assert preservation of non-option part of magic-block, while parsing magic options."""
485 """Test to assert preservation of non-option part of magic-block, while parsing magic options."""
486 m = DummyMagics(_ip)
486 m = DummyMagics(_ip)
487 opts, stmt = m.parse_options(
487 opts, stmt = m.parse_options(
488 " -n1 -r 13 _ = 314 + foo", "n:r:", preserve_non_opts=True
488 " -n1 -r 13 _ = 314 + foo", "n:r:", preserve_non_opts=True
489 )
489 )
490 assert opts == {"n": "1", "r": "13"}
490 assert opts == {"n": "1", "r": "13"}
491 assert stmt == "_ = 314 + foo"
491 assert stmt == "_ = 314 + foo"
492
492
493
493
494 def test_run_magic_preserve_code_block():
494 def test_run_magic_preserve_code_block():
495 """Test to assert preservation of non-option part of magic-block, while running magic."""
495 """Test to assert preservation of non-option part of magic-block, while running magic."""
496 _ip.user_ns["spaces"] = []
496 _ip.user_ns["spaces"] = []
497 _ip.magic("timeit -n1 -r1 spaces.append([s.count(' ') for s in ['document']])")
497 _ip.magic("timeit -n1 -r1 spaces.append([s.count(' ') for s in ['document']])")
498 assert _ip.user_ns["spaces"] == [[0]]
498 assert _ip.user_ns["spaces"] == [[0]]
499
499
500
500
501 def test_dirops():
501 def test_dirops():
502 """Test various directory handling operations."""
502 """Test various directory handling operations."""
503 # curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
503 # curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
504 curpath = os.getcwd
504 curpath = os.getcwd
505 startdir = os.getcwd()
505 startdir = os.getcwd()
506 ipdir = os.path.realpath(_ip.ipython_dir)
506 ipdir = os.path.realpath(_ip.ipython_dir)
507 try:
507 try:
508 _ip.magic('cd "%s"' % ipdir)
508 _ip.magic('cd "%s"' % ipdir)
509 assert curpath() == ipdir
509 assert curpath() == ipdir
510 _ip.magic('cd -')
510 _ip.magic('cd -')
511 assert curpath() == startdir
511 assert curpath() == startdir
512 _ip.magic('pushd "%s"' % ipdir)
512 _ip.magic('pushd "%s"' % ipdir)
513 assert curpath() == ipdir
513 assert curpath() == ipdir
514 _ip.magic('popd')
514 _ip.magic('popd')
515 assert curpath() == startdir
515 assert curpath() == startdir
516 finally:
516 finally:
517 os.chdir(startdir)
517 os.chdir(startdir)
518
518
519
519
520 def test_cd_force_quiet():
520 def test_cd_force_quiet():
521 """Test OSMagics.cd_force_quiet option"""
521 """Test OSMagics.cd_force_quiet option"""
522 _ip.config.OSMagics.cd_force_quiet = True
522 _ip.config.OSMagics.cd_force_quiet = True
523 osmagics = osm.OSMagics(shell=_ip)
523 osmagics = osm.OSMagics(shell=_ip)
524
524
525 startdir = os.getcwd()
525 startdir = os.getcwd()
526 ipdir = os.path.realpath(_ip.ipython_dir)
526 ipdir = os.path.realpath(_ip.ipython_dir)
527
527
528 try:
528 try:
529 with tt.AssertNotPrints(ipdir):
529 with tt.AssertNotPrints(ipdir):
530 osmagics.cd('"%s"' % ipdir)
530 osmagics.cd('"%s"' % ipdir)
531 with tt.AssertNotPrints(startdir):
531 with tt.AssertNotPrints(startdir):
532 osmagics.cd('-')
532 osmagics.cd('-')
533 finally:
533 finally:
534 os.chdir(startdir)
534 os.chdir(startdir)
535
535
536
536
537 def test_xmode():
537 def test_xmode():
538 # Calling xmode three times should be a no-op
538 # Calling xmode three times should be a no-op
539 xmode = _ip.InteractiveTB.mode
539 xmode = _ip.InteractiveTB.mode
540 for i in range(4):
540 for i in range(4):
541 _ip.magic("xmode")
541 _ip.magic("xmode")
542 assert _ip.InteractiveTB.mode == xmode
542 assert _ip.InteractiveTB.mode == xmode
543
543
544 def test_reset_hard():
544 def test_reset_hard():
545 monitor = []
545 monitor = []
546 class A(object):
546 class A(object):
547 def __del__(self):
547 def __del__(self):
548 monitor.append(1)
548 monitor.append(1)
549 def __repr__(self):
549 def __repr__(self):
550 return "<A instance>"
550 return "<A instance>"
551
551
552 _ip.user_ns["a"] = A()
552 _ip.user_ns["a"] = A()
553 _ip.run_cell("a")
553 _ip.run_cell("a")
554
554
555 assert monitor == []
555 assert monitor == []
556 _ip.magic("reset -f")
556 _ip.magic("reset -f")
557 assert monitor == [1]
557 assert monitor == [1]
558
558
559 class TestXdel(tt.TempFileMixin):
559 class TestXdel(tt.TempFileMixin):
560 def test_xdel(self):
560 def test_xdel(self):
561 """Test that references from %run are cleared by xdel."""
561 """Test that references from %run are cleared by xdel."""
562 src = ("class A(object):\n"
562 src = ("class A(object):\n"
563 " monitor = []\n"
563 " monitor = []\n"
564 " def __del__(self):\n"
564 " def __del__(self):\n"
565 " self.monitor.append(1)\n"
565 " self.monitor.append(1)\n"
566 "a = A()\n")
566 "a = A()\n")
567 self.mktmp(src)
567 self.mktmp(src)
568 # %run creates some hidden references...
568 # %run creates some hidden references...
569 _ip.magic("run %s" % self.fname)
569 _ip.magic("run %s" % self.fname)
570 # ... as does the displayhook.
570 # ... as does the displayhook.
571 _ip.run_cell("a")
571 _ip.run_cell("a")
572
572
573 monitor = _ip.user_ns["A"].monitor
573 monitor = _ip.user_ns["A"].monitor
574 assert monitor == []
574 assert monitor == []
575
575
576 _ip.magic("xdel a")
576 _ip.magic("xdel a")
577
577
578 # Check that a's __del__ method has been called.
578 # Check that a's __del__ method has been called.
579 assert monitor == [1]
579 assert monitor == [1]
580
580
581 def doctest_who():
581 def doctest_who():
582 """doctest for %who
582 """doctest for %who
583
583
584 In [1]: %reset -sf
584 In [1]: %reset -sf
585
585
586 In [2]: alpha = 123
586 In [2]: alpha = 123
587
587
588 In [3]: beta = 'beta'
588 In [3]: beta = 'beta'
589
589
590 In [4]: %who int
590 In [4]: %who int
591 alpha
591 alpha
592
592
593 In [5]: %who str
593 In [5]: %who str
594 beta
594 beta
595
595
596 In [6]: %whos
596 In [6]: %whos
597 Variable Type Data/Info
597 Variable Type Data/Info
598 ----------------------------
598 ----------------------------
599 alpha int 123
599 alpha int 123
600 beta str beta
600 beta str beta
601
601
602 In [7]: %who_ls
602 In [7]: %who_ls
603 Out[7]: ['alpha', 'beta']
603 Out[7]: ['alpha', 'beta']
604 """
604 """
605
605
606 def test_whos():
606 def test_whos():
607 """Check that whos is protected against objects where repr() fails."""
607 """Check that whos is protected against objects where repr() fails."""
608 class A(object):
608 class A(object):
609 def __repr__(self):
609 def __repr__(self):
610 raise Exception()
610 raise Exception()
611 _ip.user_ns['a'] = A()
611 _ip.user_ns['a'] = A()
612 _ip.magic("whos")
612 _ip.magic("whos")
613
613
614 def doctest_precision():
614 def doctest_precision():
615 """doctest for %precision
615 """doctest for %precision
616
616
617 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
617 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
618
618
619 In [2]: %precision 5
619 In [2]: %precision 5
620 Out[2]: '%.5f'
620 Out[2]: '%.5f'
621
621
622 In [3]: f.float_format
622 In [3]: f.float_format
623 Out[3]: '%.5f'
623 Out[3]: '%.5f'
624
624
625 In [4]: %precision %e
625 In [4]: %precision %e
626 Out[4]: '%e'
626 Out[4]: '%e'
627
627
628 In [5]: f(3.1415927)
628 In [5]: f(3.1415927)
629 Out[5]: '3.141593e+00'
629 Out[5]: '3.141593e+00'
630 """
630 """
631
631
632 def test_debug_magic():
632 def test_debug_magic():
633 """Test debugging a small code with %debug
633 """Test debugging a small code with %debug
634
634
635 In [1]: with PdbTestInput(['c']):
635 In [1]: with PdbTestInput(['c']):
636 ...: %debug print("a b") #doctest: +ELLIPSIS
636 ...: %debug print("a b") #doctest: +ELLIPSIS
637 ...:
637 ...:
638 ...
638 ...
639 ipdb> c
639 ipdb> c
640 a b
640 a b
641 In [2]:
641 In [2]:
642 """
642 """
643
643
644 def test_psearch():
644 def test_psearch():
645 with tt.AssertPrints("dict.fromkeys"):
645 with tt.AssertPrints("dict.fromkeys"):
646 _ip.run_cell("dict.fr*?")
646 _ip.run_cell("dict.fr*?")
647 with tt.AssertPrints("Ο€.is_integer"):
647 with tt.AssertPrints("Ο€.is_integer"):
648 _ip.run_cell("Ο€ = 3.14;\nΟ€.is_integ*?")
648 _ip.run_cell("Ο€ = 3.14;\nΟ€.is_integ*?")
649
649
650 def test_timeit_shlex():
650 def test_timeit_shlex():
651 """test shlex issues with timeit (#1109)"""
651 """test shlex issues with timeit (#1109)"""
652 _ip.ex("def f(*a,**kw): pass")
652 _ip.ex("def f(*a,**kw): pass")
653 _ip.magic('timeit -n1 "this is a bug".count(" ")')
653 _ip.magic('timeit -n1 "this is a bug".count(" ")')
654 _ip.magic('timeit -r1 -n1 f(" ", 1)')
654 _ip.magic('timeit -r1 -n1 f(" ", 1)')
655 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
655 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
656 _ip.magic('timeit -r1 -n1 ("a " + "b")')
656 _ip.magic('timeit -r1 -n1 ("a " + "b")')
657 _ip.magic('timeit -r1 -n1 f("a " + "b")')
657 _ip.magic('timeit -r1 -n1 f("a " + "b")')
658 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
658 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
659
659
660
660
661 def test_timeit_special_syntax():
661 def test_timeit_special_syntax():
662 "Test %%timeit with IPython special syntax"
662 "Test %%timeit with IPython special syntax"
663 @register_line_magic
663 @register_line_magic
664 def lmagic(line):
664 def lmagic(line):
665 ip = get_ipython()
665 ip = get_ipython()
666 ip.user_ns['lmagic_out'] = line
666 ip.user_ns['lmagic_out'] = line
667
667
668 # line mode test
668 # line mode test
669 _ip.run_line_magic("timeit", "-n1 -r1 %lmagic my line")
669 _ip.run_line_magic("timeit", "-n1 -r1 %lmagic my line")
670 assert _ip.user_ns["lmagic_out"] == "my line"
670 assert _ip.user_ns["lmagic_out"] == "my line"
671 # cell mode test
671 # cell mode test
672 _ip.run_cell_magic("timeit", "-n1 -r1", "%lmagic my line2")
672 _ip.run_cell_magic("timeit", "-n1 -r1", "%lmagic my line2")
673 assert _ip.user_ns["lmagic_out"] == "my line2"
673 assert _ip.user_ns["lmagic_out"] == "my line2"
674
674
675
675
676 def test_timeit_return():
676 def test_timeit_return():
677 """
677 """
678 test whether timeit -o return object
678 test whether timeit -o return object
679 """
679 """
680
680
681 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
681 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
682 assert(res is not None)
682 assert(res is not None)
683
683
684 def test_timeit_quiet():
684 def test_timeit_quiet():
685 """
685 """
686 test quiet option of timeit magic
686 test quiet option of timeit magic
687 """
687 """
688 with tt.AssertNotPrints("loops"):
688 with tt.AssertNotPrints("loops"):
689 _ip.run_cell("%timeit -n1 -r1 -q 1")
689 _ip.run_cell("%timeit -n1 -r1 -q 1")
690
690
691 def test_timeit_return_quiet():
691 def test_timeit_return_quiet():
692 with tt.AssertNotPrints("loops"):
692 with tt.AssertNotPrints("loops"):
693 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
693 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
694 assert (res is not None)
694 assert (res is not None)
695
695
696 def test_timeit_invalid_return():
696 def test_timeit_invalid_return():
697 with pytest.raises(SyntaxError):
697 with pytest.raises(SyntaxError):
698 _ip.run_line_magic('timeit', 'return')
698 _ip.run_line_magic('timeit', 'return')
699
699
700 @dec.skipif(execution.profile is None)
700 @dec.skipif(execution.profile is None)
701 def test_prun_special_syntax():
701 def test_prun_special_syntax():
702 "Test %%prun with IPython special syntax"
702 "Test %%prun with IPython special syntax"
703 @register_line_magic
703 @register_line_magic
704 def lmagic(line):
704 def lmagic(line):
705 ip = get_ipython()
705 ip = get_ipython()
706 ip.user_ns['lmagic_out'] = line
706 ip.user_ns['lmagic_out'] = line
707
707
708 # line mode test
708 # line mode test
709 _ip.run_line_magic("prun", "-q %lmagic my line")
709 _ip.run_line_magic("prun", "-q %lmagic my line")
710 assert _ip.user_ns["lmagic_out"] == "my line"
710 assert _ip.user_ns["lmagic_out"] == "my line"
711 # cell mode test
711 # cell mode test
712 _ip.run_cell_magic("prun", "-q", "%lmagic my line2")
712 _ip.run_cell_magic("prun", "-q", "%lmagic my line2")
713 assert _ip.user_ns["lmagic_out"] == "my line2"
713 assert _ip.user_ns["lmagic_out"] == "my line2"
714
714
715
715
716 @dec.skipif(execution.profile is None)
716 @dec.skipif(execution.profile is None)
717 def test_prun_quotes():
717 def test_prun_quotes():
718 "Test that prun does not clobber string escapes (GH #1302)"
718 "Test that prun does not clobber string escapes (GH #1302)"
719 _ip.magic(r"prun -q x = '\t'")
719 _ip.magic(r"prun -q x = '\t'")
720 assert _ip.user_ns["x"] == "\t"
720 assert _ip.user_ns["x"] == "\t"
721
721
722
722
723 def test_extension():
723 def test_extension():
724 # Debugging information for failures of this test
724 # Debugging information for failures of this test
725 print('sys.path:')
725 print('sys.path:')
726 for p in sys.path:
726 for p in sys.path:
727 print(' ', p)
727 print(' ', p)
728 print('CWD', os.getcwd())
728 print('CWD', os.getcwd())
729
729
730 pytest.raises(ImportError, _ip.magic, "load_ext daft_extension")
730 pytest.raises(ImportError, _ip.magic, "load_ext daft_extension")
731 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
731 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
732 sys.path.insert(0, daft_path)
732 sys.path.insert(0, daft_path)
733 try:
733 try:
734 _ip.user_ns.pop('arq', None)
734 _ip.user_ns.pop('arq', None)
735 invalidate_caches() # Clear import caches
735 invalidate_caches() # Clear import caches
736 _ip.magic("load_ext daft_extension")
736 _ip.magic("load_ext daft_extension")
737 assert _ip.user_ns["arq"] == 185
737 assert _ip.user_ns["arq"] == 185
738 _ip.magic("unload_ext daft_extension")
738 _ip.magic("unload_ext daft_extension")
739 assert 'arq' not in _ip.user_ns
739 assert 'arq' not in _ip.user_ns
740 finally:
740 finally:
741 sys.path.remove(daft_path)
741 sys.path.remove(daft_path)
742
742
743
743
744 def test_notebook_export_json():
744 def test_notebook_export_json():
745 _ip = get_ipython()
745 _ip = get_ipython()
746 _ip.history_manager.reset() # Clear any existing history.
746 _ip.history_manager.reset() # Clear any existing history.
747 cmds = ["a=1", "def b():\n return a**2", "print('noΓ«l, Γ©tΓ©', b())"]
747 cmds = ["a=1", "def b():\n return a**2", "print('noΓ«l, Γ©tΓ©', b())"]
748 for i, cmd in enumerate(cmds, start=1):
748 for i, cmd in enumerate(cmds, start=1):
749 _ip.history_manager.store_inputs(i, cmd)
749 _ip.history_manager.store_inputs(i, cmd)
750 with TemporaryDirectory() as td:
750 with TemporaryDirectory() as td:
751 outfile = os.path.join(td, "nb.ipynb")
751 outfile = os.path.join(td, "nb.ipynb")
752 _ip.magic("notebook -e %s" % outfile)
752 _ip.magic("notebook -e %s" % outfile)
753
753
754
754
755 class TestEnv(TestCase):
755 class TestEnv(TestCase):
756
756
757 def test_env(self):
757 def test_env(self):
758 env = _ip.magic("env")
758 env = _ip.magic("env")
759 self.assertTrue(isinstance(env, dict))
759 self.assertTrue(isinstance(env, dict))
760
760
761 def test_env_secret(self):
761 def test_env_secret(self):
762 env = _ip.magic("env")
762 env = _ip.magic("env")
763 hidden = "<hidden>"
763 hidden = "<hidden>"
764 with mock.patch.dict(
764 with mock.patch.dict(
765 os.environ,
765 os.environ,
766 {
766 {
767 "API_KEY": "abc123",
767 "API_KEY": "abc123",
768 "SECRET_THING": "ssshhh",
768 "SECRET_THING": "ssshhh",
769 "JUPYTER_TOKEN": "",
769 "JUPYTER_TOKEN": "",
770 "VAR": "abc"
770 "VAR": "abc"
771 }
771 }
772 ):
772 ):
773 env = _ip.magic("env")
773 env = _ip.magic("env")
774 assert env["API_KEY"] == hidden
774 assert env["API_KEY"] == hidden
775 assert env["SECRET_THING"] == hidden
775 assert env["SECRET_THING"] == hidden
776 assert env["JUPYTER_TOKEN"] == hidden
776 assert env["JUPYTER_TOKEN"] == hidden
777 assert env["VAR"] == "abc"
777 assert env["VAR"] == "abc"
778
778
779 def test_env_get_set_simple(self):
779 def test_env_get_set_simple(self):
780 env = _ip.magic("env var val1")
780 env = _ip.magic("env var val1")
781 self.assertEqual(env, None)
781 self.assertEqual(env, None)
782 self.assertEqual(os.environ['var'], 'val1')
782 self.assertEqual(os.environ['var'], 'val1')
783 self.assertEqual(_ip.magic("env var"), 'val1')
783 self.assertEqual(_ip.magic("env var"), 'val1')
784 env = _ip.magic("env var=val2")
784 env = _ip.magic("env var=val2")
785 self.assertEqual(env, None)
785 self.assertEqual(env, None)
786 self.assertEqual(os.environ['var'], 'val2')
786 self.assertEqual(os.environ['var'], 'val2')
787
787
788 def test_env_get_set_complex(self):
788 def test_env_get_set_complex(self):
789 env = _ip.magic("env var 'val1 '' 'val2")
789 env = _ip.magic("env var 'val1 '' 'val2")
790 self.assertEqual(env, None)
790 self.assertEqual(env, None)
791 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
791 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
792 self.assertEqual(_ip.magic("env var"), "'val1 '' 'val2")
792 self.assertEqual(_ip.magic("env var"), "'val1 '' 'val2")
793 env = _ip.magic('env var=val2 val3="val4')
793 env = _ip.magic('env var=val2 val3="val4')
794 self.assertEqual(env, None)
794 self.assertEqual(env, None)
795 self.assertEqual(os.environ['var'], 'val2 val3="val4')
795 self.assertEqual(os.environ['var'], 'val2 val3="val4')
796
796
797 def test_env_set_bad_input(self):
797 def test_env_set_bad_input(self):
798 self.assertRaises(UsageError, lambda: _ip.magic("set_env var"))
798 self.assertRaises(UsageError, lambda: _ip.magic("set_env var"))
799
799
800 def test_env_set_whitespace(self):
800 def test_env_set_whitespace(self):
801 self.assertRaises(UsageError, lambda: _ip.magic("env var A=B"))
801 self.assertRaises(UsageError, lambda: _ip.magic("env var A=B"))
802
802
803
803
804 class CellMagicTestCase(TestCase):
804 class CellMagicTestCase(TestCase):
805
805
806 def check_ident(self, magic):
806 def check_ident(self, magic):
807 # Manually called, we get the result
807 # Manually called, we get the result
808 out = _ip.run_cell_magic(magic, "a", "b")
808 out = _ip.run_cell_magic(magic, "a", "b")
809 assert out == ("a", "b")
809 assert out == ("a", "b")
810 # Via run_cell, it goes into the user's namespace via displayhook
810 # Via run_cell, it goes into the user's namespace via displayhook
811 _ip.run_cell("%%" + magic + " c\nd\n")
811 _ip.run_cell("%%" + magic + " c\nd\n")
812 assert _ip.user_ns["_"] == ("c", "d\n")
812 assert _ip.user_ns["_"] == ("c", "d\n")
813
813
814 def test_cell_magic_func_deco(self):
814 def test_cell_magic_func_deco(self):
815 "Cell magic using simple decorator"
815 "Cell magic using simple decorator"
816 @register_cell_magic
816 @register_cell_magic
817 def cellm(line, cell):
817 def cellm(line, cell):
818 return line, cell
818 return line, cell
819
819
820 self.check_ident('cellm')
820 self.check_ident('cellm')
821
821
822 def test_cell_magic_reg(self):
822 def test_cell_magic_reg(self):
823 "Cell magic manually registered"
823 "Cell magic manually registered"
824 def cellm(line, cell):
824 def cellm(line, cell):
825 return line, cell
825 return line, cell
826
826
827 _ip.register_magic_function(cellm, 'cell', 'cellm2')
827 _ip.register_magic_function(cellm, 'cell', 'cellm2')
828 self.check_ident('cellm2')
828 self.check_ident('cellm2')
829
829
830 def test_cell_magic_class(self):
830 def test_cell_magic_class(self):
831 "Cell magics declared via a class"
831 "Cell magics declared via a class"
832 @magics_class
832 @magics_class
833 class MyMagics(Magics):
833 class MyMagics(Magics):
834
834
835 @cell_magic
835 @cell_magic
836 def cellm3(self, line, cell):
836 def cellm3(self, line, cell):
837 return line, cell
837 return line, cell
838
838
839 _ip.register_magics(MyMagics)
839 _ip.register_magics(MyMagics)
840 self.check_ident('cellm3')
840 self.check_ident('cellm3')
841
841
842 def test_cell_magic_class2(self):
842 def test_cell_magic_class2(self):
843 "Cell magics declared via a class, #2"
843 "Cell magics declared via a class, #2"
844 @magics_class
844 @magics_class
845 class MyMagics2(Magics):
845 class MyMagics2(Magics):
846
846
847 @cell_magic('cellm4')
847 @cell_magic('cellm4')
848 def cellm33(self, line, cell):
848 def cellm33(self, line, cell):
849 return line, cell
849 return line, cell
850
850
851 _ip.register_magics(MyMagics2)
851 _ip.register_magics(MyMagics2)
852 self.check_ident('cellm4')
852 self.check_ident('cellm4')
853 # Check that nothing is registered as 'cellm33'
853 # Check that nothing is registered as 'cellm33'
854 c33 = _ip.find_cell_magic('cellm33')
854 c33 = _ip.find_cell_magic('cellm33')
855 assert c33 == None
855 assert c33 == None
856
856
857 def test_file():
857 def test_file():
858 """Basic %%writefile"""
858 """Basic %%writefile"""
859 ip = get_ipython()
859 ip = get_ipython()
860 with TemporaryDirectory() as td:
860 with TemporaryDirectory() as td:
861 fname = os.path.join(td, 'file1')
861 fname = os.path.join(td, 'file1')
862 ip.run_cell_magic("writefile", fname, u'\n'.join([
862 ip.run_cell_magic("writefile", fname, u'\n'.join([
863 'line1',
863 'line1',
864 'line2',
864 'line2',
865 ]))
865 ]))
866 s = Path(fname).read_text()
866 s = Path(fname).read_text()
867 assert "line1\n" in s
867 assert "line1\n" in s
868 assert "line2" in s
868 assert "line2" in s
869
869
870
870
871 @dec.skip_win32
871 @dec.skip_win32
872 def test_file_single_quote():
872 def test_file_single_quote():
873 """Basic %%writefile with embedded single quotes"""
873 """Basic %%writefile with embedded single quotes"""
874 ip = get_ipython()
874 ip = get_ipython()
875 with TemporaryDirectory() as td:
875 with TemporaryDirectory() as td:
876 fname = os.path.join(td, '\'file1\'')
876 fname = os.path.join(td, '\'file1\'')
877 ip.run_cell_magic("writefile", fname, u'\n'.join([
877 ip.run_cell_magic("writefile", fname, u'\n'.join([
878 'line1',
878 'line1',
879 'line2',
879 'line2',
880 ]))
880 ]))
881 s = Path(fname).read_text()
881 s = Path(fname).read_text()
882 assert "line1\n" in s
882 assert "line1\n" in s
883 assert "line2" in s
883 assert "line2" in s
884
884
885
885
886 @dec.skip_win32
886 @dec.skip_win32
887 def test_file_double_quote():
887 def test_file_double_quote():
888 """Basic %%writefile with embedded double quotes"""
888 """Basic %%writefile with embedded double quotes"""
889 ip = get_ipython()
889 ip = get_ipython()
890 with TemporaryDirectory() as td:
890 with TemporaryDirectory() as td:
891 fname = os.path.join(td, '"file1"')
891 fname = os.path.join(td, '"file1"')
892 ip.run_cell_magic("writefile", fname, u'\n'.join([
892 ip.run_cell_magic("writefile", fname, u'\n'.join([
893 'line1',
893 'line1',
894 'line2',
894 'line2',
895 ]))
895 ]))
896 s = Path(fname).read_text()
896 s = Path(fname).read_text()
897 assert "line1\n" in s
897 assert "line1\n" in s
898 assert "line2" in s
898 assert "line2" in s
899
899
900
900
901 def test_file_var_expand():
901 def test_file_var_expand():
902 """%%writefile $filename"""
902 """%%writefile $filename"""
903 ip = get_ipython()
903 ip = get_ipython()
904 with TemporaryDirectory() as td:
904 with TemporaryDirectory() as td:
905 fname = os.path.join(td, 'file1')
905 fname = os.path.join(td, 'file1')
906 ip.user_ns['filename'] = fname
906 ip.user_ns['filename'] = fname
907 ip.run_cell_magic("writefile", '$filename', u'\n'.join([
907 ip.run_cell_magic("writefile", '$filename', u'\n'.join([
908 'line1',
908 'line1',
909 'line2',
909 'line2',
910 ]))
910 ]))
911 s = Path(fname).read_text()
911 s = Path(fname).read_text()
912 assert "line1\n" in s
912 assert "line1\n" in s
913 assert "line2" in s
913 assert "line2" in s
914
914
915
915
916 def test_file_unicode():
916 def test_file_unicode():
917 """%%writefile with unicode cell"""
917 """%%writefile with unicode cell"""
918 ip = get_ipython()
918 ip = get_ipython()
919 with TemporaryDirectory() as td:
919 with TemporaryDirectory() as td:
920 fname = os.path.join(td, 'file1')
920 fname = os.path.join(td, 'file1')
921 ip.run_cell_magic("writefile", fname, u'\n'.join([
921 ip.run_cell_magic("writefile", fname, u'\n'.join([
922 u'linΓ©1',
922 u'linΓ©1',
923 u'linΓ©2',
923 u'linΓ©2',
924 ]))
924 ]))
925 with io.open(fname, encoding='utf-8') as f:
925 with io.open(fname, encoding='utf-8') as f:
926 s = f.read()
926 s = f.read()
927 assert "linΓ©1\n" in s
927 assert "linΓ©1\n" in s
928 assert "linΓ©2" in s
928 assert "linΓ©2" in s
929
929
930
930
931 def test_file_amend():
931 def test_file_amend():
932 """%%writefile -a amends files"""
932 """%%writefile -a amends files"""
933 ip = get_ipython()
933 ip = get_ipython()
934 with TemporaryDirectory() as td:
934 with TemporaryDirectory() as td:
935 fname = os.path.join(td, 'file2')
935 fname = os.path.join(td, 'file2')
936 ip.run_cell_magic("writefile", fname, u'\n'.join([
936 ip.run_cell_magic("writefile", fname, u'\n'.join([
937 'line1',
937 'line1',
938 'line2',
938 'line2',
939 ]))
939 ]))
940 ip.run_cell_magic("writefile", "-a %s" % fname, u'\n'.join([
940 ip.run_cell_magic("writefile", "-a %s" % fname, u'\n'.join([
941 'line3',
941 'line3',
942 'line4',
942 'line4',
943 ]))
943 ]))
944 s = Path(fname).read_text()
944 s = Path(fname).read_text()
945 assert "line1\n" in s
945 assert "line1\n" in s
946 assert "line3\n" in s
946 assert "line3\n" in s
947
947
948
948
949 def test_file_spaces():
949 def test_file_spaces():
950 """%%file with spaces in filename"""
950 """%%file with spaces in filename"""
951 ip = get_ipython()
951 ip = get_ipython()
952 with TemporaryWorkingDirectory() as td:
952 with TemporaryWorkingDirectory() as td:
953 fname = "file name"
953 fname = "file name"
954 ip.run_cell_magic("file", '"%s"'%fname, u'\n'.join([
954 ip.run_cell_magic("file", '"%s"'%fname, u'\n'.join([
955 'line1',
955 'line1',
956 'line2',
956 'line2',
957 ]))
957 ]))
958 s = Path(fname).read_text()
958 s = Path(fname).read_text()
959 assert "line1\n" in s
959 assert "line1\n" in s
960 assert "line2" in s
960 assert "line2" in s
961
961
962
962
963 def test_script_config():
963 def test_script_config():
964 ip = get_ipython()
964 ip = get_ipython()
965 ip.config.ScriptMagics.script_magics = ['whoda']
965 ip.config.ScriptMagics.script_magics = ['whoda']
966 sm = script.ScriptMagics(shell=ip)
966 sm = script.ScriptMagics(shell=ip)
967 assert "whoda" in sm.magics["cell"]
967 assert "whoda" in sm.magics["cell"]
968
968
969
969
970 @pytest.fixture
970 @pytest.fixture
971 def event_loop():
971 def event_loop():
972 yield asyncio.get_event_loop_policy().get_event_loop()
972 yield asyncio.get_event_loop_policy().get_event_loop()
973
973
974
974
975 @dec.skip_iptest_but_not_pytest
976 @dec.skip_win32
975 @dec.skip_win32
977 @pytest.mark.skipif(
976 @pytest.mark.skipif(
978 sys.platform == "win32", reason="This test does not run under Windows"
977 sys.platform == "win32", reason="This test does not run under Windows"
979 )
978 )
980 def test_script_out(event_loop):
979 def test_script_out(event_loop):
981 assert event_loop.is_running() is False
980 assert event_loop.is_running() is False
982
981
983 ip = get_ipython()
982 ip = get_ipython()
984 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
983 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
985 assert event_loop.is_running() is False
984 assert event_loop.is_running() is False
986 assert ip.user_ns["output"] == "hi\n"
985 assert ip.user_ns["output"] == "hi\n"
987
986
988
987
989 @dec.skip_iptest_but_not_pytest
990 @dec.skip_win32
988 @dec.skip_win32
991 @pytest.mark.skipif(
989 @pytest.mark.skipif(
992 sys.platform == "win32", reason="This test does not run under Windows"
990 sys.platform == "win32", reason="This test does not run under Windows"
993 )
991 )
994 def test_script_err(event_loop):
992 def test_script_err(event_loop):
995 ip = get_ipython()
993 ip = get_ipython()
996 assert event_loop.is_running() is False
994 assert event_loop.is_running() is False
997 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
995 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
998 assert event_loop.is_running() is False
996 assert event_loop.is_running() is False
999 assert ip.user_ns["error"] == "hello\n"
997 assert ip.user_ns["error"] == "hello\n"
1000
998
1001
999
1002 @dec.skip_iptest_but_not_pytest
1003 @dec.skip_win32
1000 @dec.skip_win32
1004 @pytest.mark.skipif(
1001 @pytest.mark.skipif(
1005 sys.platform == "win32", reason="This test does not run under Windows"
1002 sys.platform == "win32", reason="This test does not run under Windows"
1006 )
1003 )
1007 def test_script_out_err():
1004 def test_script_out_err():
1008
1005
1009 ip = get_ipython()
1006 ip = get_ipython()
1010 ip.run_cell_magic(
1007 ip.run_cell_magic(
1011 "script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2"
1008 "script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2"
1012 )
1009 )
1013 assert ip.user_ns["output"] == "hi\n"
1010 assert ip.user_ns["output"] == "hi\n"
1014 assert ip.user_ns["error"] == "hello\n"
1011 assert ip.user_ns["error"] == "hello\n"
1015
1012
1016
1013
1017 @dec.skip_iptest_but_not_pytest
1018 @dec.skip_win32
1014 @dec.skip_win32
1019 @pytest.mark.skipif(
1015 @pytest.mark.skipif(
1020 sys.platform == "win32", reason="This test does not run under Windows"
1016 sys.platform == "win32", reason="This test does not run under Windows"
1021 )
1017 )
1022 async def test_script_bg_out(event_loop):
1018 async def test_script_bg_out(event_loop):
1023 ip = get_ipython()
1019 ip = get_ipython()
1024 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
1020 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
1025 assert (await ip.user_ns["output"].read()) == b"hi\n"
1021 assert (await ip.user_ns["output"].read()) == b"hi\n"
1026 ip.user_ns["output"].close()
1022 ip.user_ns["output"].close()
1027 event_loop.stop()
1023 event_loop.stop()
1028
1024
1029
1025
1030 @dec.skip_iptest_but_not_pytest
1031 @dec.skip_win32
1026 @dec.skip_win32
1032 @pytest.mark.skipif(
1027 @pytest.mark.skipif(
1033 sys.platform == "win32", reason="This test does not run under Windows"
1028 sys.platform == "win32", reason="This test does not run under Windows"
1034 )
1029 )
1035 async def test_script_bg_err():
1030 async def test_script_bg_err():
1036 ip = get_ipython()
1031 ip = get_ipython()
1037 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
1032 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
1038 assert (await ip.user_ns["error"].read()) == b"hello\n"
1033 assert (await ip.user_ns["error"].read()) == b"hello\n"
1039 ip.user_ns["error"].close()
1034 ip.user_ns["error"].close()
1040
1035
1041
1036
1042 @dec.skip_iptest_but_not_pytest
1043 @dec.skip_win32
1037 @dec.skip_win32
1044 @pytest.mark.skipif(
1038 @pytest.mark.skipif(
1045 sys.platform == "win32", reason="This test does not run under Windows"
1039 sys.platform == "win32", reason="This test does not run under Windows"
1046 )
1040 )
1047 async def test_script_bg_out_err():
1041 async def test_script_bg_out_err():
1048 ip = get_ipython()
1042 ip = get_ipython()
1049 ip.run_cell_magic(
1043 ip.run_cell_magic(
1050 "script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2"
1044 "script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2"
1051 )
1045 )
1052 assert (await ip.user_ns["output"].read()) == b"hi\n"
1046 assert (await ip.user_ns["output"].read()) == b"hi\n"
1053 assert (await ip.user_ns["error"].read()) == b"hello\n"
1047 assert (await ip.user_ns["error"].read()) == b"hello\n"
1054 ip.user_ns["output"].close()
1048 ip.user_ns["output"].close()
1055 ip.user_ns["error"].close()
1049 ip.user_ns["error"].close()
1056
1050
1057
1051
1058 def test_script_defaults():
1052 def test_script_defaults():
1059 ip = get_ipython()
1053 ip = get_ipython()
1060 for cmd in ['sh', 'bash', 'perl', 'ruby']:
1054 for cmd in ['sh', 'bash', 'perl', 'ruby']:
1061 try:
1055 try:
1062 find_cmd(cmd)
1056 find_cmd(cmd)
1063 except Exception:
1057 except Exception:
1064 pass
1058 pass
1065 else:
1059 else:
1066 assert cmd in ip.magics_manager.magics["cell"]
1060 assert cmd in ip.magics_manager.magics["cell"]
1067
1061
1068
1062
1069 @magics_class
1063 @magics_class
1070 class FooFoo(Magics):
1064 class FooFoo(Magics):
1071 """class with both %foo and %%foo magics"""
1065 """class with both %foo and %%foo magics"""
1072 @line_magic('foo')
1066 @line_magic('foo')
1073 def line_foo(self, line):
1067 def line_foo(self, line):
1074 "I am line foo"
1068 "I am line foo"
1075 pass
1069 pass
1076
1070
1077 @cell_magic("foo")
1071 @cell_magic("foo")
1078 def cell_foo(self, line, cell):
1072 def cell_foo(self, line, cell):
1079 "I am cell foo, not line foo"
1073 "I am cell foo, not line foo"
1080 pass
1074 pass
1081
1075
1082 def test_line_cell_info():
1076 def test_line_cell_info():
1083 """%%foo and %foo magics are distinguishable to inspect"""
1077 """%%foo and %foo magics are distinguishable to inspect"""
1084 ip = get_ipython()
1078 ip = get_ipython()
1085 ip.magics_manager.register(FooFoo)
1079 ip.magics_manager.register(FooFoo)
1086 oinfo = ip.object_inspect("foo")
1080 oinfo = ip.object_inspect("foo")
1087 assert oinfo["found"] is True
1081 assert oinfo["found"] is True
1088 assert oinfo["ismagic"] is True
1082 assert oinfo["ismagic"] is True
1089
1083
1090 oinfo = ip.object_inspect("%%foo")
1084 oinfo = ip.object_inspect("%%foo")
1091 assert oinfo["found"] is True
1085 assert oinfo["found"] is True
1092 assert oinfo["ismagic"] is True
1086 assert oinfo["ismagic"] is True
1093 assert oinfo["docstring"] == FooFoo.cell_foo.__doc__
1087 assert oinfo["docstring"] == FooFoo.cell_foo.__doc__
1094
1088
1095 oinfo = ip.object_inspect("%foo")
1089 oinfo = ip.object_inspect("%foo")
1096 assert oinfo["found"] is True
1090 assert oinfo["found"] is True
1097 assert oinfo["ismagic"] is True
1091 assert oinfo["ismagic"] is True
1098 assert oinfo["docstring"] == FooFoo.line_foo.__doc__
1092 assert oinfo["docstring"] == FooFoo.line_foo.__doc__
1099
1093
1100
1094
1101 def test_multiple_magics():
1095 def test_multiple_magics():
1102 ip = get_ipython()
1096 ip = get_ipython()
1103 foo1 = FooFoo(ip)
1097 foo1 = FooFoo(ip)
1104 foo2 = FooFoo(ip)
1098 foo2 = FooFoo(ip)
1105 mm = ip.magics_manager
1099 mm = ip.magics_manager
1106 mm.register(foo1)
1100 mm.register(foo1)
1107 assert mm.magics["line"]["foo"].__self__ is foo1
1101 assert mm.magics["line"]["foo"].__self__ is foo1
1108 mm.register(foo2)
1102 mm.register(foo2)
1109 assert mm.magics["line"]["foo"].__self__ is foo2
1103 assert mm.magics["line"]["foo"].__self__ is foo2
1110
1104
1111
1105
1112 def test_alias_magic():
1106 def test_alias_magic():
1113 """Test %alias_magic."""
1107 """Test %alias_magic."""
1114 ip = get_ipython()
1108 ip = get_ipython()
1115 mm = ip.magics_manager
1109 mm = ip.magics_manager
1116
1110
1117 # Basic operation: both cell and line magics are created, if possible.
1111 # Basic operation: both cell and line magics are created, if possible.
1118 ip.run_line_magic("alias_magic", "timeit_alias timeit")
1112 ip.run_line_magic("alias_magic", "timeit_alias timeit")
1119 assert "timeit_alias" in mm.magics["line"]
1113 assert "timeit_alias" in mm.magics["line"]
1120 assert "timeit_alias" in mm.magics["cell"]
1114 assert "timeit_alias" in mm.magics["cell"]
1121
1115
1122 # --cell is specified, line magic not created.
1116 # --cell is specified, line magic not created.
1123 ip.run_line_magic("alias_magic", "--cell timeit_cell_alias timeit")
1117 ip.run_line_magic("alias_magic", "--cell timeit_cell_alias timeit")
1124 assert "timeit_cell_alias" not in mm.magics["line"]
1118 assert "timeit_cell_alias" not in mm.magics["line"]
1125 assert "timeit_cell_alias" in mm.magics["cell"]
1119 assert "timeit_cell_alias" in mm.magics["cell"]
1126
1120
1127 # Test that line alias is created successfully.
1121 # Test that line alias is created successfully.
1128 ip.run_line_magic("alias_magic", "--line env_alias env")
1122 ip.run_line_magic("alias_magic", "--line env_alias env")
1129 assert ip.run_line_magic("env", "") == ip.run_line_magic("env_alias", "")
1123 assert ip.run_line_magic("env", "") == ip.run_line_magic("env_alias", "")
1130
1124
1131 # Test that line alias with parameters passed in is created successfully.
1125 # Test that line alias with parameters passed in is created successfully.
1132 ip.run_line_magic(
1126 ip.run_line_magic(
1133 "alias_magic", "--line history_alias history --params " + shlex.quote("3")
1127 "alias_magic", "--line history_alias history --params " + shlex.quote("3")
1134 )
1128 )
1135 assert "history_alias" in mm.magics["line"]
1129 assert "history_alias" in mm.magics["line"]
1136
1130
1137
1131
1138 def test_save():
1132 def test_save():
1139 """Test %save."""
1133 """Test %save."""
1140 ip = get_ipython()
1134 ip = get_ipython()
1141 ip.history_manager.reset() # Clear any existing history.
1135 ip.history_manager.reset() # Clear any existing history.
1142 cmds = ["a=1", "def b():\n return a**2", "print(a, b())"]
1136 cmds = ["a=1", "def b():\n return a**2", "print(a, b())"]
1143 for i, cmd in enumerate(cmds, start=1):
1137 for i, cmd in enumerate(cmds, start=1):
1144 ip.history_manager.store_inputs(i, cmd)
1138 ip.history_manager.store_inputs(i, cmd)
1145 with TemporaryDirectory() as tmpdir:
1139 with TemporaryDirectory() as tmpdir:
1146 file = os.path.join(tmpdir, "testsave.py")
1140 file = os.path.join(tmpdir, "testsave.py")
1147 ip.run_line_magic("save", "%s 1-10" % file)
1141 ip.run_line_magic("save", "%s 1-10" % file)
1148 content = Path(file).read_text()
1142 content = Path(file).read_text()
1149 assert content.count(cmds[0]) == 1
1143 assert content.count(cmds[0]) == 1
1150 assert "coding: utf-8" in content
1144 assert "coding: utf-8" in content
1151 ip.run_line_magic("save", "-a %s 1-10" % file)
1145 ip.run_line_magic("save", "-a %s 1-10" % file)
1152 content = Path(file).read_text()
1146 content = Path(file).read_text()
1153 assert content.count(cmds[0]) == 2
1147 assert content.count(cmds[0]) == 2
1154 assert "coding: utf-8" in content
1148 assert "coding: utf-8" in content
1155
1149
1156
1150
1157 def test_save_with_no_args():
1151 def test_save_with_no_args():
1158 ip = get_ipython()
1152 ip = get_ipython()
1159 ip.history_manager.reset() # Clear any existing history.
1153 ip.history_manager.reset() # Clear any existing history.
1160 cmds = ["a=1", "def b():\n return a**2", "print(a, b())", "%save"]
1154 cmds = ["a=1", "def b():\n return a**2", "print(a, b())", "%save"]
1161 for i, cmd in enumerate(cmds, start=1):
1155 for i, cmd in enumerate(cmds, start=1):
1162 ip.history_manager.store_inputs(i, cmd)
1156 ip.history_manager.store_inputs(i, cmd)
1163
1157
1164 with TemporaryDirectory() as tmpdir:
1158 with TemporaryDirectory() as tmpdir:
1165 path = os.path.join(tmpdir, "testsave.py")
1159 path = os.path.join(tmpdir, "testsave.py")
1166 ip.run_line_magic("save", path)
1160 ip.run_line_magic("save", path)
1167 content = Path(path).read_text()
1161 content = Path(path).read_text()
1168 expected_content = dedent(
1162 expected_content = dedent(
1169 """\
1163 """\
1170 # coding: utf-8
1164 # coding: utf-8
1171 a=1
1165 a=1
1172 def b():
1166 def b():
1173 return a**2
1167 return a**2
1174 print(a, b())
1168 print(a, b())
1175 """
1169 """
1176 )
1170 )
1177 assert content == expected_content
1171 assert content == expected_content
1178
1172
1179
1173
1180 def test_store():
1174 def test_store():
1181 """Test %store."""
1175 """Test %store."""
1182 ip = get_ipython()
1176 ip = get_ipython()
1183 ip.run_line_magic('load_ext', 'storemagic')
1177 ip.run_line_magic('load_ext', 'storemagic')
1184
1178
1185 # make sure the storage is empty
1179 # make sure the storage is empty
1186 ip.run_line_magic("store", "-z")
1180 ip.run_line_magic("store", "-z")
1187 ip.user_ns["var"] = 42
1181 ip.user_ns["var"] = 42
1188 ip.run_line_magic("store", "var")
1182 ip.run_line_magic("store", "var")
1189 ip.user_ns["var"] = 39
1183 ip.user_ns["var"] = 39
1190 ip.run_line_magic("store", "-r")
1184 ip.run_line_magic("store", "-r")
1191 assert ip.user_ns["var"] == 42
1185 assert ip.user_ns["var"] == 42
1192
1186
1193 ip.run_line_magic("store", "-d var")
1187 ip.run_line_magic("store", "-d var")
1194 ip.user_ns["var"] = 39
1188 ip.user_ns["var"] = 39
1195 ip.run_line_magic("store", "-r")
1189 ip.run_line_magic("store", "-r")
1196 assert ip.user_ns["var"] == 39
1190 assert ip.user_ns["var"] == 39
1197
1191
1198
1192
1199 def _run_edit_test(arg_s, exp_filename=None,
1193 def _run_edit_test(arg_s, exp_filename=None,
1200 exp_lineno=-1,
1194 exp_lineno=-1,
1201 exp_contents=None,
1195 exp_contents=None,
1202 exp_is_temp=None):
1196 exp_is_temp=None):
1203 ip = get_ipython()
1197 ip = get_ipython()
1204 M = code.CodeMagics(ip)
1198 M = code.CodeMagics(ip)
1205 last_call = ['','']
1199 last_call = ['','']
1206 opts,args = M.parse_options(arg_s,'prxn:')
1200 opts,args = M.parse_options(arg_s,'prxn:')
1207 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
1201 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
1208
1202
1209 if exp_filename is not None:
1203 if exp_filename is not None:
1210 assert exp_filename == filename
1204 assert exp_filename == filename
1211 if exp_contents is not None:
1205 if exp_contents is not None:
1212 with io.open(filename, 'r', encoding='utf-8') as f:
1206 with io.open(filename, 'r', encoding='utf-8') as f:
1213 contents = f.read()
1207 contents = f.read()
1214 assert exp_contents == contents
1208 assert exp_contents == contents
1215 if exp_lineno != -1:
1209 if exp_lineno != -1:
1216 assert exp_lineno == lineno
1210 assert exp_lineno == lineno
1217 if exp_is_temp is not None:
1211 if exp_is_temp is not None:
1218 assert exp_is_temp == is_temp
1212 assert exp_is_temp == is_temp
1219
1213
1220
1214
1221 def test_edit_interactive():
1215 def test_edit_interactive():
1222 """%edit on interactively defined objects"""
1216 """%edit on interactively defined objects"""
1223 ip = get_ipython()
1217 ip = get_ipython()
1224 n = ip.execution_count
1218 n = ip.execution_count
1225 ip.run_cell("def foo(): return 1", store_history=True)
1219 ip.run_cell("def foo(): return 1", store_history=True)
1226
1220
1227 with pytest.raises(code.InteractivelyDefined) as e:
1221 with pytest.raises(code.InteractivelyDefined) as e:
1228 _run_edit_test("foo")
1222 _run_edit_test("foo")
1229 assert e.value.index == n
1223 assert e.value.index == n
1230
1224
1231
1225
1232 def test_edit_cell():
1226 def test_edit_cell():
1233 """%edit [cell id]"""
1227 """%edit [cell id]"""
1234 ip = get_ipython()
1228 ip = get_ipython()
1235
1229
1236 ip.run_cell("def foo(): return 1", store_history=True)
1230 ip.run_cell("def foo(): return 1", store_history=True)
1237
1231
1238 # test
1232 # test
1239 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
1233 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
1240
1234
1241 def test_edit_fname():
1235 def test_edit_fname():
1242 """%edit file"""
1236 """%edit file"""
1243 # test
1237 # test
1244 _run_edit_test("test file.py", exp_filename="test file.py")
1238 _run_edit_test("test file.py", exp_filename="test file.py")
1245
1239
1246 def test_bookmark():
1240 def test_bookmark():
1247 ip = get_ipython()
1241 ip = get_ipython()
1248 ip.run_line_magic('bookmark', 'bmname')
1242 ip.run_line_magic('bookmark', 'bmname')
1249 with tt.AssertPrints('bmname'):
1243 with tt.AssertPrints('bmname'):
1250 ip.run_line_magic('bookmark', '-l')
1244 ip.run_line_magic('bookmark', '-l')
1251 ip.run_line_magic('bookmark', '-d bmname')
1245 ip.run_line_magic('bookmark', '-d bmname')
1252
1246
1253 def test_ls_magic():
1247 def test_ls_magic():
1254 ip = get_ipython()
1248 ip = get_ipython()
1255 json_formatter = ip.display_formatter.formatters['application/json']
1249 json_formatter = ip.display_formatter.formatters['application/json']
1256 json_formatter.enabled = True
1250 json_formatter.enabled = True
1257 lsmagic = ip.magic('lsmagic')
1251 lsmagic = ip.magic('lsmagic')
1258 with warnings.catch_warnings(record=True) as w:
1252 with warnings.catch_warnings(record=True) as w:
1259 j = json_formatter(lsmagic)
1253 j = json_formatter(lsmagic)
1260 assert sorted(j) == ["cell", "line"]
1254 assert sorted(j) == ["cell", "line"]
1261 assert w == [] # no warnings
1255 assert w == [] # no warnings
1262
1256
1263
1257
1264 def test_strip_initial_indent():
1258 def test_strip_initial_indent():
1265 def sii(s):
1259 def sii(s):
1266 lines = s.splitlines()
1260 lines = s.splitlines()
1267 return '\n'.join(code.strip_initial_indent(lines))
1261 return '\n'.join(code.strip_initial_indent(lines))
1268
1262
1269 assert sii(" a = 1\nb = 2") == "a = 1\nb = 2"
1263 assert sii(" a = 1\nb = 2") == "a = 1\nb = 2"
1270 assert sii(" a\n b\nc") == "a\n b\nc"
1264 assert sii(" a\n b\nc") == "a\n b\nc"
1271 assert sii("a\n b") == "a\n b"
1265 assert sii("a\n b") == "a\n b"
1272
1266
1273 def test_logging_magic_quiet_from_arg():
1267 def test_logging_magic_quiet_from_arg():
1274 _ip.config.LoggingMagics.quiet = False
1268 _ip.config.LoggingMagics.quiet = False
1275 lm = logging.LoggingMagics(shell=_ip)
1269 lm = logging.LoggingMagics(shell=_ip)
1276 with TemporaryDirectory() as td:
1270 with TemporaryDirectory() as td:
1277 try:
1271 try:
1278 with tt.AssertNotPrints(re.compile("Activating.*")):
1272 with tt.AssertNotPrints(re.compile("Activating.*")):
1279 lm.logstart('-q {}'.format(
1273 lm.logstart('-q {}'.format(
1280 os.path.join(td, "quiet_from_arg.log")))
1274 os.path.join(td, "quiet_from_arg.log")))
1281 finally:
1275 finally:
1282 _ip.logger.logstop()
1276 _ip.logger.logstop()
1283
1277
1284 def test_logging_magic_quiet_from_config():
1278 def test_logging_magic_quiet_from_config():
1285 _ip.config.LoggingMagics.quiet = True
1279 _ip.config.LoggingMagics.quiet = True
1286 lm = logging.LoggingMagics(shell=_ip)
1280 lm = logging.LoggingMagics(shell=_ip)
1287 with TemporaryDirectory() as td:
1281 with TemporaryDirectory() as td:
1288 try:
1282 try:
1289 with tt.AssertNotPrints(re.compile("Activating.*")):
1283 with tt.AssertNotPrints(re.compile("Activating.*")):
1290 lm.logstart(os.path.join(td, "quiet_from_config.log"))
1284 lm.logstart(os.path.join(td, "quiet_from_config.log"))
1291 finally:
1285 finally:
1292 _ip.logger.logstop()
1286 _ip.logger.logstop()
1293
1287
1294
1288
1295 def test_logging_magic_not_quiet():
1289 def test_logging_magic_not_quiet():
1296 _ip.config.LoggingMagics.quiet = False
1290 _ip.config.LoggingMagics.quiet = False
1297 lm = logging.LoggingMagics(shell=_ip)
1291 lm = logging.LoggingMagics(shell=_ip)
1298 with TemporaryDirectory() as td:
1292 with TemporaryDirectory() as td:
1299 try:
1293 try:
1300 with tt.AssertPrints(re.compile("Activating.*")):
1294 with tt.AssertPrints(re.compile("Activating.*")):
1301 lm.logstart(os.path.join(td, "not_quiet.log"))
1295 lm.logstart(os.path.join(td, "not_quiet.log"))
1302 finally:
1296 finally:
1303 _ip.logger.logstop()
1297 _ip.logger.logstop()
1304
1298
1305
1299
1306 def test_time_no_var_expand():
1300 def test_time_no_var_expand():
1307 _ip.user_ns['a'] = 5
1301 _ip.user_ns['a'] = 5
1308 _ip.user_ns['b'] = []
1302 _ip.user_ns['b'] = []
1309 _ip.magic('time b.append("{a}")')
1303 _ip.magic('time b.append("{a}")')
1310 assert _ip.user_ns['b'] == ['{a}']
1304 assert _ip.user_ns['b'] == ['{a}']
1311
1305
1312
1306
1313 # this is slow, put at the end for local testing.
1307 # this is slow, put at the end for local testing.
1314 def test_timeit_arguments():
1308 def test_timeit_arguments():
1315 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
1309 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
1316 if sys.version_info < (3,7):
1310 if sys.version_info < (3,7):
1317 _ip.magic("timeit -n1 -r1 ('#')")
1311 _ip.magic("timeit -n1 -r1 ('#')")
1318 else:
1312 else:
1319 # 3.7 optimize no-op statement like above out, and complain there is
1313 # 3.7 optimize no-op statement like above out, and complain there is
1320 # nothing in the for loop.
1314 # nothing in the for loop.
1321 _ip.magic("timeit -n1 -r1 a=('#')")
1315 _ip.magic("timeit -n1 -r1 a=('#')")
1322
1316
1323
1317
1324 TEST_MODULE = """
1318 TEST_MODULE = """
1325 print('Loaded my_tmp')
1319 print('Loaded my_tmp')
1326 if __name__ == "__main__":
1320 if __name__ == "__main__":
1327 print('I just ran a script')
1321 print('I just ran a script')
1328 """
1322 """
1329
1323
1330
1324
1331 def test_run_module_from_import_hook():
1325 def test_run_module_from_import_hook():
1332 "Test that a module can be loaded via an import hook"
1326 "Test that a module can be loaded via an import hook"
1333 with TemporaryDirectory() as tmpdir:
1327 with TemporaryDirectory() as tmpdir:
1334 fullpath = os.path.join(tmpdir, 'my_tmp.py')
1328 fullpath = os.path.join(tmpdir, 'my_tmp.py')
1335 Path(fullpath).write_text(TEST_MODULE)
1329 Path(fullpath).write_text(TEST_MODULE)
1336
1330
1337 import importlib.abc
1331 import importlib.abc
1338 import importlib.util
1332 import importlib.util
1339
1333
1340 class MyTempImporter(importlib.abc.MetaPathFinder, importlib.abc.SourceLoader):
1334 class MyTempImporter(importlib.abc.MetaPathFinder, importlib.abc.SourceLoader):
1341 def find_spec(self, fullname, path, target=None):
1335 def find_spec(self, fullname, path, target=None):
1342 if fullname == "my_tmp":
1336 if fullname == "my_tmp":
1343 return importlib.util.spec_from_loader(fullname, self)
1337 return importlib.util.spec_from_loader(fullname, self)
1344
1338
1345 def get_filename(self, fullname):
1339 def get_filename(self, fullname):
1346 if fullname != "my_tmp":
1340 if fullname != "my_tmp":
1347 raise ImportError(f"unexpected module name '{fullname}'")
1341 raise ImportError(f"unexpected module name '{fullname}'")
1348 return fullpath
1342 return fullpath
1349
1343
1350 def get_data(self, path):
1344 def get_data(self, path):
1351 if not Path(path).samefile(fullpath):
1345 if not Path(path).samefile(fullpath):
1352 raise OSError(f"expected path '{fullpath}', got '{path}'")
1346 raise OSError(f"expected path '{fullpath}', got '{path}'")
1353 return Path(fullpath).read_text()
1347 return Path(fullpath).read_text()
1354
1348
1355 sys.meta_path.insert(0, MyTempImporter())
1349 sys.meta_path.insert(0, MyTempImporter())
1356
1350
1357 with capture_output() as captured:
1351 with capture_output() as captured:
1358 _ip.magic("run -m my_tmp")
1352 _ip.magic("run -m my_tmp")
1359 _ip.run_cell("import my_tmp")
1353 _ip.run_cell("import my_tmp")
1360
1354
1361 output = "Loaded my_tmp\nI just ran a script\nLoaded my_tmp\n"
1355 output = "Loaded my_tmp\nI just ran a script\nLoaded my_tmp\n"
1362 assert output == captured.stdout
1356 assert output == captured.stdout
1363
1357
1364 sys.meta_path.pop(0)
1358 sys.meta_path.pop(0)
@@ -1,196 +1,192
1 """Tests for IPython.utils.path.py"""
1 """Tests for IPython.utils.path.py"""
2 # Copyright (c) IPython Development Team.
2 # Copyright (c) IPython Development Team.
3 # Distributed under the terms of the Modified BSD License.
3 # Distributed under the terms of the Modified BSD License.
4
4
5 from contextlib import contextmanager
5 from contextlib import contextmanager
6 from unittest.mock import patch
6 from unittest.mock import patch
7
7
8 import pytest
8 import pytest
9
9
10 from IPython.lib import latextools
10 from IPython.lib import latextools
11 from IPython.testing.decorators import (
11 from IPython.testing.decorators import (
12 onlyif_cmds_exist,
12 onlyif_cmds_exist,
13 skipif_not_matplotlib,
13 skipif_not_matplotlib,
14 skip_iptest_but_not_pytest,
15 )
14 )
16 from IPython.utils.process import FindCmdError
15 from IPython.utils.process import FindCmdError
17
16
18
17
19 @pytest.mark.parametrize('command', ['latex', 'dvipng'])
18 @pytest.mark.parametrize('command', ['latex', 'dvipng'])
20 @skip_iptest_but_not_pytest
21 def test_check_latex_to_png_dvipng_fails_when_no_cmd(command):
19 def test_check_latex_to_png_dvipng_fails_when_no_cmd(command):
22 def mock_find_cmd(arg):
20 def mock_find_cmd(arg):
23 if arg == command:
21 if arg == command:
24 raise FindCmdError
22 raise FindCmdError
25
23
26 with patch.object(latextools, "find_cmd", mock_find_cmd):
24 with patch.object(latextools, "find_cmd", mock_find_cmd):
27 assert latextools.latex_to_png_dvipng("whatever", True) is None
25 assert latextools.latex_to_png_dvipng("whatever", True) is None
28
26
29
27
30 @contextmanager
28 @contextmanager
31 def no_op(*args, **kwargs):
29 def no_op(*args, **kwargs):
32 yield
30 yield
33
31
34
32
35 @skip_iptest_but_not_pytest
36 @onlyif_cmds_exist("latex", "dvipng")
33 @onlyif_cmds_exist("latex", "dvipng")
37 @pytest.mark.parametrize("s, wrap", [(u"$$x^2$$", False), (u"x^2", True)])
34 @pytest.mark.parametrize("s, wrap", [(u"$$x^2$$", False), (u"x^2", True)])
38 def test_latex_to_png_dvipng_runs(s, wrap):
35 def test_latex_to_png_dvipng_runs(s, wrap):
39 """
36 """
40 Test that latex_to_png_dvipng just runs without error.
37 Test that latex_to_png_dvipng just runs without error.
41 """
38 """
42 def mock_kpsewhich(filename):
39 def mock_kpsewhich(filename):
43 assert filename == "breqn.sty"
40 assert filename == "breqn.sty"
44 return None
41 return None
45
42
46 latextools.latex_to_png_dvipng(s, wrap)
43 latextools.latex_to_png_dvipng(s, wrap)
47
44
48 with patch_latextool(mock_kpsewhich):
45 with patch_latextool(mock_kpsewhich):
49 latextools.latex_to_png_dvipng(s, wrap)
46 latextools.latex_to_png_dvipng(s, wrap)
50
47
51
48
52 def mock_kpsewhich(filename):
49 def mock_kpsewhich(filename):
53 assert filename == "breqn.sty"
50 assert filename == "breqn.sty"
54 return None
51 return None
55
52
56 @contextmanager
53 @contextmanager
57 def patch_latextool(mock=mock_kpsewhich):
54 def patch_latextool(mock=mock_kpsewhich):
58 with patch.object(latextools, "kpsewhich", mock):
55 with patch.object(latextools, "kpsewhich", mock):
59 yield
56 yield
60
57
61 @pytest.mark.parametrize('context', [no_op, patch_latextool])
58 @pytest.mark.parametrize('context', [no_op, patch_latextool])
62 @pytest.mark.parametrize('s_wrap', [("$x^2$", False), ("x^2", True)])
59 @pytest.mark.parametrize('s_wrap', [("$x^2$", False), ("x^2", True)])
63 @skip_iptest_but_not_pytest
64 def test_latex_to_png_mpl_runs(s_wrap, context):
60 def test_latex_to_png_mpl_runs(s_wrap, context):
65 """
61 """
66 Test that latex_to_png_mpl just runs without error.
62 Test that latex_to_png_mpl just runs without error.
67 """
63 """
68 try:
64 try:
69 import matplotlib
65 import matplotlib
70 except ImportError:
66 except ImportError:
71 pytest.skip("This needs matplotlib to be available")
67 pytest.skip("This needs matplotlib to be available")
72 return
68 return
73 s, wrap = s_wrap
69 s, wrap = s_wrap
74 with context():
70 with context():
75 latextools.latex_to_png_mpl(s, wrap)
71 latextools.latex_to_png_mpl(s, wrap)
76
72
77 @skipif_not_matplotlib
73 @skipif_not_matplotlib
78 def test_latex_to_html():
74 def test_latex_to_html():
79 img = latextools.latex_to_html("$x^2$")
75 img = latextools.latex_to_html("$x^2$")
80 assert "data:image/png;base64,iVBOR" in img
76 assert "data:image/png;base64,iVBOR" in img
81
77
82
78
83 def test_genelatex_no_wrap():
79 def test_genelatex_no_wrap():
84 """
80 """
85 Test genelatex with wrap=False.
81 Test genelatex with wrap=False.
86 """
82 """
87 def mock_kpsewhich(filename):
83 def mock_kpsewhich(filename):
88 assert False, ("kpsewhich should not be called "
84 assert False, ("kpsewhich should not be called "
89 "(called with {0})".format(filename))
85 "(called with {0})".format(filename))
90
86
91 with patch_latextool(mock_kpsewhich):
87 with patch_latextool(mock_kpsewhich):
92 assert '\n'.join(latextools.genelatex("body text", False)) == r'''\documentclass{article}
88 assert '\n'.join(latextools.genelatex("body text", False)) == r'''\documentclass{article}
93 \usepackage{amsmath}
89 \usepackage{amsmath}
94 \usepackage{amsthm}
90 \usepackage{amsthm}
95 \usepackage{amssymb}
91 \usepackage{amssymb}
96 \usepackage{bm}
92 \usepackage{bm}
97 \pagestyle{empty}
93 \pagestyle{empty}
98 \begin{document}
94 \begin{document}
99 body text
95 body text
100 \end{document}'''
96 \end{document}'''
101
97
102
98
103 def test_genelatex_wrap_with_breqn():
99 def test_genelatex_wrap_with_breqn():
104 """
100 """
105 Test genelatex with wrap=True for the case breqn.sty is installed.
101 Test genelatex with wrap=True for the case breqn.sty is installed.
106 """
102 """
107 def mock_kpsewhich(filename):
103 def mock_kpsewhich(filename):
108 assert filename == "breqn.sty"
104 assert filename == "breqn.sty"
109 return "path/to/breqn.sty"
105 return "path/to/breqn.sty"
110
106
111 with patch_latextool(mock_kpsewhich):
107 with patch_latextool(mock_kpsewhich):
112 assert '\n'.join(latextools.genelatex("x^2", True)) == r'''\documentclass{article}
108 assert '\n'.join(latextools.genelatex("x^2", True)) == r'''\documentclass{article}
113 \usepackage{amsmath}
109 \usepackage{amsmath}
114 \usepackage{amsthm}
110 \usepackage{amsthm}
115 \usepackage{amssymb}
111 \usepackage{amssymb}
116 \usepackage{bm}
112 \usepackage{bm}
117 \usepackage{breqn}
113 \usepackage{breqn}
118 \pagestyle{empty}
114 \pagestyle{empty}
119 \begin{document}
115 \begin{document}
120 \begin{dmath*}
116 \begin{dmath*}
121 x^2
117 x^2
122 \end{dmath*}
118 \end{dmath*}
123 \end{document}'''
119 \end{document}'''
124
120
125
121
126 def test_genelatex_wrap_without_breqn():
122 def test_genelatex_wrap_without_breqn():
127 """
123 """
128 Test genelatex with wrap=True for the case breqn.sty is not installed.
124 Test genelatex with wrap=True for the case breqn.sty is not installed.
129 """
125 """
130 def mock_kpsewhich(filename):
126 def mock_kpsewhich(filename):
131 assert filename == "breqn.sty"
127 assert filename == "breqn.sty"
132 return None
128 return None
133
129
134 with patch_latextool(mock_kpsewhich):
130 with patch_latextool(mock_kpsewhich):
135 assert '\n'.join(latextools.genelatex("x^2", True)) == r'''\documentclass{article}
131 assert '\n'.join(latextools.genelatex("x^2", True)) == r'''\documentclass{article}
136 \usepackage{amsmath}
132 \usepackage{amsmath}
137 \usepackage{amsthm}
133 \usepackage{amsthm}
138 \usepackage{amssymb}
134 \usepackage{amssymb}
139 \usepackage{bm}
135 \usepackage{bm}
140 \pagestyle{empty}
136 \pagestyle{empty}
141 \begin{document}
137 \begin{document}
142 $$x^2$$
138 $$x^2$$
143 \end{document}'''
139 \end{document}'''
144
140
145
141
146 @skipif_not_matplotlib
142 @skipif_not_matplotlib
147 @onlyif_cmds_exist('latex', 'dvipng')
143 @onlyif_cmds_exist('latex', 'dvipng')
148 def test_latex_to_png_color():
144 def test_latex_to_png_color():
149 """
145 """
150 Test color settings for latex_to_png.
146 Test color settings for latex_to_png.
151 """
147 """
152 latex_string = "$x^2$"
148 latex_string = "$x^2$"
153 default_value = latextools.latex_to_png(latex_string, wrap=False)
149 default_value = latextools.latex_to_png(latex_string, wrap=False)
154 default_hexblack = latextools.latex_to_png(latex_string, wrap=False,
150 default_hexblack = latextools.latex_to_png(latex_string, wrap=False,
155 color='#000000')
151 color='#000000')
156 dvipng_default = latextools.latex_to_png_dvipng(latex_string, False)
152 dvipng_default = latextools.latex_to_png_dvipng(latex_string, False)
157 dvipng_black = latextools.latex_to_png_dvipng(latex_string, False, 'Black')
153 dvipng_black = latextools.latex_to_png_dvipng(latex_string, False, 'Black')
158 assert dvipng_default == dvipng_black
154 assert dvipng_default == dvipng_black
159 mpl_default = latextools.latex_to_png_mpl(latex_string, False)
155 mpl_default = latextools.latex_to_png_mpl(latex_string, False)
160 mpl_black = latextools.latex_to_png_mpl(latex_string, False, 'Black')
156 mpl_black = latextools.latex_to_png_mpl(latex_string, False, 'Black')
161 assert mpl_default == mpl_black
157 assert mpl_default == mpl_black
162 assert default_value in [dvipng_black, mpl_black]
158 assert default_value in [dvipng_black, mpl_black]
163 assert default_hexblack in [dvipng_black, mpl_black]
159 assert default_hexblack in [dvipng_black, mpl_black]
164
160
165 # Test that dvips name colors can be used without error
161 # Test that dvips name colors can be used without error
166 dvipng_maroon = latextools.latex_to_png_dvipng(latex_string, False,
162 dvipng_maroon = latextools.latex_to_png_dvipng(latex_string, False,
167 'Maroon')
163 'Maroon')
168 # And that it doesn't return the black one
164 # And that it doesn't return the black one
169 assert dvipng_black != dvipng_maroon
165 assert dvipng_black != dvipng_maroon
170
166
171 mpl_maroon = latextools.latex_to_png_mpl(latex_string, False, 'Maroon')
167 mpl_maroon = latextools.latex_to_png_mpl(latex_string, False, 'Maroon')
172 assert mpl_black != mpl_maroon
168 assert mpl_black != mpl_maroon
173 mpl_white = latextools.latex_to_png_mpl(latex_string, False, 'White')
169 mpl_white = latextools.latex_to_png_mpl(latex_string, False, 'White')
174 mpl_hexwhite = latextools.latex_to_png_mpl(latex_string, False, '#FFFFFF')
170 mpl_hexwhite = latextools.latex_to_png_mpl(latex_string, False, '#FFFFFF')
175 assert mpl_white == mpl_hexwhite
171 assert mpl_white == mpl_hexwhite
176
172
177 mpl_white_scale = latextools.latex_to_png_mpl(latex_string, False,
173 mpl_white_scale = latextools.latex_to_png_mpl(latex_string, False,
178 'White', 1.2)
174 'White', 1.2)
179 assert mpl_white != mpl_white_scale
175 assert mpl_white != mpl_white_scale
180
176
181
177
182 def test_latex_to_png_invalid_hex_colors():
178 def test_latex_to_png_invalid_hex_colors():
183 """
179 """
184 Test that invalid hex colors provided to dvipng gives an exception.
180 Test that invalid hex colors provided to dvipng gives an exception.
185 """
181 """
186 latex_string = "$x^2$"
182 latex_string = "$x^2$"
187 pytest.raises(
183 pytest.raises(
188 ValueError,
184 ValueError,
189 lambda: latextools.latex_to_png(
185 lambda: latextools.latex_to_png(
190 latex_string, backend="dvipng", color="#f00bar"
186 latex_string, backend="dvipng", color="#f00bar"
191 ),
187 ),
192 )
188 )
193 pytest.raises(
189 pytest.raises(
194 ValueError,
190 ValueError,
195 lambda: latextools.latex_to_png(latex_string, backend="dvipng", color="#f00"),
191 lambda: latextools.latex_to_png(latex_string, backend="dvipng", color="#f00"),
196 )
192 )
@@ -1,502 +1,500
1 # coding: utf-8
1 # coding: utf-8
2 """Tests for IPython.lib.pretty."""
2 """Tests for IPython.lib.pretty."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7
7
8 from collections import Counter, defaultdict, deque, OrderedDict
8 from collections import Counter, defaultdict, deque, OrderedDict
9 import os
9 import os
10 import pytest
10 import pytest
11 import types
11 import types
12 import string
12 import string
13 import sys
13 import sys
14 import unittest
14 import unittest
15
15
16 import pytest
16 import pytest
17
17
18 from IPython.lib import pretty
18 from IPython.lib import pretty
19 from IPython.testing.decorators import skip_iptest_but_not_pytest
20
19
21 from io import StringIO
20 from io import StringIO
22
21
23
22
24 class MyList(object):
23 class MyList(object):
25 def __init__(self, content):
24 def __init__(self, content):
26 self.content = content
25 self.content = content
27 def _repr_pretty_(self, p, cycle):
26 def _repr_pretty_(self, p, cycle):
28 if cycle:
27 if cycle:
29 p.text("MyList(...)")
28 p.text("MyList(...)")
30 else:
29 else:
31 with p.group(3, "MyList(", ")"):
30 with p.group(3, "MyList(", ")"):
32 for (i, child) in enumerate(self.content):
31 for (i, child) in enumerate(self.content):
33 if i:
32 if i:
34 p.text(",")
33 p.text(",")
35 p.breakable()
34 p.breakable()
36 else:
35 else:
37 p.breakable("")
36 p.breakable("")
38 p.pretty(child)
37 p.pretty(child)
39
38
40
39
41 class MyDict(dict):
40 class MyDict(dict):
42 def _repr_pretty_(self, p, cycle):
41 def _repr_pretty_(self, p, cycle):
43 p.text("MyDict(...)")
42 p.text("MyDict(...)")
44
43
45 class MyObj(object):
44 class MyObj(object):
46 def somemethod(self):
45 def somemethod(self):
47 pass
46 pass
48
47
49
48
50 class Dummy1(object):
49 class Dummy1(object):
51 def _repr_pretty_(self, p, cycle):
50 def _repr_pretty_(self, p, cycle):
52 p.text("Dummy1(...)")
51 p.text("Dummy1(...)")
53
52
54 class Dummy2(Dummy1):
53 class Dummy2(Dummy1):
55 _repr_pretty_ = None
54 _repr_pretty_ = None
56
55
57 class NoModule(object):
56 class NoModule(object):
58 pass
57 pass
59
58
60 NoModule.__module__ = None
59 NoModule.__module__ = None
61
60
62 class Breaking(object):
61 class Breaking(object):
63 def _repr_pretty_(self, p, cycle):
62 def _repr_pretty_(self, p, cycle):
64 with p.group(4,"TG: ",":"):
63 with p.group(4,"TG: ",":"):
65 p.text("Breaking(")
64 p.text("Breaking(")
66 p.break_()
65 p.break_()
67 p.text(")")
66 p.text(")")
68
67
69 class BreakingRepr(object):
68 class BreakingRepr(object):
70 def __repr__(self):
69 def __repr__(self):
71 return "Breaking(\n)"
70 return "Breaking(\n)"
72
71
73 class BadRepr(object):
72 class BadRepr(object):
74 def __repr__(self):
73 def __repr__(self):
75 return 1/0
74 return 1/0
76
75
77
76
78 def test_indentation():
77 def test_indentation():
79 """Test correct indentation in groups"""
78 """Test correct indentation in groups"""
80 count = 40
79 count = 40
81 gotoutput = pretty.pretty(MyList(range(count)))
80 gotoutput = pretty.pretty(MyList(range(count)))
82 expectedoutput = "MyList(\n" + ",\n".join(" %d" % i for i in range(count)) + ")"
81 expectedoutput = "MyList(\n" + ",\n".join(" %d" % i for i in range(count)) + ")"
83
82
84 assert gotoutput == expectedoutput
83 assert gotoutput == expectedoutput
85
84
86
85
87 def test_dispatch():
86 def test_dispatch():
88 """
87 """
89 Test correct dispatching: The _repr_pretty_ method for MyDict
88 Test correct dispatching: The _repr_pretty_ method for MyDict
90 must be found before the registered printer for dict.
89 must be found before the registered printer for dict.
91 """
90 """
92 gotoutput = pretty.pretty(MyDict())
91 gotoutput = pretty.pretty(MyDict())
93 expectedoutput = "MyDict(...)"
92 expectedoutput = "MyDict(...)"
94
93
95 assert gotoutput == expectedoutput
94 assert gotoutput == expectedoutput
96
95
97
96
98 def test_callability_checking():
97 def test_callability_checking():
99 """
98 """
100 Test that the _repr_pretty_ method is tested for callability and skipped if
99 Test that the _repr_pretty_ method is tested for callability and skipped if
101 not.
100 not.
102 """
101 """
103 gotoutput = pretty.pretty(Dummy2())
102 gotoutput = pretty.pretty(Dummy2())
104 expectedoutput = "Dummy1(...)"
103 expectedoutput = "Dummy1(...)"
105
104
106 assert gotoutput == expectedoutput
105 assert gotoutput == expectedoutput
107
106
108
107
109 @pytest.mark.parametrize(
108 @pytest.mark.parametrize(
110 "obj,expected_output",
109 "obj,expected_output",
111 zip(
110 zip(
112 [
111 [
113 set(),
112 set(),
114 frozenset(),
113 frozenset(),
115 set([1]),
114 set([1]),
116 frozenset([1]),
115 frozenset([1]),
117 set([1, 2]),
116 set([1, 2]),
118 frozenset([1, 2]),
117 frozenset([1, 2]),
119 set([-1, -2, -3]),
118 set([-1, -2, -3]),
120 ],
119 ],
121 [
120 [
122 "set()",
121 "set()",
123 "frozenset()",
122 "frozenset()",
124 "{1}",
123 "{1}",
125 "frozenset({1})",
124 "frozenset({1})",
126 "{1, 2}",
125 "{1, 2}",
127 "frozenset({1, 2})",
126 "frozenset({1, 2})",
128 "{-3, -2, -1}",
127 "{-3, -2, -1}",
129 ],
128 ],
130 ),
129 ),
131 )
130 )
132 @skip_iptest_but_not_pytest
133 def test_sets(obj, expected_output):
131 def test_sets(obj, expected_output):
134 """
132 """
135 Test that set and frozenset use Python 3 formatting.
133 Test that set and frozenset use Python 3 formatting.
136 """
134 """
137 got_output = pretty.pretty(obj)
135 got_output = pretty.pretty(obj)
138 assert got_output == expected_output
136 assert got_output == expected_output
139
137
140
138
141 def test_pprint_heap_allocated_type():
139 def test_pprint_heap_allocated_type():
142 """
140 """
143 Test that pprint works for heap allocated types.
141 Test that pprint works for heap allocated types.
144 """
142 """
145 module_name = "xxlimited" if sys.version_info < (3, 10) else "xxlimited_35"
143 module_name = "xxlimited" if sys.version_info < (3, 10) else "xxlimited_35"
146 xxlimited = pytest.importorskip(module_name)
144 xxlimited = pytest.importorskip(module_name)
147 output = pretty.pretty(xxlimited.Null)
145 output = pretty.pretty(xxlimited.Null)
148 assert output == "xxlimited.Null"
146 assert output == "xxlimited.Null"
149
147
150
148
151 def test_pprint_nomod():
149 def test_pprint_nomod():
152 """
150 """
153 Test that pprint works for classes with no __module__.
151 Test that pprint works for classes with no __module__.
154 """
152 """
155 output = pretty.pretty(NoModule)
153 output = pretty.pretty(NoModule)
156 assert output == "NoModule"
154 assert output == "NoModule"
157
155
158
156
159 def test_pprint_break():
157 def test_pprint_break():
160 """
158 """
161 Test that p.break_ produces expected output
159 Test that p.break_ produces expected output
162 """
160 """
163 output = pretty.pretty(Breaking())
161 output = pretty.pretty(Breaking())
164 expected = "TG: Breaking(\n ):"
162 expected = "TG: Breaking(\n ):"
165 assert output == expected
163 assert output == expected
166
164
167 def test_pprint_break_repr():
165 def test_pprint_break_repr():
168 """
166 """
169 Test that p.break_ is used in repr
167 Test that p.break_ is used in repr
170 """
168 """
171 output = pretty.pretty([[BreakingRepr()]])
169 output = pretty.pretty([[BreakingRepr()]])
172 expected = "[[Breaking(\n )]]"
170 expected = "[[Breaking(\n )]]"
173 assert output == expected
171 assert output == expected
174
172
175 output = pretty.pretty([[BreakingRepr()]*2])
173 output = pretty.pretty([[BreakingRepr()]*2])
176 expected = "[[Breaking(\n ),\n Breaking(\n )]]"
174 expected = "[[Breaking(\n ),\n Breaking(\n )]]"
177 assert output == expected
175 assert output == expected
178
176
179 def test_bad_repr():
177 def test_bad_repr():
180 """Don't catch bad repr errors"""
178 """Don't catch bad repr errors"""
181 with pytest.raises(ZeroDivisionError):
179 with pytest.raises(ZeroDivisionError):
182 pretty.pretty(BadRepr())
180 pretty.pretty(BadRepr())
183
181
184 class BadException(Exception):
182 class BadException(Exception):
185 def __str__(self):
183 def __str__(self):
186 return -1
184 return -1
187
185
188 class ReallyBadRepr(object):
186 class ReallyBadRepr(object):
189 __module__ = 1
187 __module__ = 1
190 @property
188 @property
191 def __class__(self):
189 def __class__(self):
192 raise ValueError("I am horrible")
190 raise ValueError("I am horrible")
193
191
194 def __repr__(self):
192 def __repr__(self):
195 raise BadException()
193 raise BadException()
196
194
197 def test_really_bad_repr():
195 def test_really_bad_repr():
198 with pytest.raises(BadException):
196 with pytest.raises(BadException):
199 pretty.pretty(ReallyBadRepr())
197 pretty.pretty(ReallyBadRepr())
200
198
201
199
202 class SA(object):
200 class SA(object):
203 pass
201 pass
204
202
205 class SB(SA):
203 class SB(SA):
206 pass
204 pass
207
205
208 class TestsPretty(unittest.TestCase):
206 class TestsPretty(unittest.TestCase):
209
207
210 def test_super_repr(self):
208 def test_super_repr(self):
211 # "<super: module_name.SA, None>"
209 # "<super: module_name.SA, None>"
212 output = pretty.pretty(super(SA))
210 output = pretty.pretty(super(SA))
213 self.assertRegex(output, r"<super: \S+.SA, None>")
211 self.assertRegex(output, r"<super: \S+.SA, None>")
214
212
215 # "<super: module_name.SA, <module_name.SB at 0x...>>"
213 # "<super: module_name.SA, <module_name.SB at 0x...>>"
216 sb = SB()
214 sb = SB()
217 output = pretty.pretty(super(SA, sb))
215 output = pretty.pretty(super(SA, sb))
218 self.assertRegex(output, r"<super: \S+.SA,\s+<\S+.SB at 0x\S+>>")
216 self.assertRegex(output, r"<super: \S+.SA,\s+<\S+.SB at 0x\S+>>")
219
217
220
218
221 def test_long_list(self):
219 def test_long_list(self):
222 lis = list(range(10000))
220 lis = list(range(10000))
223 p = pretty.pretty(lis)
221 p = pretty.pretty(lis)
224 last2 = p.rsplit('\n', 2)[-2:]
222 last2 = p.rsplit('\n', 2)[-2:]
225 self.assertEqual(last2, [' 999,', ' ...]'])
223 self.assertEqual(last2, [' 999,', ' ...]'])
226
224
227 def test_long_set(self):
225 def test_long_set(self):
228 s = set(range(10000))
226 s = set(range(10000))
229 p = pretty.pretty(s)
227 p = pretty.pretty(s)
230 last2 = p.rsplit('\n', 2)[-2:]
228 last2 = p.rsplit('\n', 2)[-2:]
231 self.assertEqual(last2, [' 999,', ' ...}'])
229 self.assertEqual(last2, [' 999,', ' ...}'])
232
230
233 def test_long_tuple(self):
231 def test_long_tuple(self):
234 tup = tuple(range(10000))
232 tup = tuple(range(10000))
235 p = pretty.pretty(tup)
233 p = pretty.pretty(tup)
236 last2 = p.rsplit('\n', 2)[-2:]
234 last2 = p.rsplit('\n', 2)[-2:]
237 self.assertEqual(last2, [' 999,', ' ...)'])
235 self.assertEqual(last2, [' 999,', ' ...)'])
238
236
239 def test_long_dict(self):
237 def test_long_dict(self):
240 d = { n:n for n in range(10000) }
238 d = { n:n for n in range(10000) }
241 p = pretty.pretty(d)
239 p = pretty.pretty(d)
242 last2 = p.rsplit('\n', 2)[-2:]
240 last2 = p.rsplit('\n', 2)[-2:]
243 self.assertEqual(last2, [' 999: 999,', ' ...}'])
241 self.assertEqual(last2, [' 999: 999,', ' ...}'])
244
242
245 def test_unbound_method(self):
243 def test_unbound_method(self):
246 output = pretty.pretty(MyObj.somemethod)
244 output = pretty.pretty(MyObj.somemethod)
247 self.assertIn('MyObj.somemethod', output)
245 self.assertIn('MyObj.somemethod', output)
248
246
249
247
250 class MetaClass(type):
248 class MetaClass(type):
251 def __new__(cls, name):
249 def __new__(cls, name):
252 return type.__new__(cls, name, (object,), {'name': name})
250 return type.__new__(cls, name, (object,), {'name': name})
253
251
254 def __repr__(self):
252 def __repr__(self):
255 return "[CUSTOM REPR FOR CLASS %s]" % self.name
253 return "[CUSTOM REPR FOR CLASS %s]" % self.name
256
254
257
255
258 ClassWithMeta = MetaClass('ClassWithMeta')
256 ClassWithMeta = MetaClass('ClassWithMeta')
259
257
260
258
261 def test_metaclass_repr():
259 def test_metaclass_repr():
262 output = pretty.pretty(ClassWithMeta)
260 output = pretty.pretty(ClassWithMeta)
263 assert output == "[CUSTOM REPR FOR CLASS ClassWithMeta]"
261 assert output == "[CUSTOM REPR FOR CLASS ClassWithMeta]"
264
262
265
263
266 def test_unicode_repr():
264 def test_unicode_repr():
267 u = u"üniçodé"
265 u = u"üniçodé"
268 ustr = u
266 ustr = u
269
267
270 class C(object):
268 class C(object):
271 def __repr__(self):
269 def __repr__(self):
272 return ustr
270 return ustr
273
271
274 c = C()
272 c = C()
275 p = pretty.pretty(c)
273 p = pretty.pretty(c)
276 assert p == u
274 assert p == u
277 p = pretty.pretty([c])
275 p = pretty.pretty([c])
278 assert p == u"[%s]" % u
276 assert p == u"[%s]" % u
279
277
280
278
281 def test_basic_class():
279 def test_basic_class():
282 def type_pprint_wrapper(obj, p, cycle):
280 def type_pprint_wrapper(obj, p, cycle):
283 if obj is MyObj:
281 if obj is MyObj:
284 type_pprint_wrapper.called = True
282 type_pprint_wrapper.called = True
285 return pretty._type_pprint(obj, p, cycle)
283 return pretty._type_pprint(obj, p, cycle)
286 type_pprint_wrapper.called = False
284 type_pprint_wrapper.called = False
287
285
288 stream = StringIO()
286 stream = StringIO()
289 printer = pretty.RepresentationPrinter(stream)
287 printer = pretty.RepresentationPrinter(stream)
290 printer.type_pprinters[type] = type_pprint_wrapper
288 printer.type_pprinters[type] = type_pprint_wrapper
291 printer.pretty(MyObj)
289 printer.pretty(MyObj)
292 printer.flush()
290 printer.flush()
293 output = stream.getvalue()
291 output = stream.getvalue()
294
292
295 assert output == "%s.MyObj" % __name__
293 assert output == "%s.MyObj" % __name__
296 assert type_pprint_wrapper.called is True
294 assert type_pprint_wrapper.called is True
297
295
298
296
299 # TODO : pytest.mark.parametrise once nose is gone.
297 # TODO : pytest.mark.parametrise once nose is gone.
300 def test_collections_defaultdict():
298 def test_collections_defaultdict():
301 # Create defaultdicts with cycles
299 # Create defaultdicts with cycles
302 a = defaultdict()
300 a = defaultdict()
303 a.default_factory = a
301 a.default_factory = a
304 b = defaultdict(list)
302 b = defaultdict(list)
305 b['key'] = b
303 b['key'] = b
306
304
307 # Dictionary order cannot be relied on, test against single keys.
305 # Dictionary order cannot be relied on, test against single keys.
308 cases = [
306 cases = [
309 (defaultdict(list), 'defaultdict(list, {})'),
307 (defaultdict(list), 'defaultdict(list, {})'),
310 (defaultdict(list, {'key': '-' * 50}),
308 (defaultdict(list, {'key': '-' * 50}),
311 "defaultdict(list,\n"
309 "defaultdict(list,\n"
312 " {'key': '--------------------------------------------------'})"),
310 " {'key': '--------------------------------------------------'})"),
313 (a, 'defaultdict(defaultdict(...), {})'),
311 (a, 'defaultdict(defaultdict(...), {})'),
314 (b, "defaultdict(list, {'key': defaultdict(...)})"),
312 (b, "defaultdict(list, {'key': defaultdict(...)})"),
315 ]
313 ]
316 for obj, expected in cases:
314 for obj, expected in cases:
317 assert pretty.pretty(obj) == expected
315 assert pretty.pretty(obj) == expected
318
316
319
317
320 # TODO : pytest.mark.parametrise once nose is gone.
318 # TODO : pytest.mark.parametrise once nose is gone.
321 def test_collections_ordereddict():
319 def test_collections_ordereddict():
322 # Create OrderedDict with cycle
320 # Create OrderedDict with cycle
323 a = OrderedDict()
321 a = OrderedDict()
324 a['key'] = a
322 a['key'] = a
325
323
326 cases = [
324 cases = [
327 (OrderedDict(), 'OrderedDict()'),
325 (OrderedDict(), 'OrderedDict()'),
328 (OrderedDict((i, i) for i in range(1000, 1010)),
326 (OrderedDict((i, i) for i in range(1000, 1010)),
329 'OrderedDict([(1000, 1000),\n'
327 'OrderedDict([(1000, 1000),\n'
330 ' (1001, 1001),\n'
328 ' (1001, 1001),\n'
331 ' (1002, 1002),\n'
329 ' (1002, 1002),\n'
332 ' (1003, 1003),\n'
330 ' (1003, 1003),\n'
333 ' (1004, 1004),\n'
331 ' (1004, 1004),\n'
334 ' (1005, 1005),\n'
332 ' (1005, 1005),\n'
335 ' (1006, 1006),\n'
333 ' (1006, 1006),\n'
336 ' (1007, 1007),\n'
334 ' (1007, 1007),\n'
337 ' (1008, 1008),\n'
335 ' (1008, 1008),\n'
338 ' (1009, 1009)])'),
336 ' (1009, 1009)])'),
339 (a, "OrderedDict([('key', OrderedDict(...))])"),
337 (a, "OrderedDict([('key', OrderedDict(...))])"),
340 ]
338 ]
341 for obj, expected in cases:
339 for obj, expected in cases:
342 assert pretty.pretty(obj) == expected
340 assert pretty.pretty(obj) == expected
343
341
344
342
345 # TODO : pytest.mark.parametrise once nose is gone.
343 # TODO : pytest.mark.parametrise once nose is gone.
346 def test_collections_deque():
344 def test_collections_deque():
347 # Create deque with cycle
345 # Create deque with cycle
348 a = deque()
346 a = deque()
349 a.append(a)
347 a.append(a)
350
348
351 cases = [
349 cases = [
352 (deque(), 'deque([])'),
350 (deque(), 'deque([])'),
353 (deque(i for i in range(1000, 1020)),
351 (deque(i for i in range(1000, 1020)),
354 'deque([1000,\n'
352 'deque([1000,\n'
355 ' 1001,\n'
353 ' 1001,\n'
356 ' 1002,\n'
354 ' 1002,\n'
357 ' 1003,\n'
355 ' 1003,\n'
358 ' 1004,\n'
356 ' 1004,\n'
359 ' 1005,\n'
357 ' 1005,\n'
360 ' 1006,\n'
358 ' 1006,\n'
361 ' 1007,\n'
359 ' 1007,\n'
362 ' 1008,\n'
360 ' 1008,\n'
363 ' 1009,\n'
361 ' 1009,\n'
364 ' 1010,\n'
362 ' 1010,\n'
365 ' 1011,\n'
363 ' 1011,\n'
366 ' 1012,\n'
364 ' 1012,\n'
367 ' 1013,\n'
365 ' 1013,\n'
368 ' 1014,\n'
366 ' 1014,\n'
369 ' 1015,\n'
367 ' 1015,\n'
370 ' 1016,\n'
368 ' 1016,\n'
371 ' 1017,\n'
369 ' 1017,\n'
372 ' 1018,\n'
370 ' 1018,\n'
373 ' 1019])'),
371 ' 1019])'),
374 (a, 'deque([deque(...)])'),
372 (a, 'deque([deque(...)])'),
375 ]
373 ]
376 for obj, expected in cases:
374 for obj, expected in cases:
377 assert pretty.pretty(obj) == expected
375 assert pretty.pretty(obj) == expected
378
376
379
377
380 # TODO : pytest.mark.parametrise once nose is gone.
378 # TODO : pytest.mark.parametrise once nose is gone.
381 def test_collections_counter():
379 def test_collections_counter():
382 class MyCounter(Counter):
380 class MyCounter(Counter):
383 pass
381 pass
384 cases = [
382 cases = [
385 (Counter(), 'Counter()'),
383 (Counter(), 'Counter()'),
386 (Counter(a=1), "Counter({'a': 1})"),
384 (Counter(a=1), "Counter({'a': 1})"),
387 (MyCounter(a=1), "MyCounter({'a': 1})"),
385 (MyCounter(a=1), "MyCounter({'a': 1})"),
388 ]
386 ]
389 for obj, expected in cases:
387 for obj, expected in cases:
390 assert pretty.pretty(obj) == expected
388 assert pretty.pretty(obj) == expected
391
389
392 # TODO : pytest.mark.parametrise once nose is gone.
390 # TODO : pytest.mark.parametrise once nose is gone.
393 def test_mappingproxy():
391 def test_mappingproxy():
394 MP = types.MappingProxyType
392 MP = types.MappingProxyType
395 underlying_dict = {}
393 underlying_dict = {}
396 mp_recursive = MP(underlying_dict)
394 mp_recursive = MP(underlying_dict)
397 underlying_dict[2] = mp_recursive
395 underlying_dict[2] = mp_recursive
398 underlying_dict[3] = underlying_dict
396 underlying_dict[3] = underlying_dict
399
397
400 cases = [
398 cases = [
401 (MP({}), "mappingproxy({})"),
399 (MP({}), "mappingproxy({})"),
402 (MP({None: MP({})}), "mappingproxy({None: mappingproxy({})})"),
400 (MP({None: MP({})}), "mappingproxy({None: mappingproxy({})})"),
403 (MP({k: k.upper() for k in string.ascii_lowercase}),
401 (MP({k: k.upper() for k in string.ascii_lowercase}),
404 "mappingproxy({'a': 'A',\n"
402 "mappingproxy({'a': 'A',\n"
405 " 'b': 'B',\n"
403 " 'b': 'B',\n"
406 " 'c': 'C',\n"
404 " 'c': 'C',\n"
407 " 'd': 'D',\n"
405 " 'd': 'D',\n"
408 " 'e': 'E',\n"
406 " 'e': 'E',\n"
409 " 'f': 'F',\n"
407 " 'f': 'F',\n"
410 " 'g': 'G',\n"
408 " 'g': 'G',\n"
411 " 'h': 'H',\n"
409 " 'h': 'H',\n"
412 " 'i': 'I',\n"
410 " 'i': 'I',\n"
413 " 'j': 'J',\n"
411 " 'j': 'J',\n"
414 " 'k': 'K',\n"
412 " 'k': 'K',\n"
415 " 'l': 'L',\n"
413 " 'l': 'L',\n"
416 " 'm': 'M',\n"
414 " 'm': 'M',\n"
417 " 'n': 'N',\n"
415 " 'n': 'N',\n"
418 " 'o': 'O',\n"
416 " 'o': 'O',\n"
419 " 'p': 'P',\n"
417 " 'p': 'P',\n"
420 " 'q': 'Q',\n"
418 " 'q': 'Q',\n"
421 " 'r': 'R',\n"
419 " 'r': 'R',\n"
422 " 's': 'S',\n"
420 " 's': 'S',\n"
423 " 't': 'T',\n"
421 " 't': 'T',\n"
424 " 'u': 'U',\n"
422 " 'u': 'U',\n"
425 " 'v': 'V',\n"
423 " 'v': 'V',\n"
426 " 'w': 'W',\n"
424 " 'w': 'W',\n"
427 " 'x': 'X',\n"
425 " 'x': 'X',\n"
428 " 'y': 'Y',\n"
426 " 'y': 'Y',\n"
429 " 'z': 'Z'})"),
427 " 'z': 'Z'})"),
430 (mp_recursive, "mappingproxy({2: {...}, 3: {2: {...}, 3: {...}}})"),
428 (mp_recursive, "mappingproxy({2: {...}, 3: {2: {...}, 3: {...}}})"),
431 (underlying_dict,
429 (underlying_dict,
432 "{2: mappingproxy({2: {...}, 3: {...}}), 3: {...}}"),
430 "{2: mappingproxy({2: {...}, 3: {...}}), 3: {...}}"),
433 ]
431 ]
434 for obj, expected in cases:
432 for obj, expected in cases:
435 assert pretty.pretty(obj) == expected
433 assert pretty.pretty(obj) == expected
436
434
437
435
438 # TODO : pytest.mark.parametrise once nose is gone.
436 # TODO : pytest.mark.parametrise once nose is gone.
439 def test_simplenamespace():
437 def test_simplenamespace():
440 SN = types.SimpleNamespace
438 SN = types.SimpleNamespace
441
439
442 sn_recursive = SN()
440 sn_recursive = SN()
443 sn_recursive.first = sn_recursive
441 sn_recursive.first = sn_recursive
444 sn_recursive.second = sn_recursive
442 sn_recursive.second = sn_recursive
445 cases = [
443 cases = [
446 (SN(), "namespace()"),
444 (SN(), "namespace()"),
447 (SN(x=SN()), "namespace(x=namespace())"),
445 (SN(x=SN()), "namespace(x=namespace())"),
448 (SN(a_long_name=[SN(s=string.ascii_lowercase)]*3, a_short_name=None),
446 (SN(a_long_name=[SN(s=string.ascii_lowercase)]*3, a_short_name=None),
449 "namespace(a_long_name=[namespace(s='abcdefghijklmnopqrstuvwxyz'),\n"
447 "namespace(a_long_name=[namespace(s='abcdefghijklmnopqrstuvwxyz'),\n"
450 " namespace(s='abcdefghijklmnopqrstuvwxyz'),\n"
448 " namespace(s='abcdefghijklmnopqrstuvwxyz'),\n"
451 " namespace(s='abcdefghijklmnopqrstuvwxyz')],\n"
449 " namespace(s='abcdefghijklmnopqrstuvwxyz')],\n"
452 " a_short_name=None)"),
450 " a_short_name=None)"),
453 (sn_recursive, "namespace(first=namespace(...), second=namespace(...))"),
451 (sn_recursive, "namespace(first=namespace(...), second=namespace(...))"),
454 ]
452 ]
455 for obj, expected in cases:
453 for obj, expected in cases:
456 assert pretty.pretty(obj) == expected
454 assert pretty.pretty(obj) == expected
457
455
458
456
459 def test_pretty_environ():
457 def test_pretty_environ():
460 dict_repr = pretty.pretty(dict(os.environ))
458 dict_repr = pretty.pretty(dict(os.environ))
461 # reindent to align with 'environ' prefix
459 # reindent to align with 'environ' prefix
462 dict_indented = dict_repr.replace('\n', '\n' + (' ' * len('environ')))
460 dict_indented = dict_repr.replace('\n', '\n' + (' ' * len('environ')))
463 env_repr = pretty.pretty(os.environ)
461 env_repr = pretty.pretty(os.environ)
464 assert env_repr == "environ" + dict_indented
462 assert env_repr == "environ" + dict_indented
465
463
466
464
467 def test_function_pretty():
465 def test_function_pretty():
468 "Test pretty print of function"
466 "Test pretty print of function"
469 # posixpath is a pure python module, its interface is consistent
467 # posixpath is a pure python module, its interface is consistent
470 # across Python distributions
468 # across Python distributions
471 import posixpath
469 import posixpath
472
470
473 assert pretty.pretty(posixpath.join) == "<function posixpath.join(a, *p)>"
471 assert pretty.pretty(posixpath.join) == "<function posixpath.join(a, *p)>"
474
472
475 # custom function
473 # custom function
476 def meaning_of_life(question=None):
474 def meaning_of_life(question=None):
477 if question:
475 if question:
478 return 42
476 return 42
479 return "Don't panic"
477 return "Don't panic"
480
478
481 assert "meaning_of_life(question=None)" in pretty.pretty(meaning_of_life)
479 assert "meaning_of_life(question=None)" in pretty.pretty(meaning_of_life)
482
480
483
481
484 class OrderedCounter(Counter, OrderedDict):
482 class OrderedCounter(Counter, OrderedDict):
485 'Counter that remembers the order elements are first encountered'
483 'Counter that remembers the order elements are first encountered'
486
484
487 def __repr__(self):
485 def __repr__(self):
488 return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))
486 return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))
489
487
490 def __reduce__(self):
488 def __reduce__(self):
491 return self.__class__, (OrderedDict(self),)
489 return self.__class__, (OrderedDict(self),)
492
490
493 class MySet(set): # Override repr of a basic type
491 class MySet(set): # Override repr of a basic type
494 def __repr__(self):
492 def __repr__(self):
495 return 'mine'
493 return 'mine'
496
494
497 def test_custom_repr():
495 def test_custom_repr():
498 """A custom repr should override a pretty printer for a parent type"""
496 """A custom repr should override a pretty printer for a parent type"""
499 oc = OrderedCounter("abracadabra")
497 oc = OrderedCounter("abracadabra")
500 assert "OrderedCounter(OrderedDict" in pretty.pretty(oc)
498 assert "OrderedCounter(OrderedDict" in pretty.pretty(oc)
501
499
502 assert pretty.pretty(MySet()) == "mine"
500 assert pretty.pretty(MySet()) == "mine"
@@ -1,342 +1,331
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Decorators for labeling test objects.
2 """Decorators for labeling test objects.
3
3
4 Decorators that merely return a modified version of the original function
4 Decorators that merely return a modified version of the original function
5 object are straightforward. Decorators that return a new function object need
5 object are straightforward. Decorators that return a new function object need
6 to use nose.tools.make_decorator(original_function)(decorator) in returning the
6 to use nose.tools.make_decorator(original_function)(decorator) in returning the
7 decorator, in order to preserve metadata such as function name, setup and
7 decorator, in order to preserve metadata such as function name, setup and
8 teardown functions and so on - see nose.tools for more information.
8 teardown functions and so on - see nose.tools for more information.
9
9
10 This module provides a set of useful decorators meant to be ready to use in
10 This module provides a set of useful decorators meant to be ready to use in
11 your own tests. See the bottom of the file for the ready-made ones, and if you
11 your own tests. See the bottom of the file for the ready-made ones, and if you
12 find yourself writing a new one that may be of generic use, add it here.
12 find yourself writing a new one that may be of generic use, add it here.
13
13
14 Included decorators:
14 Included decorators:
15
15
16
16
17 Lightweight testing that remains unittest-compatible.
17 Lightweight testing that remains unittest-compatible.
18
18
19 - An @as_unittest decorator can be used to tag any normal parameter-less
19 - An @as_unittest decorator can be used to tag any normal parameter-less
20 function as a unittest TestCase. Then, both nose and normal unittest will
20 function as a unittest TestCase. Then, both nose and normal unittest will
21 recognize it as such. This will make it easier to migrate away from Nose if
21 recognize it as such. This will make it easier to migrate away from Nose if
22 we ever need/want to while maintaining very lightweight tests.
22 we ever need/want to while maintaining very lightweight tests.
23
23
24 NOTE: This file contains IPython-specific decorators. Using the machinery in
24 NOTE: This file contains IPython-specific decorators. Using the machinery in
25 IPython.external.decorators, we import either numpy.testing.decorators if numpy is
25 IPython.external.decorators, we import either numpy.testing.decorators if numpy is
26 available, OR use equivalent code in IPython.external._decorators, which
26 available, OR use equivalent code in IPython.external._decorators, which
27 we've copied verbatim from numpy.
27 we've copied verbatim from numpy.
28
28
29 """
29 """
30
30
31 # Copyright (c) IPython Development Team.
31 # Copyright (c) IPython Development Team.
32 # Distributed under the terms of the Modified BSD License.
32 # Distributed under the terms of the Modified BSD License.
33
33
34 import os
34 import os
35 import shutil
35 import shutil
36 import sys
36 import sys
37 import tempfile
37 import tempfile
38 import unittest
38 import unittest
39 import warnings
39 import warnings
40 from importlib import import_module
40 from importlib import import_module
41
41
42 from decorator import decorator
42 from decorator import decorator
43
43
44 # Expose the unittest-driven decorators
44 # Expose the unittest-driven decorators
45 from .ipunittest import ipdoctest, ipdocstring
45 from .ipunittest import ipdoctest, ipdocstring
46
46
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48 # Classes and functions
48 # Classes and functions
49 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
50
50
51 # Simple example of the basic idea
51 # Simple example of the basic idea
52 def as_unittest(func):
52 def as_unittest(func):
53 """Decorator to make a simple function into a normal test via unittest."""
53 """Decorator to make a simple function into a normal test via unittest."""
54 class Tester(unittest.TestCase):
54 class Tester(unittest.TestCase):
55 def test(self):
55 def test(self):
56 func()
56 func()
57
57
58 Tester.__name__ = func.__name__
58 Tester.__name__ = func.__name__
59
59
60 return Tester
60 return Tester
61
61
62 # Utility functions
62 # Utility functions
63
63
64 def apply_wrapper(wrapper, func):
64 def apply_wrapper(wrapper, func):
65 """Apply a wrapper to a function for decoration.
65 """Apply a wrapper to a function for decoration.
66
66
67 This mixes Michele Simionato's decorator tool with nose's make_decorator,
67 This mixes Michele Simionato's decorator tool with nose's make_decorator,
68 to apply a wrapper in a decorator so that all nose attributes, as well as
68 to apply a wrapper in a decorator so that all nose attributes, as well as
69 function signature and other properties, survive the decoration cleanly.
69 function signature and other properties, survive the decoration cleanly.
70 This will ensure that wrapped functions can still be well introspected via
70 This will ensure that wrapped functions can still be well introspected via
71 IPython, for example.
71 IPython, for example.
72 """
72 """
73 warnings.warn("The function `apply_wrapper` is deprecated since IPython 4.0",
73 warnings.warn("The function `apply_wrapper` is deprecated since IPython 4.0",
74 DeprecationWarning, stacklevel=2)
74 DeprecationWarning, stacklevel=2)
75 import nose.tools
75 import nose.tools
76
76
77 return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
77 return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
78
78
79
79
80 def make_label_dec(label, ds=None):
80 def make_label_dec(label, ds=None):
81 """Factory function to create a decorator that applies one or more labels.
81 """Factory function to create a decorator that applies one or more labels.
82
82
83 Parameters
83 Parameters
84 ----------
84 ----------
85 label : string or sequence
85 label : string or sequence
86 One or more labels that will be applied by the decorator to the functions
86 One or more labels that will be applied by the decorator to the functions
87 it decorates. Labels are attributes of the decorated function with their
87 it decorates. Labels are attributes of the decorated function with their
88 value set to True.
88 value set to True.
89
89
90 ds : string
90 ds : string
91 An optional docstring for the resulting decorator. If not given, a
91 An optional docstring for the resulting decorator. If not given, a
92 default docstring is auto-generated.
92 default docstring is auto-generated.
93
93
94 Returns
94 Returns
95 -------
95 -------
96 A decorator.
96 A decorator.
97
97
98 Examples
98 Examples
99 --------
99 --------
100
100
101 A simple labeling decorator:
101 A simple labeling decorator:
102
102
103 >>> slow = make_label_dec('slow')
103 >>> slow = make_label_dec('slow')
104 >>> slow.__doc__
104 >>> slow.__doc__
105 "Labels a test as 'slow'."
105 "Labels a test as 'slow'."
106
106
107 And one that uses multiple labels and a custom docstring:
107 And one that uses multiple labels and a custom docstring:
108
108
109 >>> rare = make_label_dec(['slow','hard'],
109 >>> rare = make_label_dec(['slow','hard'],
110 ... "Mix labels 'slow' and 'hard' for rare tests.")
110 ... "Mix labels 'slow' and 'hard' for rare tests.")
111 >>> rare.__doc__
111 >>> rare.__doc__
112 "Mix labels 'slow' and 'hard' for rare tests."
112 "Mix labels 'slow' and 'hard' for rare tests."
113
113
114 Now, let's test using this one:
114 Now, let's test using this one:
115 >>> @rare
115 >>> @rare
116 ... def f(): pass
116 ... def f(): pass
117 ...
117 ...
118 >>>
118 >>>
119 >>> f.slow
119 >>> f.slow
120 True
120 True
121 >>> f.hard
121 >>> f.hard
122 True
122 True
123 """
123 """
124
124
125 warnings.warn("The function `make_label_dec` is deprecated since IPython 4.0",
125 warnings.warn("The function `make_label_dec` is deprecated since IPython 4.0",
126 DeprecationWarning, stacklevel=2)
126 DeprecationWarning, stacklevel=2)
127 if isinstance(label, str):
127 if isinstance(label, str):
128 labels = [label]
128 labels = [label]
129 else:
129 else:
130 labels = label
130 labels = label
131
131
132 # Validate that the given label(s) are OK for use in setattr() by doing a
132 # Validate that the given label(s) are OK for use in setattr() by doing a
133 # dry run on a dummy function.
133 # dry run on a dummy function.
134 tmp = lambda : None
134 tmp = lambda : None
135 for label in labels:
135 for label in labels:
136 setattr(tmp,label,True)
136 setattr(tmp,label,True)
137
137
138 # This is the actual decorator we'll return
138 # This is the actual decorator we'll return
139 def decor(f):
139 def decor(f):
140 for label in labels:
140 for label in labels:
141 setattr(f,label,True)
141 setattr(f,label,True)
142 return f
142 return f
143
143
144 # Apply the user's docstring, or autogenerate a basic one
144 # Apply the user's docstring, or autogenerate a basic one
145 if ds is None:
145 if ds is None:
146 ds = "Labels a test as %r." % label
146 ds = "Labels a test as %r." % label
147 decor.__doc__ = ds
147 decor.__doc__ = ds
148
148
149 return decor
149 return decor
150
150
151
151
152 def skip_iptest_but_not_pytest(f):
153 """
154 Warning this will make the test invisible to iptest.
155 """
156 import os
157
158 if os.environ.get("IPTEST_WORKING_DIR", None) is not None:
159 f.__test__ = False
160 return f
161
162
163 def skipif(skip_condition, msg=None):
152 def skipif(skip_condition, msg=None):
164 """Make function raise SkipTest exception if skip_condition is true
153 """Make function raise SkipTest exception if skip_condition is true
165
154
166 Parameters
155 Parameters
167 ----------
156 ----------
168
157
169 skip_condition : bool or callable
158 skip_condition : bool or callable
170 Flag to determine whether to skip test. If the condition is a
159 Flag to determine whether to skip test. If the condition is a
171 callable, it is used at runtime to dynamically make the decision. This
160 callable, it is used at runtime to dynamically make the decision. This
172 is useful for tests that may require costly imports, to delay the cost
161 is useful for tests that may require costly imports, to delay the cost
173 until the test suite is actually executed.
162 until the test suite is actually executed.
174 msg : string
163 msg : string
175 Message to give on raising a SkipTest exception.
164 Message to give on raising a SkipTest exception.
176
165
177 Returns
166 Returns
178 -------
167 -------
179 decorator : function
168 decorator : function
180 Decorator, which, when applied to a function, causes SkipTest
169 Decorator, which, when applied to a function, causes SkipTest
181 to be raised when the skip_condition was True, and the function
170 to be raised when the skip_condition was True, and the function
182 to be called normally otherwise.
171 to be called normally otherwise.
183 """
172 """
184 if msg is None:
173 if msg is None:
185 msg = "Test skipped due to test condition."
174 msg = "Test skipped due to test condition."
186
175
187 import pytest
176 import pytest
188
177
189 assert isinstance(skip_condition, bool)
178 assert isinstance(skip_condition, bool)
190 return pytest.mark.skipif(skip_condition, reason=msg)
179 return pytest.mark.skipif(skip_condition, reason=msg)
191
180
192
181
193 # A version with the condition set to true, common case just to attach a message
182 # A version with the condition set to true, common case just to attach a message
194 # to a skip decorator
183 # to a skip decorator
195 def skip(msg=None):
184 def skip(msg=None):
196 """Decorator factory - mark a test function for skipping from test suite.
185 """Decorator factory - mark a test function for skipping from test suite.
197
186
198 Parameters
187 Parameters
199 ----------
188 ----------
200 msg : string
189 msg : string
201 Optional message to be added.
190 Optional message to be added.
202
191
203 Returns
192 Returns
204 -------
193 -------
205 decorator : function
194 decorator : function
206 Decorator, which, when applied to a function, causes SkipTest
195 Decorator, which, when applied to a function, causes SkipTest
207 to be raised, with the optional message added.
196 to be raised, with the optional message added.
208 """
197 """
209 if msg and not isinstance(msg, str):
198 if msg and not isinstance(msg, str):
210 raise ValueError('invalid object passed to `@skip` decorator, did you '
199 raise ValueError('invalid object passed to `@skip` decorator, did you '
211 'meant `@skip()` with brackets ?')
200 'meant `@skip()` with brackets ?')
212 return skipif(True, msg)
201 return skipif(True, msg)
213
202
214
203
215 def onlyif(condition, msg):
204 def onlyif(condition, msg):
216 """The reverse from skipif, see skipif for details."""
205 """The reverse from skipif, see skipif for details."""
217
206
218 return skipif(not condition, msg)
207 return skipif(not condition, msg)
219
208
220 #-----------------------------------------------------------------------------
209 #-----------------------------------------------------------------------------
221 # Utility functions for decorators
210 # Utility functions for decorators
222 def module_not_available(module):
211 def module_not_available(module):
223 """Can module be imported? Returns true if module does NOT import.
212 """Can module be imported? Returns true if module does NOT import.
224
213
225 This is used to make a decorator to skip tests that require module to be
214 This is used to make a decorator to skip tests that require module to be
226 available, but delay the 'import numpy' to test execution time.
215 available, but delay the 'import numpy' to test execution time.
227 """
216 """
228 try:
217 try:
229 mod = import_module(module)
218 mod = import_module(module)
230 mod_not_avail = False
219 mod_not_avail = False
231 except ImportError:
220 except ImportError:
232 mod_not_avail = True
221 mod_not_avail = True
233
222
234 return mod_not_avail
223 return mod_not_avail
235
224
236
225
237 def decorated_dummy(dec, name):
226 def decorated_dummy(dec, name):
238 """Return a dummy function decorated with dec, with the given name.
227 """Return a dummy function decorated with dec, with the given name.
239
228
240 Examples
229 Examples
241 --------
230 --------
242 import IPython.testing.decorators as dec
231 import IPython.testing.decorators as dec
243 setup = dec.decorated_dummy(dec.skip_if_no_x11, __name__)
232 setup = dec.decorated_dummy(dec.skip_if_no_x11, __name__)
244 """
233 """
245 warnings.warn("The function `decorated_dummy` is deprecated since IPython 4.0",
234 warnings.warn("The function `decorated_dummy` is deprecated since IPython 4.0",
246 DeprecationWarning, stacklevel=2)
235 DeprecationWarning, stacklevel=2)
247 dummy = lambda: None
236 dummy = lambda: None
248 dummy.__name__ = name
237 dummy.__name__ = name
249 return dec(dummy)
238 return dec(dummy)
250
239
251 #-----------------------------------------------------------------------------
240 #-----------------------------------------------------------------------------
252 # Decorators for public use
241 # Decorators for public use
253
242
254 # Decorators to skip certain tests on specific platforms.
243 # Decorators to skip certain tests on specific platforms.
255 skip_win32 = skipif(sys.platform == 'win32',
244 skip_win32 = skipif(sys.platform == 'win32',
256 "This test does not run under Windows")
245 "This test does not run under Windows")
257 skip_linux = skipif(sys.platform.startswith('linux'),
246 skip_linux = skipif(sys.platform.startswith('linux'),
258 "This test does not run under Linux")
247 "This test does not run under Linux")
259 skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X")
248 skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X")
260
249
261
250
262 # Decorators to skip tests if not on specific platforms.
251 # Decorators to skip tests if not on specific platforms.
263 skip_if_not_win32 = skipif(sys.platform != 'win32',
252 skip_if_not_win32 = skipif(sys.platform != 'win32',
264 "This test only runs under Windows")
253 "This test only runs under Windows")
265 skip_if_not_linux = skipif(not sys.platform.startswith('linux'),
254 skip_if_not_linux = skipif(not sys.platform.startswith('linux'),
266 "This test only runs under Linux")
255 "This test only runs under Linux")
267 skip_if_not_osx = skipif(sys.platform != 'darwin',
256 skip_if_not_osx = skipif(sys.platform != 'darwin',
268 "This test only runs under OSX")
257 "This test only runs under OSX")
269
258
270
259
271 _x11_skip_cond = (sys.platform not in ('darwin', 'win32') and
260 _x11_skip_cond = (sys.platform not in ('darwin', 'win32') and
272 os.environ.get('DISPLAY', '') == '')
261 os.environ.get('DISPLAY', '') == '')
273 _x11_skip_msg = "Skipped under *nix when X11/XOrg not available"
262 _x11_skip_msg = "Skipped under *nix when X11/XOrg not available"
274
263
275 skip_if_no_x11 = skipif(_x11_skip_cond, _x11_skip_msg)
264 skip_if_no_x11 = skipif(_x11_skip_cond, _x11_skip_msg)
276
265
277
266
278 # Decorators to skip certain tests on specific platform/python combinations
267 # Decorators to skip certain tests on specific platform/python combinations
279 skip_win32_py38 = skipif(sys.version_info > (3,8) and os.name == 'nt')
268 skip_win32_py38 = skipif(sys.version_info > (3,8) and os.name == 'nt')
280
269
281
270
282 # not a decorator itself, returns a dummy function to be used as setup
271 # not a decorator itself, returns a dummy function to be used as setup
283 def skip_file_no_x11(name):
272 def skip_file_no_x11(name):
284 warnings.warn("The function `skip_file_no_x11` is deprecated since IPython 4.0",
273 warnings.warn("The function `skip_file_no_x11` is deprecated since IPython 4.0",
285 DeprecationWarning, stacklevel=2)
274 DeprecationWarning, stacklevel=2)
286 return decorated_dummy(skip_if_no_x11, name) if _x11_skip_cond else None
275 return decorated_dummy(skip_if_no_x11, name) if _x11_skip_cond else None
287
276
288 # Other skip decorators
277 # Other skip decorators
289
278
290 # generic skip without module
279 # generic skip without module
291 skip_without = lambda mod: skipif(module_not_available(mod), "This test requires %s" % mod)
280 skip_without = lambda mod: skipif(module_not_available(mod), "This test requires %s" % mod)
292
281
293 skipif_not_numpy = skip_without('numpy')
282 skipif_not_numpy = skip_without('numpy')
294
283
295 skipif_not_matplotlib = skip_without('matplotlib')
284 skipif_not_matplotlib = skip_without('matplotlib')
296
285
297 skipif_not_sympy = skip_without('sympy')
286 skipif_not_sympy = skip_without('sympy')
298
287
299 # A null 'decorator', useful to make more readable code that needs to pick
288 # A null 'decorator', useful to make more readable code that needs to pick
300 # between different decorators based on OS or other conditions
289 # between different decorators based on OS or other conditions
301 null_deco = lambda f: f
290 null_deco = lambda f: f
302
291
303 # Some tests only run where we can use unicode paths. Note that we can't just
292 # Some tests only run where we can use unicode paths. Note that we can't just
304 # check os.path.supports_unicode_filenames, which is always False on Linux.
293 # check os.path.supports_unicode_filenames, which is always False on Linux.
305 try:
294 try:
306 f = tempfile.NamedTemporaryFile(prefix=u"tmp€")
295 f = tempfile.NamedTemporaryFile(prefix=u"tmp€")
307 except UnicodeEncodeError:
296 except UnicodeEncodeError:
308 unicode_paths = False
297 unicode_paths = False
309 else:
298 else:
310 unicode_paths = True
299 unicode_paths = True
311 f.close()
300 f.close()
312
301
313 onlyif_unicode_paths = onlyif(unicode_paths, ("This test is only applicable "
302 onlyif_unicode_paths = onlyif(unicode_paths, ("This test is only applicable "
314 "where we can use unicode in filenames."))
303 "where we can use unicode in filenames."))
315
304
316
305
317 def onlyif_cmds_exist(*commands):
306 def onlyif_cmds_exist(*commands):
318 """
307 """
319 Decorator to skip test when at least one of `commands` is not found.
308 Decorator to skip test when at least one of `commands` is not found.
320 """
309 """
321 for cmd in commands:
310 for cmd in commands:
322 reason = f"This test runs only if command '{cmd}' is installed"
311 reason = f"This test runs only if command '{cmd}' is installed"
323 if not shutil.which(cmd):
312 if not shutil.which(cmd):
324 if os.environ.get("IPTEST_WORKING_DIR", None) is not None:
313 if os.environ.get("IPTEST_WORKING_DIR", None) is not None:
325 return skip(reason)
314 return skip(reason)
326 else:
315 else:
327 import pytest
316 import pytest
328
317
329 return pytest.mark.skip(reason=reason)
318 return pytest.mark.skip(reason=reason)
330 return null_deco
319 return null_deco
331
320
332 def onlyif_any_cmd_exists(*commands):
321 def onlyif_any_cmd_exists(*commands):
333 """
322 """
334 Decorator to skip test unless at least one of `commands` is found.
323 Decorator to skip test unless at least one of `commands` is found.
335 """
324 """
336 warnings.warn("The function `onlyif_any_cmd_exists` is deprecated since IPython 4.0",
325 warnings.warn("The function `onlyif_any_cmd_exists` is deprecated since IPython 4.0",
337 DeprecationWarning, stacklevel=2)
326 DeprecationWarning, stacklevel=2)
338 for cmd in commands:
327 for cmd in commands:
339 if shutil.which(cmd):
328 if shutil.which(cmd):
340 return null_deco
329 return null_deco
341 return skip("This test runs only if one of the commands {0} "
330 return skip("This test runs only if one of the commands {0} "
342 "is installed".format(commands))
331 "is installed".format(commands))
@@ -1,171 +1,166
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for IPython.utils.capture"""
2 """Tests for IPython.utils.capture"""
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2013 The IPython Development Team
5 # Copyright (C) 2013 The IPython Development Team
6 #
6 #
7 # Distributed under the terms of the BSD License. The full license is in
7 # Distributed under the terms of the BSD License. The full license is in
8 # the file COPYING, distributed as part of this software.
8 # the file COPYING, distributed as part of this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15
15
16 import sys
16 import sys
17
17
18 import pytest
18 import pytest
19
19
20 from IPython.testing.decorators import skip_iptest_but_not_pytest
21
22 from IPython.utils import capture
20 from IPython.utils import capture
23
21
24 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
25 # Globals
23 # Globals
26 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
27
25
28 _mime_map = dict(
26 _mime_map = dict(
29 _repr_png_="image/png",
27 _repr_png_="image/png",
30 _repr_jpeg_="image/jpeg",
28 _repr_jpeg_="image/jpeg",
31 _repr_svg_="image/svg+xml",
29 _repr_svg_="image/svg+xml",
32 _repr_html_="text/html",
30 _repr_html_="text/html",
33 _repr_json_="application/json",
31 _repr_json_="application/json",
34 _repr_javascript_="application/javascript",
32 _repr_javascript_="application/javascript",
35 )
33 )
36
34
37 basic_data = {
35 basic_data = {
38 'image/png' : b'binarydata',
36 'image/png' : b'binarydata',
39 'text/html' : "<b>bold</b>",
37 'text/html' : "<b>bold</b>",
40 }
38 }
41 basic_metadata = {
39 basic_metadata = {
42 'image/png' : {
40 'image/png' : {
43 'width' : 10,
41 'width' : 10,
44 'height' : 20,
42 'height' : 20,
45 },
43 },
46 }
44 }
47
45
48 full_data = {
46 full_data = {
49 'image/png' : b'binarydata',
47 'image/png' : b'binarydata',
50 'image/jpeg' : b'binarydata',
48 'image/jpeg' : b'binarydata',
51 'image/svg+xml' : "<svg>",
49 'image/svg+xml' : "<svg>",
52 'text/html' : "<b>bold</b>",
50 'text/html' : "<b>bold</b>",
53 'application/javascript' : "alert();",
51 'application/javascript' : "alert();",
54 'application/json' : "{}",
52 'application/json' : "{}",
55 }
53 }
56 full_metadata = {
54 full_metadata = {
57 'image/png' : {"png" : "exists"},
55 'image/png' : {"png" : "exists"},
58 'image/jpeg' : {"jpeg" : "exists"},
56 'image/jpeg' : {"jpeg" : "exists"},
59 'image/svg+xml' : {"svg" : "exists"},
57 'image/svg+xml' : {"svg" : "exists"},
60 'text/html' : {"html" : "exists"},
58 'text/html' : {"html" : "exists"},
61 'application/javascript' : {"js" : "exists"},
59 'application/javascript' : {"js" : "exists"},
62 'application/json' : {"json" : "exists"},
60 'application/json' : {"json" : "exists"},
63 }
61 }
64
62
65 hello_stdout = "hello, stdout"
63 hello_stdout = "hello, stdout"
66 hello_stderr = "hello, stderr"
64 hello_stderr = "hello, stderr"
67
65
68 #-----------------------------------------------------------------------------
66 #-----------------------------------------------------------------------------
69 # Test Functions
67 # Test Functions
70 #-----------------------------------------------------------------------------
68 #-----------------------------------------------------------------------------
71 @pytest.mark.parametrize("method_mime", _mime_map.items())
69 @pytest.mark.parametrize("method_mime", _mime_map.items())
72 @skip_iptest_but_not_pytest
73 def test_rich_output_empty(method_mime):
70 def test_rich_output_empty(method_mime):
74 """RichOutput with no args"""
71 """RichOutput with no args"""
75 rich = capture.RichOutput()
72 rich = capture.RichOutput()
76 method, mime = method_mime
73 method, mime = method_mime
77 assert getattr(rich, method)() is None
74 assert getattr(rich, method)() is None
78
75
79 def test_rich_output():
76 def test_rich_output():
80 """test RichOutput basics"""
77 """test RichOutput basics"""
81 data = basic_data
78 data = basic_data
82 metadata = basic_metadata
79 metadata = basic_metadata
83 rich = capture.RichOutput(data=data, metadata=metadata)
80 rich = capture.RichOutput(data=data, metadata=metadata)
84 assert rich._repr_html_() == data["text/html"]
81 assert rich._repr_html_() == data["text/html"]
85 assert rich._repr_png_() == (data["image/png"], metadata["image/png"])
82 assert rich._repr_png_() == (data["image/png"], metadata["image/png"])
86 assert rich._repr_latex_() is None
83 assert rich._repr_latex_() is None
87 assert rich._repr_javascript_() is None
84 assert rich._repr_javascript_() is None
88 assert rich._repr_svg_() is None
85 assert rich._repr_svg_() is None
89
86
90
87
91 @skip_iptest_but_not_pytest
92 @pytest.mark.parametrize("method_mime", _mime_map.items())
88 @pytest.mark.parametrize("method_mime", _mime_map.items())
93 def test_rich_output_no_metadata(method_mime):
89 def test_rich_output_no_metadata(method_mime):
94 """test RichOutput with no metadata"""
90 """test RichOutput with no metadata"""
95 data = full_data
91 data = full_data
96 rich = capture.RichOutput(data=data)
92 rich = capture.RichOutput(data=data)
97 method, mime = method_mime
93 method, mime = method_mime
98 assert getattr(rich, method)() == data[mime]
94 assert getattr(rich, method)() == data[mime]
99
95
100
96
101 @skip_iptest_but_not_pytest
102 @pytest.mark.parametrize("method_mime", _mime_map.items())
97 @pytest.mark.parametrize("method_mime", _mime_map.items())
103 def test_rich_output_metadata(method_mime):
98 def test_rich_output_metadata(method_mime):
104 """test RichOutput with metadata"""
99 """test RichOutput with metadata"""
105 data = full_data
100 data = full_data
106 metadata = full_metadata
101 metadata = full_metadata
107 rich = capture.RichOutput(data=data, metadata=metadata)
102 rich = capture.RichOutput(data=data, metadata=metadata)
108 method, mime = method_mime
103 method, mime = method_mime
109 assert getattr(rich, method)() == (data[mime], metadata[mime])
104 assert getattr(rich, method)() == (data[mime], metadata[mime])
110
105
111 def test_rich_output_display():
106 def test_rich_output_display():
112 """test RichOutput.display
107 """test RichOutput.display
113
108
114 This is a bit circular, because we are actually using the capture code we are testing
109 This is a bit circular, because we are actually using the capture code we are testing
115 to test itself.
110 to test itself.
116 """
111 """
117 data = full_data
112 data = full_data
118 rich = capture.RichOutput(data=data)
113 rich = capture.RichOutput(data=data)
119 with capture.capture_output() as cap:
114 with capture.capture_output() as cap:
120 rich.display()
115 rich.display()
121 assert len(cap.outputs) == 1
116 assert len(cap.outputs) == 1
122 rich2 = cap.outputs[0]
117 rich2 = cap.outputs[0]
123 assert rich2.data == rich.data
118 assert rich2.data == rich.data
124 assert rich2.metadata == rich.metadata
119 assert rich2.metadata == rich.metadata
125
120
126 def test_capture_output():
121 def test_capture_output():
127 """capture_output works"""
122 """capture_output works"""
128 rich = capture.RichOutput(data=full_data)
123 rich = capture.RichOutput(data=full_data)
129 with capture.capture_output() as cap:
124 with capture.capture_output() as cap:
130 print(hello_stdout, end="")
125 print(hello_stdout, end="")
131 print(hello_stderr, end="", file=sys.stderr)
126 print(hello_stderr, end="", file=sys.stderr)
132 rich.display()
127 rich.display()
133 assert hello_stdout == cap.stdout
128 assert hello_stdout == cap.stdout
134 assert hello_stderr == cap.stderr
129 assert hello_stderr == cap.stderr
135
130
136
131
137 def test_capture_output_no_stdout():
132 def test_capture_output_no_stdout():
138 """test capture_output(stdout=False)"""
133 """test capture_output(stdout=False)"""
139 rich = capture.RichOutput(data=full_data)
134 rich = capture.RichOutput(data=full_data)
140 with capture.capture_output(stdout=False) as cap:
135 with capture.capture_output(stdout=False) as cap:
141 print(hello_stdout, end="")
136 print(hello_stdout, end="")
142 print(hello_stderr, end="", file=sys.stderr)
137 print(hello_stderr, end="", file=sys.stderr)
143 rich.display()
138 rich.display()
144 assert "" == cap.stdout
139 assert "" == cap.stdout
145 assert hello_stderr == cap.stderr
140 assert hello_stderr == cap.stderr
146 assert len(cap.outputs) == 1
141 assert len(cap.outputs) == 1
147
142
148
143
149 def test_capture_output_no_stderr():
144 def test_capture_output_no_stderr():
150 """test capture_output(stderr=False)"""
145 """test capture_output(stderr=False)"""
151 rich = capture.RichOutput(data=full_data)
146 rich = capture.RichOutput(data=full_data)
152 # add nested capture_output so stderr doesn't make it to nose output
147 # add nested capture_output so stderr doesn't make it to nose output
153 with capture.capture_output(), capture.capture_output(stderr=False) as cap:
148 with capture.capture_output(), capture.capture_output(stderr=False) as cap:
154 print(hello_stdout, end="")
149 print(hello_stdout, end="")
155 print(hello_stderr, end="", file=sys.stderr)
150 print(hello_stderr, end="", file=sys.stderr)
156 rich.display()
151 rich.display()
157 assert hello_stdout == cap.stdout
152 assert hello_stdout == cap.stdout
158 assert "" == cap.stderr
153 assert "" == cap.stderr
159 assert len(cap.outputs) == 1
154 assert len(cap.outputs) == 1
160
155
161
156
162 def test_capture_output_no_display():
157 def test_capture_output_no_display():
163 """test capture_output(display=False)"""
158 """test capture_output(display=False)"""
164 rich = capture.RichOutput(data=full_data)
159 rich = capture.RichOutput(data=full_data)
165 with capture.capture_output(display=False) as cap:
160 with capture.capture_output(display=False) as cap:
166 print(hello_stdout, end="")
161 print(hello_stdout, end="")
167 print(hello_stderr, end="", file=sys.stderr)
162 print(hello_stderr, end="", file=sys.stderr)
168 rich.display()
163 rich.display()
169 assert hello_stdout == cap.stdout
164 assert hello_stdout == cap.stdout
170 assert hello_stderr == cap.stderr
165 assert hello_stderr == cap.stderr
171 assert cap.outputs == []
166 assert cap.outputs == []
@@ -1,73 +1,69
1 # coding: utf-8
1 # coding: utf-8
2 """Test suite for our color utilities.
2 """Test suite for our color utilities.
3
3
4 Authors
4 Authors
5 -------
5 -------
6
6
7 * Min RK
7 * Min RK
8 """
8 """
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2011 The IPython Development Team
10 # Copyright (C) 2011 The IPython Development Team
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING.txt, distributed as part of this software.
13 # the file COPYING.txt, distributed as part of this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 from IPython.testing.decorators import skip_iptest_but_not_pytest
21
22 # our own
20 # our own
23 from IPython.utils.PyColorize import Parser
21 from IPython.utils.PyColorize import Parser
24 import io
22 import io
25 import pytest
23 import pytest
26
24
27
25
28 @pytest.fixture(scope="module", params=("Linux", "NoColor", "LightBG", "Neutral"))
26 @pytest.fixture(scope="module", params=("Linux", "NoColor", "LightBG", "Neutral"))
29 def style(request):
27 def style(request):
30 yield request.param
28 yield request.param
31
29
32 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
33 # Test functions
31 # Test functions
34 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
35
33
36 sample = """
34 sample = """
37 def function(arg, *args, kwarg=True, **kwargs):
35 def function(arg, *args, kwarg=True, **kwargs):
38 '''
36 '''
39 this is docs
37 this is docs
40 '''
38 '''
41 pass is True
39 pass is True
42 False == None
40 False == None
43
41
44 with io.open(ru'unicode'):
42 with io.open(ru'unicode'):
45 raise ValueError("\n escape \r sequence")
43 raise ValueError("\n escape \r sequence")
46
44
47 print("wΔ›ird ΓΌnicoΓ°e")
45 print("wΔ›ird ΓΌnicoΓ°e")
48
46
49 class Bar(Super):
47 class Bar(Super):
50
48
51 def __init__(self):
49 def __init__(self):
52 super(Bar, self).__init__(1**2, 3^4, 5 or 6)
50 super(Bar, self).__init__(1**2, 3^4, 5 or 6)
53 """
51 """
54
52
55
53
56 @skip_iptest_but_not_pytest
57 def test_parse_sample(style):
54 def test_parse_sample(style):
58 """and test writing to a buffer"""
55 """and test writing to a buffer"""
59 buf = io.StringIO()
56 buf = io.StringIO()
60 p = Parser(style=style)
57 p = Parser(style=style)
61 p.format(sample, buf)
58 p.format(sample, buf)
62 buf.seek(0)
59 buf.seek(0)
63 f1 = buf.read()
60 f1 = buf.read()
64
61
65 assert "ERROR" not in f1
62 assert "ERROR" not in f1
66
63
67
64
68 @skip_iptest_but_not_pytest
69 def test_parse_error(style):
65 def test_parse_error(style):
70 p = Parser(style=style)
66 p = Parser(style=style)
71 f1 = p.format(")", "str")
67 f1 = p.format(")", "str")
72 if style != "NoColor":
68 if style != "NoColor":
73 assert "ERROR" in f1
69 assert "ERROR" in f1
@@ -1,143 +1,141
1 """Tests for tokenutil"""
1 """Tests for tokenutil"""
2 # Copyright (c) IPython Development Team.
2 # Copyright (c) IPython Development Team.
3 # Distributed under the terms of the Modified BSD License.
3 # Distributed under the terms of the Modified BSD License.
4
4
5 import pytest
5 import pytest
6 from IPython.testing.decorators import skip_iptest_but_not_pytest
7
6
8 from IPython.utils.tokenutil import token_at_cursor, line_at_cursor
7 from IPython.utils.tokenutil import token_at_cursor, line_at_cursor
9
8
10 def expect_token(expected, cell, cursor_pos):
9 def expect_token(expected, cell, cursor_pos):
11 token = token_at_cursor(cell, cursor_pos)
10 token = token_at_cursor(cell, cursor_pos)
12 offset = 0
11 offset = 0
13 for line in cell.splitlines():
12 for line in cell.splitlines():
14 if offset + len(line) >= cursor_pos:
13 if offset + len(line) >= cursor_pos:
15 break
14 break
16 else:
15 else:
17 offset += len(line)+1
16 offset += len(line)+1
18 column = cursor_pos - offset
17 column = cursor_pos - offset
19 line_with_cursor = "%s|%s" % (line[:column], line[column:])
18 line_with_cursor = "%s|%s" % (line[:column], line[column:])
20 assert token == expected, "Expected %r, got %r in: %r (pos %i)" % (
19 assert token == expected, "Expected %r, got %r in: %r (pos %i)" % (
21 expected,
20 expected,
22 token,
21 token,
23 line_with_cursor,
22 line_with_cursor,
24 cursor_pos,
23 cursor_pos,
25 )
24 )
26
25
27
26
28 def test_simple():
27 def test_simple():
29 cell = "foo"
28 cell = "foo"
30 for i in range(len(cell)):
29 for i in range(len(cell)):
31 expect_token("foo", cell, i)
30 expect_token("foo", cell, i)
32
31
33 def test_function():
32 def test_function():
34 cell = "foo(a=5, b='10')"
33 cell = "foo(a=5, b='10')"
35 expected = 'foo'
34 expected = 'foo'
36 # up to `foo(|a=`
35 # up to `foo(|a=`
37 for i in range(cell.find('a=') + 1):
36 for i in range(cell.find('a=') + 1):
38 expect_token("foo", cell, i)
37 expect_token("foo", cell, i)
39 # find foo after `=`
38 # find foo after `=`
40 for i in [cell.find('=') + 1, cell.rfind('=') + 1]:
39 for i in [cell.find('=') + 1, cell.rfind('=') + 1]:
41 expect_token("foo", cell, i)
40 expect_token("foo", cell, i)
42 # in between `5,|` and `|b=`
41 # in between `5,|` and `|b=`
43 for i in range(cell.find(','), cell.find('b=')):
42 for i in range(cell.find(','), cell.find('b=')):
44 expect_token("foo", cell, i)
43 expect_token("foo", cell, i)
45
44
46 def test_multiline():
45 def test_multiline():
47 cell = '\n'.join([
46 cell = '\n'.join([
48 'a = 5',
47 'a = 5',
49 'b = hello("string", there)'
48 'b = hello("string", there)'
50 ])
49 ])
51 expected = 'hello'
50 expected = 'hello'
52 start = cell.index(expected) + 1
51 start = cell.index(expected) + 1
53 for i in range(start, start + len(expected)):
52 for i in range(start, start + len(expected)):
54 expect_token(expected, cell, i)
53 expect_token(expected, cell, i)
55 expected = 'hello'
54 expected = 'hello'
56 start = cell.index(expected) + 1
55 start = cell.index(expected) + 1
57 for i in range(start, start + len(expected)):
56 for i in range(start, start + len(expected)):
58 expect_token(expected, cell, i)
57 expect_token(expected, cell, i)
59
58
60 def test_multiline_token():
59 def test_multiline_token():
61 cell = '\n'.join([
60 cell = '\n'.join([
62 '"""\n\nxxxxxxxxxx\n\n"""',
61 '"""\n\nxxxxxxxxxx\n\n"""',
63 '5, """',
62 '5, """',
64 'docstring',
63 'docstring',
65 'multiline token',
64 'multiline token',
66 '""", [',
65 '""", [',
67 '2, 3, "complicated"]',
66 '2, 3, "complicated"]',
68 'b = hello("string", there)'
67 'b = hello("string", there)'
69 ])
68 ])
70 expected = 'hello'
69 expected = 'hello'
71 start = cell.index(expected) + 1
70 start = cell.index(expected) + 1
72 for i in range(start, start + len(expected)):
71 for i in range(start, start + len(expected)):
73 expect_token(expected, cell, i)
72 expect_token(expected, cell, i)
74 expected = 'hello'
73 expected = 'hello'
75 start = cell.index(expected) + 1
74 start = cell.index(expected) + 1
76 for i in range(start, start + len(expected)):
75 for i in range(start, start + len(expected)):
77 expect_token(expected, cell, i)
76 expect_token(expected, cell, i)
78
77
79 def test_nested_call():
78 def test_nested_call():
80 cell = "foo(bar(a=5), b=10)"
79 cell = "foo(bar(a=5), b=10)"
81 expected = 'foo'
80 expected = 'foo'
82 start = cell.index('bar') + 1
81 start = cell.index('bar') + 1
83 for i in range(start, start + 3):
82 for i in range(start, start + 3):
84 expect_token(expected, cell, i)
83 expect_token(expected, cell, i)
85 expected = 'bar'
84 expected = 'bar'
86 start = cell.index('a=')
85 start = cell.index('a=')
87 for i in range(start, start + 3):
86 for i in range(start, start + 3):
88 expect_token(expected, cell, i)
87 expect_token(expected, cell, i)
89 expected = 'foo'
88 expected = 'foo'
90 start = cell.index(')') + 1
89 start = cell.index(')') + 1
91 for i in range(start, len(cell)-1):
90 for i in range(start, len(cell)-1):
92 expect_token(expected, cell, i)
91 expect_token(expected, cell, i)
93
92
94 def test_attrs():
93 def test_attrs():
95 cell = "a = obj.attr.subattr"
94 cell = "a = obj.attr.subattr"
96 expected = 'obj'
95 expected = 'obj'
97 idx = cell.find('obj') + 1
96 idx = cell.find('obj') + 1
98 for i in range(idx, idx + 3):
97 for i in range(idx, idx + 3):
99 expect_token(expected, cell, i)
98 expect_token(expected, cell, i)
100 idx = cell.find('.attr') + 2
99 idx = cell.find('.attr') + 2
101 expected = 'obj.attr'
100 expected = 'obj.attr'
102 for i in range(idx, idx + 4):
101 for i in range(idx, idx + 4):
103 expect_token(expected, cell, i)
102 expect_token(expected, cell, i)
104 idx = cell.find('.subattr') + 2
103 idx = cell.find('.subattr') + 2
105 expected = 'obj.attr.subattr'
104 expected = 'obj.attr.subattr'
106 for i in range(idx, len(cell)):
105 for i in range(idx, len(cell)):
107 expect_token(expected, cell, i)
106 expect_token(expected, cell, i)
108
107
109 def test_line_at_cursor():
108 def test_line_at_cursor():
110 cell = ""
109 cell = ""
111 (line, offset) = line_at_cursor(cell, cursor_pos=11)
110 (line, offset) = line_at_cursor(cell, cursor_pos=11)
112 assert line == ""
111 assert line == ""
113 assert offset == 0
112 assert offset == 0
114
113
115 # The position after a newline should be the start of the following line.
114 # The position after a newline should be the start of the following line.
116 cell = "One\nTwo\n"
115 cell = "One\nTwo\n"
117 (line, offset) = line_at_cursor(cell, cursor_pos=4)
116 (line, offset) = line_at_cursor(cell, cursor_pos=4)
118 assert line == "Two\n"
117 assert line == "Two\n"
119 assert offset == 4
118 assert offset == 4
120
119
121 # The end of a cell should be on the last line
120 # The end of a cell should be on the last line
122 cell = "pri\npri"
121 cell = "pri\npri"
123 (line, offset) = line_at_cursor(cell, cursor_pos=7)
122 (line, offset) = line_at_cursor(cell, cursor_pos=7)
124 assert line == "pri"
123 assert line == "pri"
125 assert offset == 4
124 assert offset == 4
126
125
127
126
128 @pytest.mark.parametrize(
127 @pytest.mark.parametrize(
129 "c, token",
128 "c, token",
130 zip(
129 zip(
131 list(range(16, 22)) + list(range(22, 28)),
130 list(range(16, 22)) + list(range(22, 28)),
132 ["int"] * (22 - 16) + ["map"] * (28 - 22),
131 ["int"] * (22 - 16) + ["map"] * (28 - 22),
133 ),
132 ),
134 )
133 )
135 @skip_iptest_but_not_pytest
136 def test_multiline_statement(c, token):
134 def test_multiline_statement(c, token):
137 cell = """a = (1,
135 cell = """a = (1,
138 3)
136 3)
139
137
140 int()
138 int()
141 map()
139 map()
142 """
140 """
143 expect_token(token, cell, c)
141 expect_token(token, cell, c)
General Comments 0
You need to be logged in to leave comments. Login now