##// END OF EJS Templates
Enable `check_make_token_by_line_never_ends_empty` test...
Nikita Kniazev -
Show More
@@ -1,387 +1,388 b''
1 1 """Tests for the token-based transformers in IPython.core.inputtransformer2
2 2
3 3 Line-based transformers are the simpler ones; token-based transformers are
4 4 more complex. See test_inputtransformer2_line for tests for line-based
5 5 transformations.
6 6 """
7 7 import string
8 8 import sys
9 9 from textwrap import dedent
10 10
11 11 import pytest
12 12
13 13 from IPython.core import inputtransformer2 as ipt2
14 14 from IPython.core.inputtransformer2 import _find_assign_op, make_tokens_by_line
15 15 from IPython.testing.decorators import skip_iptest_but_not_pytest
16 16
17 17 MULTILINE_MAGIC = ("""\
18 18 a = f()
19 19 %foo \\
20 20 bar
21 21 g()
22 22 """.splitlines(keepends=True), (2, 0), """\
23 23 a = f()
24 24 get_ipython().run_line_magic('foo', ' bar')
25 25 g()
26 26 """.splitlines(keepends=True))
27 27
28 28 INDENTED_MAGIC = ("""\
29 29 for a in range(5):
30 30 %ls
31 31 """.splitlines(keepends=True), (2, 4), """\
32 32 for a in range(5):
33 33 get_ipython().run_line_magic('ls', '')
34 34 """.splitlines(keepends=True))
35 35
36 36 CRLF_MAGIC = ([
37 37 "a = f()\n",
38 38 "%ls\r\n",
39 39 "g()\n"
40 40 ], (2, 0), [
41 41 "a = f()\n",
42 42 "get_ipython().run_line_magic('ls', '')\n",
43 43 "g()\n"
44 44 ])
45 45
46 46 MULTILINE_MAGIC_ASSIGN = ("""\
47 47 a = f()
48 48 b = %foo \\
49 49 bar
50 50 g()
51 51 """.splitlines(keepends=True), (2, 4), """\
52 52 a = f()
53 53 b = get_ipython().run_line_magic('foo', ' bar')
54 54 g()
55 55 """.splitlines(keepends=True))
56 56
57 57 MULTILINE_SYSTEM_ASSIGN = ("""\
58 58 a = f()
59 59 b = !foo \\
60 60 bar
61 61 g()
62 62 """.splitlines(keepends=True), (2, 4), """\
63 63 a = f()
64 64 b = get_ipython().getoutput('foo bar')
65 65 g()
66 66 """.splitlines(keepends=True))
67 67
68 68 #####
69 69
70 70 MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT = ("""\
71 71 def test():
72 72 for i in range(1):
73 73 print(i)
74 74 res =! ls
75 75 """.splitlines(keepends=True), (4, 7), '''\
76 76 def test():
77 77 for i in range(1):
78 78 print(i)
79 79 res =get_ipython().getoutput(\' ls\')
80 80 '''.splitlines(keepends=True))
81 81
82 82 ######
83 83
84 84 AUTOCALL_QUOTE = (
85 85 [",f 1 2 3\n"], (1, 0),
86 86 ['f("1", "2", "3")\n']
87 87 )
88 88
89 89 AUTOCALL_QUOTE2 = (
90 90 [";f 1 2 3\n"], (1, 0),
91 91 ['f("1 2 3")\n']
92 92 )
93 93
94 94 AUTOCALL_PAREN = (
95 95 ["/f 1 2 3\n"], (1, 0),
96 96 ['f(1, 2, 3)\n']
97 97 )
98 98
99 99 SIMPLE_HELP = (
100 100 ["foo?\n"], (1, 0),
101 101 ["get_ipython().run_line_magic('pinfo', 'foo')\n"]
102 102 )
103 103
104 104 DETAILED_HELP = (
105 105 ["foo??\n"], (1, 0),
106 106 ["get_ipython().run_line_magic('pinfo2', 'foo')\n"]
107 107 )
108 108
109 109 MAGIC_HELP = (
110 110 ["%foo?\n"], (1, 0),
111 111 ["get_ipython().run_line_magic('pinfo', '%foo')\n"]
112 112 )
113 113
114 114 HELP_IN_EXPR = (
115 115 ["a = b + c?\n"], (1, 0),
116 116 ["get_ipython().set_next_input('a = b + c');"
117 117 "get_ipython().run_line_magic('pinfo', 'c')\n"]
118 118 )
119 119
120 120 HELP_CONTINUED_LINE = ("""\
121 121 a = \\
122 122 zip?
123 123 """.splitlines(keepends=True), (1, 0),
124 124 [r"get_ipython().set_next_input('a = \\\nzip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
125 125 )
126 126
127 127 HELP_MULTILINE = ("""\
128 128 (a,
129 129 b) = zip?
130 130 """.splitlines(keepends=True), (1, 0),
131 131 [r"get_ipython().set_next_input('(a,\nb) = zip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
132 132 )
133 133
134 134 HELP_UNICODE = (
135 135 ["Ο€.foo?\n"], (1, 0),
136 136 ["get_ipython().run_line_magic('pinfo', 'Ο€.foo')\n"]
137 137 )
138 138
139 139
140 140 def null_cleanup_transformer(lines):
141 141 """
142 142 A cleanup transform that returns an empty list.
143 143 """
144 144 return []
145 145
146 def check_make_token_by_line_never_ends_empty():
146
147 def test_check_make_token_by_line_never_ends_empty():
147 148 """
148 149 Check that not sequence of single or double characters ends up leading to en empty list of tokens
149 150 """
150 151 from string import printable
151 152 for c in printable:
152 153 assert make_tokens_by_line(c)[-1] != []
153 154 for k in printable:
154 155 assert make_tokens_by_line(c + k)[-1] != []
155 156
156 157
157 158 def check_find(transformer, case, match=True):
158 159 sample, expected_start, _ = case
159 160 tbl = make_tokens_by_line(sample)
160 161 res = transformer.find(tbl)
161 162 if match:
162 163 # start_line is stored 0-indexed, expected values are 1-indexed
163 164 assert (res.start_line + 1, res.start_col) == expected_start
164 165 return res
165 166 else:
166 167 assert res is None
167 168
168 169 def check_transform(transformer_cls, case):
169 170 lines, start, expected = case
170 171 transformer = transformer_cls(start)
171 172 assert transformer.transform(lines) == expected
172 173
173 174 def test_continued_line():
174 175 lines = MULTILINE_MAGIC_ASSIGN[0]
175 176 assert ipt2.find_end_of_continued_line(lines, 1) == 2
176 177
177 178 assert ipt2.assemble_continued_line(lines, (1, 5), 2) == "foo bar"
178 179
179 180 def test_find_assign_magic():
180 181 check_find(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
181 182 check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN, match=False)
182 183 check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT, match=False)
183 184
184 185 def test_transform_assign_magic():
185 186 check_transform(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
186 187
187 188 def test_find_assign_system():
188 189 check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
189 190 check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
190 191 check_find(ipt2.SystemAssign, (["a = !ls\n"], (1, 5), None))
191 192 check_find(ipt2.SystemAssign, (["a=!ls\n"], (1, 2), None))
192 193 check_find(ipt2.SystemAssign, MULTILINE_MAGIC_ASSIGN, match=False)
193 194
194 195 def test_transform_assign_system():
195 196 check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
196 197 check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
197 198
198 199 def test_find_magic_escape():
199 200 check_find(ipt2.EscapedCommand, MULTILINE_MAGIC)
200 201 check_find(ipt2.EscapedCommand, INDENTED_MAGIC)
201 202 check_find(ipt2.EscapedCommand, MULTILINE_MAGIC_ASSIGN, match=False)
202 203
203 204 def test_transform_magic_escape():
204 205 check_transform(ipt2.EscapedCommand, MULTILINE_MAGIC)
205 206 check_transform(ipt2.EscapedCommand, INDENTED_MAGIC)
206 207 check_transform(ipt2.EscapedCommand, CRLF_MAGIC)
207 208
208 209 def test_find_autocalls():
209 210 for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
210 211 print("Testing %r" % case[0])
211 212 check_find(ipt2.EscapedCommand, case)
212 213
213 214 def test_transform_autocall():
214 215 for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
215 216 print("Testing %r" % case[0])
216 217 check_transform(ipt2.EscapedCommand, case)
217 218
218 219 def test_find_help():
219 220 for case in [SIMPLE_HELP, DETAILED_HELP, MAGIC_HELP, HELP_IN_EXPR]:
220 221 check_find(ipt2.HelpEnd, case)
221 222
222 223 tf = check_find(ipt2.HelpEnd, HELP_CONTINUED_LINE)
223 224 assert tf.q_line == 1
224 225 assert tf.q_col == 3
225 226
226 227 tf = check_find(ipt2.HelpEnd, HELP_MULTILINE)
227 228 assert tf.q_line == 1
228 229 assert tf.q_col == 8
229 230
230 231 # ? in a comment does not trigger help
231 232 check_find(ipt2.HelpEnd, (["foo # bar?\n"], None, None), match=False)
232 233 # Nor in a string
233 234 check_find(ipt2.HelpEnd, (["foo = '''bar?\n"], None, None), match=False)
234 235
235 236 def test_transform_help():
236 237 tf = ipt2.HelpEnd((1, 0), (1, 9))
237 238 assert tf.transform(HELP_IN_EXPR[0]) == HELP_IN_EXPR[2]
238 239
239 240 tf = ipt2.HelpEnd((1, 0), (2, 3))
240 241 assert tf.transform(HELP_CONTINUED_LINE[0]) == HELP_CONTINUED_LINE[2]
241 242
242 243 tf = ipt2.HelpEnd((1, 0), (2, 8))
243 244 assert tf.transform(HELP_MULTILINE[0]) == HELP_MULTILINE[2]
244 245
245 246 tf = ipt2.HelpEnd((1, 0), (1, 0))
246 247 assert tf.transform(HELP_UNICODE[0]) == HELP_UNICODE[2]
247 248
248 249 def test_find_assign_op_dedent():
249 250 """
250 251 be careful that empty token like dedent are not counted as parens
251 252 """
252 253 class Tk:
253 254 def __init__(self, s):
254 255 self.string = s
255 256
256 257 assert _find_assign_op([Tk(s) for s in ("", "a", "=", "b")]) == 2
257 258 assert (
258 259 _find_assign_op([Tk(s) for s in ("", "(", "a", "=", "b", ")", "=", "5")]) == 6
259 260 )
260 261
261 262
262 263 examples = [
263 264 pytest.param("a = 1", "complete", None),
264 265 pytest.param("for a in range(5):", "incomplete", 4),
265 266 pytest.param("for a in range(5):\n if a > 0:", "incomplete", 8),
266 267 pytest.param("raise = 2", "invalid", None),
267 268 pytest.param("a = [1,\n2,", "incomplete", 0),
268 269 pytest.param("(\n))", "incomplete", 0),
269 270 pytest.param("\\\r\n", "incomplete", 0),
270 271 pytest.param("a = '''\n hi", "incomplete", 3),
271 272 pytest.param("def a():\n x=1\n global x", "invalid", None),
272 273 pytest.param(
273 274 "a \\ ",
274 275 "invalid",
275 276 None,
276 277 marks=pytest.mark.xfail(
277 278 reason="Bug in python 3.9.8 – bpo 45738",
278 279 condition=sys.version_info[:3] == (3, 9, 8),
279 280 raises=SystemError,
280 281 strict=True,
281 282 ),
282 283 ), # Nothing allowed after backslash,
283 284 pytest.param("1\\\n+2", "complete", None),
284 285 ]
285 286
286 287
287 288 @skip_iptest_but_not_pytest
288 289 @pytest.mark.parametrize("code, expected, number", examples)
289 290 def test_check_complete_param(code, expected, number):
290 291 cc = ipt2.TransformerManager().check_complete
291 292 assert cc(code) == (expected, number)
292 293
293 294
294 295 @skip_iptest_but_not_pytest
295 296 @pytest.mark.xfail(
296 297 reason="Bug in python 3.9.8 – bpo 45738",
297 298 condition=sys.version_info[:3] == (3, 9, 8),
298 299 )
299 300 def test_check_complete():
300 301 cc = ipt2.TransformerManager().check_complete
301 302
302 303 example = dedent("""
303 304 if True:
304 305 a=1""" )
305 306
306 307 assert cc(example) == ("incomplete", 4)
307 308 assert cc(example + "\n") == ("complete", None)
308 309 assert cc(example + "\n ") == ("complete", None)
309 310
310 311 # no need to loop on all the letters/numbers.
311 312 short = '12abAB'+string.printable[62:]
312 313 for c in short:
313 314 # test does not raise:
314 315 cc(c)
315 316 for k in short:
316 317 cc(c+k)
317 318
318 319 assert cc("def f():\n x=0\n \\\n ") == ("incomplete", 2)
319 320
320 321
321 322 def test_check_complete_II():
322 323 """
323 324 Test that multiple line strings are properly handled.
324 325
325 326 Separate test function for convenience
326 327
327 328 """
328 329 cc = ipt2.TransformerManager().check_complete
329 330 assert cc('''def foo():\n """''') == ("incomplete", 4)
330 331
331 332
332 333 def test_check_complete_invalidates_sunken_brackets():
333 334 """
334 335 Test that a single line with more closing brackets than the opening ones is
335 336 interpreted as invalid
336 337 """
337 338 cc = ipt2.TransformerManager().check_complete
338 339 assert cc(")") == ("invalid", None)
339 340 assert cc("]") == ("invalid", None)
340 341 assert cc("}") == ("invalid", None)
341 342 assert cc(")(") == ("invalid", None)
342 343 assert cc("][") == ("invalid", None)
343 344 assert cc("}{") == ("invalid", None)
344 345 assert cc("]()(") == ("invalid", None)
345 346 assert cc("())(") == ("invalid", None)
346 347 assert cc(")[](") == ("invalid", None)
347 348 assert cc("()](") == ("invalid", None)
348 349
349 350
350 351 def test_null_cleanup_transformer():
351 352 manager = ipt2.TransformerManager()
352 353 manager.cleanup_transforms.insert(0, null_cleanup_transformer)
353 354 assert manager.transform_cell("") == ""
354 355
355 356
356 357
357 358
358 359 def test_side_effects_I():
359 360 count = 0
360 361 def counter(lines):
361 362 nonlocal count
362 363 count += 1
363 364 return lines
364 365
365 366 counter.has_side_effects = True
366 367
367 368 manager = ipt2.TransformerManager()
368 369 manager.cleanup_transforms.insert(0, counter)
369 370 assert manager.check_complete("a=1\n") == ('complete', None)
370 371 assert count == 0
371 372
372 373
373 374
374 375
375 376 def test_side_effects_II():
376 377 count = 0
377 378 def counter(lines):
378 379 nonlocal count
379 380 count += 1
380 381 return lines
381 382
382 383 counter.has_side_effects = True
383 384
384 385 manager = ipt2.TransformerManager()
385 386 manager.line_transforms.insert(0, counter)
386 387 assert manager.check_complete("b=1\n") == ('complete', None)
387 388 assert count == 0
General Comments 0
You need to be logged in to leave comments. Login now