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