##// END OF EJS Templates
Add failing test for line continuation in multiline string
Thomas Kluyver -
Show More
@@ -1,489 +1,494 b''
1 1 import tokenize
2 2 import nose.tools as nt
3 3
4 4 from IPython.testing import tools as tt
5 5 from IPython.utils import py3compat
6 6 u_fmt = py3compat.u_format
7 7
8 8 from IPython.core import inputtransformer as ipt
9 9
10 10 def transform_and_reset(transformer):
11 11 transformer = transformer()
12 12 def transform(inp):
13 13 try:
14 14 return transformer.push(inp)
15 15 finally:
16 16 transformer.reset()
17 17
18 18 return transform
19 19
20 20 # Transformer tests
21 21 def transform_checker(tests, transformer, **kwargs):
22 22 """Utility to loop over test inputs"""
23 23 transformer = transformer(**kwargs)
24 24 try:
25 25 for inp, tr in tests:
26 26 if inp is None:
27 27 out = transformer.reset()
28 28 else:
29 29 out = transformer.push(inp)
30 30 nt.assert_equal(out, tr)
31 31 finally:
32 32 transformer.reset()
33 33
34 34 # Data for all the syntax tests in the form of lists of pairs of
35 35 # raw/transformed input. We store it here as a global dict so that we can use
36 36 # it both within single-function tests and also to validate the behavior of the
37 37 # larger objects
38 38
39 39 syntax = \
40 40 dict(assign_system =
41 41 [(i,py3compat.u_format(o)) for i,o in \
42 42 [(u'a =! ls', "a = get_ipython().getoutput({u}'ls')"),
43 43 (u'b = !ls', "b = get_ipython().getoutput({u}'ls')"),
44 44 (u'c= !ls', "c = get_ipython().getoutput({u}'ls')"),
45 45 (u'd == !ls', u'd == !ls'), # Invalid syntax, but we leave == alone.
46 46 ('x=1', 'x=1'), # normal input is unmodified
47 47 (' ',' '), # blank lines are kept intact
48 48 # Tuple unpacking
49 49 (u"a, b = !echo 'a\\nb'", u"a, b = get_ipython().getoutput({u}\"echo 'a\\\\nb'\")"),
50 50 (u"a,= !echo 'a'", u"a, = get_ipython().getoutput({u}\"echo 'a'\")"),
51 51 (u"a, *bc = !echo 'a\\nb\\nc'", u"a, *bc = get_ipython().getoutput({u}\"echo 'a\\\\nb\\\\nc'\")"),
52 52 # Tuple unpacking with regular Python expressions, not our syntax.
53 53 (u"a, b = range(2)", u"a, b = range(2)"),
54 54 (u"a, = range(1)", u"a, = range(1)"),
55 55 (u"a, *bc = range(3)", u"a, *bc = range(3)"),
56 56 ]],
57 57
58 58 assign_magic =
59 59 [(i,py3compat.u_format(o)) for i,o in \
60 60 [(u'a =% who', "a = get_ipython().magic({u}'who')"),
61 61 (u'b = %who', "b = get_ipython().magic({u}'who')"),
62 62 (u'c= %ls', "c = get_ipython().magic({u}'ls')"),
63 63 (u'd == %ls', u'd == %ls'), # Invalid syntax, but we leave == alone.
64 64 ('x=1', 'x=1'), # normal input is unmodified
65 65 (' ',' '), # blank lines are kept intact
66 66 (u"a, b = %foo", u"a, b = get_ipython().magic({u}'foo')"),
67 67 ]],
68 68
69 69 classic_prompt =
70 70 [('>>> x=1', 'x=1'),
71 71 ('x=1', 'x=1'), # normal input is unmodified
72 72 (' ', ' '), # blank lines are kept intact
73 73 ],
74 74
75 75 ipy_prompt =
76 76 [('In [1]: x=1', 'x=1'),
77 77 ('x=1', 'x=1'), # normal input is unmodified
78 78 (' ',' '), # blank lines are kept intact
79 79 ],
80 80
81 81 # Tests for the escape transformer to leave normal code alone
82 82 escaped_noesc =
83 83 [ (' ', ' '),
84 84 ('x=1', 'x=1'),
85 85 ],
86 86
87 87 # System calls
88 88 escaped_shell =
89 89 [(i,py3compat.u_format(o)) for i,o in \
90 90 [ (u'!ls', "get_ipython().system({u}'ls')"),
91 91 # Double-escape shell, this means to capture the output of the
92 92 # subprocess and return it
93 93 (u'!!ls', "get_ipython().getoutput({u}'ls')"),
94 94 ]],
95 95
96 96 # Help/object info
97 97 escaped_help =
98 98 [(i,py3compat.u_format(o)) for i,o in \
99 99 [ (u'?', 'get_ipython().show_usage()'),
100 100 (u'?x1', "get_ipython().magic({u}'pinfo x1')"),
101 101 (u'??x2', "get_ipython().magic({u}'pinfo2 x2')"),
102 102 (u'?a.*s', "get_ipython().magic({u}'psearch a.*s')"),
103 103 (u'?%hist1', "get_ipython().magic({u}'pinfo %hist1')"),
104 104 (u'?%%hist2', "get_ipython().magic({u}'pinfo %%hist2')"),
105 105 (u'?abc = qwe', "get_ipython().magic({u}'pinfo abc')"),
106 106 ]],
107 107
108 108 end_help =
109 109 [(i,py3compat.u_format(o)) for i,o in \
110 110 [ (u'x3?', "get_ipython().magic({u}'pinfo x3')"),
111 111 (u'x4??', "get_ipython().magic({u}'pinfo2 x4')"),
112 112 (u'%hist1?', "get_ipython().magic({u}'pinfo %hist1')"),
113 113 (u'%hist2??', "get_ipython().magic({u}'pinfo2 %hist2')"),
114 114 (u'%%hist3?', "get_ipython().magic({u}'pinfo %%hist3')"),
115 115 (u'%%hist4??', "get_ipython().magic({u}'pinfo2 %%hist4')"),
116 116 (u'f*?', "get_ipython().magic({u}'psearch f*')"),
117 117 (u'ax.*aspe*?', "get_ipython().magic({u}'psearch ax.*aspe*')"),
118 118 (u'a = abc?', "get_ipython().set_next_input({u}'a = abc');"
119 119 "get_ipython().magic({u}'pinfo abc')"),
120 120 (u'a = abc.qe??', "get_ipython().set_next_input({u}'a = abc.qe');"
121 121 "get_ipython().magic({u}'pinfo2 abc.qe')"),
122 122 (u'a = *.items?', "get_ipython().set_next_input({u}'a = *.items');"
123 123 "get_ipython().magic({u}'psearch *.items')"),
124 124 (u'plot(a?', "get_ipython().set_next_input({u}'plot(a');"
125 125 "get_ipython().magic({u}'pinfo a')"),
126 126 (u'a*2 #comment?', 'a*2 #comment?'),
127 127 ]],
128 128
129 129 # Explicit magic calls
130 130 escaped_magic =
131 131 [(i,py3compat.u_format(o)) for i,o in \
132 132 [ (u'%cd', "get_ipython().magic({u}'cd')"),
133 133 (u'%cd /home', "get_ipython().magic({u}'cd /home')"),
134 134 # Backslashes need to be escaped.
135 135 (u'%cd C:\\User', "get_ipython().magic({u}'cd C:\\\\User')"),
136 136 (u' %magic', " get_ipython().magic({u}'magic')"),
137 137 ]],
138 138
139 139 # Quoting with separate arguments
140 140 escaped_quote =
141 141 [ (',f', 'f("")'),
142 142 (',f x', 'f("x")'),
143 143 (' ,f y', ' f("y")'),
144 144 (',f a b', 'f("a", "b")'),
145 145 ],
146 146
147 147 # Quoting with single argument
148 148 escaped_quote2 =
149 149 [ (';f', 'f("")'),
150 150 (';f x', 'f("x")'),
151 151 (' ;f y', ' f("y")'),
152 152 (';f a b', 'f("a b")'),
153 153 ],
154 154
155 155 # Simply apply parens
156 156 escaped_paren =
157 157 [ ('/f', 'f()'),
158 158 ('/f x', 'f(x)'),
159 159 (' /f y', ' f(y)'),
160 160 ('/f a b', 'f(a, b)'),
161 161 ],
162 162
163 163 # Check that we transform prompts before other transforms
164 164 mixed =
165 165 [(i,py3compat.u_format(o)) for i,o in \
166 166 [ (u'In [1]: %lsmagic', "get_ipython().magic({u}'lsmagic')"),
167 167 (u'>>> %lsmagic', "get_ipython().magic({u}'lsmagic')"),
168 168 (u'In [2]: !ls', "get_ipython().system({u}'ls')"),
169 169 (u'In [3]: abs?', "get_ipython().magic({u}'pinfo abs')"),
170 170 (u'In [4]: b = %who', "b = get_ipython().magic({u}'who')"),
171 171 ]],
172 172 )
173 173
174 174 # multiline syntax examples. Each of these should be a list of lists, with
175 175 # each entry itself having pairs of raw/transformed input. The union (with
176 176 # '\n'.join() of the transformed inputs is what the splitter should produce
177 177 # when fed the raw lines one at a time via push.
178 178 syntax_ml = \
179 179 dict(classic_prompt =
180 180 [ [('>>> for i in range(10):','for i in range(10):'),
181 181 ('... print i',' print i'),
182 182 ('... ', ''),
183 183 ],
184 184 [('>>> a="""','a="""'),
185 185 ('... 123"""','123"""'),
186 186 ],
187 187 [('a="""','a="""'),
188 188 ('... 123','123'),
189 189 ('... 456"""','456"""'),
190 190 ],
191 191 [('a="""','a="""'),
192 192 ('>>> 123','123'),
193 193 ('... 456"""','456"""'),
194 194 ],
195 195 [('a="""','a="""'),
196 196 ('123','123'),
197 197 ('... 456"""','... 456"""'),
198 198 ],
199 199 [('....__class__','....__class__'),
200 200 ],
201 201 [('a=5', 'a=5'),
202 202 ('...', ''),
203 203 ],
204 204 [('>>> def f(x):', 'def f(x):'),
205 205 ('...', ''),
206 206 ('... return x', ' return x'),
207 207 ],
208 208 [('board = """....', 'board = """....'),
209 209 ('....', '....'),
210 210 ('...."""', '...."""'),
211 211 ],
212 212 ],
213 213
214 214 ipy_prompt =
215 215 [ [('In [24]: for i in range(10):','for i in range(10):'),
216 216 (' ....: print i',' print i'),
217 217 (' ....: ', ''),
218 218 ],
219 219 [('In [24]: for i in range(10):','for i in range(10):'),
220 220 # Qt console prompts expand with spaces, not dots
221 221 (' ...: print i',' print i'),
222 222 (' ...: ', ''),
223 223 ],
224 224 [('In [24]: for i in range(10):','for i in range(10):'),
225 225 # Sometimes whitespace preceding '...' has been removed
226 226 ('...: print i',' print i'),
227 227 ('...: ', ''),
228 228 ],
229 229 [('In [24]: for i in range(10):','for i in range(10):'),
230 230 # Space after last continuation prompt has been removed (issue #6674)
231 231 ('...: print i',' print i'),
232 232 ('...:', ''),
233 233 ],
234 234 [('In [2]: a="""','a="""'),
235 235 (' ...: 123"""','123"""'),
236 236 ],
237 237 [('a="""','a="""'),
238 238 (' ...: 123','123'),
239 239 (' ...: 456"""','456"""'),
240 240 ],
241 241 [('a="""','a="""'),
242 242 ('In [1]: 123','123'),
243 243 (' ...: 456"""','456"""'),
244 244 ],
245 245 [('a="""','a="""'),
246 246 ('123','123'),
247 247 (' ...: 456"""',' ...: 456"""'),
248 248 ],
249 249 ],
250 250
251 251 multiline_datastructure_prompt =
252 252 [ [('>>> a = [1,','a = [1,'),
253 253 ('... 2]','2]'),
254 254 ],
255 255 ],
256 256
257 257 multiline_datastructure =
258 258 [ [('b = ("%s"', None),
259 259 ('# comment', None),
260 260 ('%foo )', 'b = ("%s"\n# comment\n%foo )'),
261 261 ],
262 262 ],
263 263
264 264 multiline_string =
265 265 [ [("'''foo?", None),
266 266 ("bar'''", "'''foo?\nbar'''"),
267 267 ],
268 268 ],
269 269
270 270 leading_indent =
271 271 [ [(' print "hi"','print "hi"'),
272 272 ],
273 273 [(' for a in range(5):','for a in range(5):'),
274 274 (' a*2',' a*2'),
275 275 ],
276 276 [(' a="""','a="""'),
277 277 (' 123"""','123"""'),
278 278 ],
279 279 [('a="""','a="""'),
280 280 (' 123"""',' 123"""'),
281 281 ],
282 282 ],
283 283
284 284 cellmagic =
285 285 [ [(u'%%foo a', None),
286 286 (None, u_fmt("get_ipython().run_cell_magic({u}'foo', {u}'a', {u}'')")),
287 287 ],
288 288 [(u'%%bar 123', None),
289 289 (u'hello', None),
290 290 (None , u_fmt("get_ipython().run_cell_magic({u}'bar', {u}'123', {u}'hello')")),
291 291 ],
292 292 [(u'a=5', 'a=5'),
293 293 (u'%%cellmagic', '%%cellmagic'),
294 294 ],
295 295 ],
296 296
297 297 escaped =
298 298 [ [('%abc def \\', None),
299 299 ('ghi', u_fmt("get_ipython().magic({u}'abc def ghi')")),
300 300 ],
301 301 [('%abc def \\', None),
302 302 ('ghi\\', None),
303 303 (None, u_fmt("get_ipython().magic({u}'abc def ghi')")),
304 304 ],
305 305 ],
306 306
307 307 assign_magic =
308 308 [ [(u'a = %bc de \\', None),
309 309 (u'fg', u_fmt("a = get_ipython().magic({u}'bc de fg')")),
310 310 ],
311 311 [(u'a = %bc de \\', None),
312 312 (u'fg\\', None),
313 313 (None, u_fmt("a = get_ipython().magic({u}'bc de fg')")),
314 314 ],
315 315 ],
316 316
317 317 assign_system =
318 318 [ [(u'a = !bc de \\', None),
319 319 (u'fg', u_fmt("a = get_ipython().getoutput({u}'bc de fg')")),
320 320 ],
321 321 [(u'a = !bc de \\', None),
322 322 (u'fg\\', None),
323 323 (None, u_fmt("a = get_ipython().getoutput({u}'bc de fg')")),
324 324 ],
325 325 ],
326 326 )
327 327
328 328
329 329 def test_assign_system():
330 330 tt.check_pairs(transform_and_reset(ipt.assign_from_system), syntax['assign_system'])
331 331
332 332 def test_assign_magic():
333 333 tt.check_pairs(transform_and_reset(ipt.assign_from_magic), syntax['assign_magic'])
334 334
335 335 def test_classic_prompt():
336 336 tt.check_pairs(transform_and_reset(ipt.classic_prompt), syntax['classic_prompt'])
337 337 for example in syntax_ml['classic_prompt']:
338 338 transform_checker(example, ipt.classic_prompt)
339 339 for example in syntax_ml['multiline_datastructure_prompt']:
340 340 transform_checker(example, ipt.classic_prompt)
341 341
342 342 # Check that we don't transform the second line if the first is obviously
343 343 # IPython syntax
344 344 transform_checker([
345 345 (u'%foo', '%foo'),
346 346 (u'>>> bar', '>>> bar'),
347 347 ], ipt.classic_prompt)
348 348
349 349
350 350 def test_ipy_prompt():
351 351 tt.check_pairs(transform_and_reset(ipt.ipy_prompt), syntax['ipy_prompt'])
352 352 for example in syntax_ml['ipy_prompt']:
353 353 transform_checker(example, ipt.ipy_prompt)
354 354
355 355 # Check that we don't transform the second line if we're inside a cell magic
356 356 transform_checker([
357 357 (u'%%foo', '%%foo'),
358 358 (u'In [1]: bar', 'In [1]: bar'),
359 359 ], ipt.ipy_prompt)
360 360
361 361 def test_assemble_logical_lines():
362 362 tests = \
363 363 [ [(u"a = \\", None),
364 364 (u"123", u"a = 123"),
365 365 ],
366 366 [(u"a = \\", None), # Test resetting when within a multi-line string
367 367 (u"12 *\\", None),
368 368 (None, u"a = 12 *"),
369 369 ],
370 370 [(u"# foo\\", u"# foo\\"), # Comments can't be continued like this
371 371 ],
372 372 ]
373 373 for example in tests:
374 374 transform_checker(example, ipt.assemble_logical_lines)
375 375
376 376 def test_assemble_python_lines():
377 377 tests = \
378 378 [ [(u"a = '''", None),
379 379 (u"abc'''", u"a = '''\nabc'''"),
380 380 ],
381 381 [(u"a = '''", None), # Test resetting when within a multi-line string
382 382 (u"def", None),
383 383 (None, u"a = '''\ndef"),
384 384 ],
385 385 [(u"a = [1,", None),
386 386 (u"2]", u"a = [1,\n2]"),
387 387 ],
388 388 [(u"a = [1,", None), # Test resetting when within a multi-line string
389 389 (u"2,", None),
390 390 (None, u"a = [1,\n2,"),
391 391 ],
392 [(u"a = '''", None), # Test line continuation within a multi-line string
393 (u"abc\\", None),
394 (u"def", None),
395 (u"'''", u"a = '''\nabc\\\ndef\n'''"),
396 ],
392 397 ] + syntax_ml['multiline_datastructure']
393 398 for example in tests:
394 399 transform_checker(example, ipt.assemble_python_lines)
395 400
396 401
397 402 def test_help_end():
398 403 tt.check_pairs(transform_and_reset(ipt.help_end), syntax['end_help'])
399 404
400 405 def test_escaped_noesc():
401 406 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_noesc'])
402 407
403 408
404 409 def test_escaped_shell():
405 410 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_shell'])
406 411
407 412
408 413 def test_escaped_help():
409 414 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_help'])
410 415
411 416
412 417 def test_escaped_magic():
413 418 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_magic'])
414 419
415 420
416 421 def test_escaped_quote():
417 422 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_quote'])
418 423
419 424
420 425 def test_escaped_quote2():
421 426 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_quote2'])
422 427
423 428
424 429 def test_escaped_paren():
425 430 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_paren'])
426 431
427 432
428 433 def test_cellmagic():
429 434 for example in syntax_ml['cellmagic']:
430 435 transform_checker(example, ipt.cellmagic)
431 436
432 437 line_example = [(u'%%bar 123', None),
433 438 (u'hello', None),
434 439 (u'' , u_fmt("get_ipython().run_cell_magic({u}'bar', {u}'123', {u}'hello')")),
435 440 ]
436 441 transform_checker(line_example, ipt.cellmagic, end_on_blank_line=True)
437 442
438 443 def test_has_comment():
439 444 tests = [('text', False),
440 445 ('text #comment', True),
441 446 ('text #comment\n', True),
442 447 ('#comment', True),
443 448 ('#comment\n', True),
444 449 ('a = "#string"', False),
445 450 ('a = "#string" # comment', True),
446 451 ('a #comment not "string"', True),
447 452 ]
448 453 tt.check_pairs(ipt.has_comment, tests)
449 454
450 455 @ipt.TokenInputTransformer.wrap
451 456 def decistmt(tokens):
452 457 """Substitute Decimals for floats in a string of statements.
453 458
454 459 Based on an example from the tokenize module docs.
455 460 """
456 461 result = []
457 462 for toknum, tokval, _, _, _ in tokens:
458 463 if toknum == tokenize.NUMBER and '.' in tokval: # replace NUMBER tokens
459 464 for newtok in [
460 465 (tokenize.NAME, 'Decimal'),
461 466 (tokenize.OP, '('),
462 467 (tokenize.STRING, repr(tokval)),
463 468 (tokenize.OP, ')')
464 469 ]:
465 470 yield newtok
466 471 else:
467 472 yield (toknum, tokval)
468 473
469 474
470 475
471 476 def test_token_input_transformer():
472 477 tests = [(u'1.2', u_fmt(u"Decimal ({u}'1.2')")),
473 478 (u'"1.2"', u'"1.2"'),
474 479 ]
475 480 tt.check_pairs(transform_and_reset(decistmt), tests)
476 481 ml_tests = \
477 482 [ [(u"a = 1.2; b = '''x", None),
478 483 (u"y'''", u_fmt(u"a =Decimal ({u}'1.2');b ='''x\ny'''")),
479 484 ],
480 485 [(u"a = [1.2,", None),
481 486 (u"3]", u_fmt(u"a =[Decimal ({u}'1.2'),\n3 ]")),
482 487 ],
483 488 [(u"a = '''foo", None), # Test resetting when within a multi-line string
484 489 (u"bar", None),
485 490 (None, u"a = '''foo\nbar"),
486 491 ],
487 492 ]
488 493 for example in ml_tests:
489 494 transform_checker(example, decistmt)
General Comments 0
You need to be logged in to leave comments. Login now