##// END OF EJS Templates
added test for issue #678
Daniel Velkov -
Show More
@@ -1,698 +1,704
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for the inputsplitter module.
3 3
4 4 Authors
5 5 -------
6 6 * Fernando Perez
7 7 * Robert Kern
8 8 """
9 9 #-----------------------------------------------------------------------------
10 10 # Copyright (C) 2010 The IPython Development Team
11 11 #
12 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
14 14 #-----------------------------------------------------------------------------
15 15
16 16 #-----------------------------------------------------------------------------
17 17 # Imports
18 18 #-----------------------------------------------------------------------------
19 19 # stdlib
20 20 import unittest
21 21 import sys
22 22
23 23 # Third party
24 24 import nose.tools as nt
25 25
26 26 # Our own
27 27 from IPython.core import inputsplitter as isp
28 28 from IPython.testing import tools as tt
29 29 from IPython.utils import py3compat
30 30
31 31 #-----------------------------------------------------------------------------
32 32 # Semi-complete examples (also used as tests)
33 33 #-----------------------------------------------------------------------------
34 34
35 35 # Note: at the bottom, there's a slightly more complete version of this that
36 36 # can be useful during development of code here.
37 37
38 38 def mini_interactive_loop(input_func):
39 39 """Minimal example of the logic of an interactive interpreter loop.
40 40
41 41 This serves as an example, and it is used by the test system with a fake
42 42 raw_input that simulates interactive input."""
43 43
44 44 from IPython.core.inputsplitter import InputSplitter
45 45
46 46 isp = InputSplitter()
47 47 # In practice, this input loop would be wrapped in an outside loop to read
48 48 # input indefinitely, until some exit/quit command was issued. Here we
49 49 # only illustrate the basic inner loop.
50 50 while isp.push_accepts_more():
51 51 indent = ' '*isp.indent_spaces
52 52 prompt = '>>> ' + indent
53 53 line = indent + input_func(prompt)
54 54 isp.push(line)
55 55
56 56 # Here we just return input so we can use it in a test suite, but a real
57 57 # interpreter would instead send it for execution somewhere.
58 58 src = isp.source_reset()
59 59 #print 'Input source was:\n', src # dbg
60 60 return src
61 61
62 62 #-----------------------------------------------------------------------------
63 63 # Test utilities, just for local use
64 64 #-----------------------------------------------------------------------------
65 65
66 66 def assemble(block):
67 67 """Assemble a block into multi-line sub-blocks."""
68 68 return ['\n'.join(sub_block)+'\n' for sub_block in block]
69 69
70 70
71 71 def pseudo_input(lines):
72 72 """Return a function that acts like raw_input but feeds the input list."""
73 73 ilines = iter(lines)
74 74 def raw_in(prompt):
75 75 try:
76 76 return next(ilines)
77 77 except StopIteration:
78 78 return ''
79 79 return raw_in
80 80
81 81 #-----------------------------------------------------------------------------
82 82 # Tests
83 83 #-----------------------------------------------------------------------------
84 84 def test_spaces():
85 85 tests = [('', 0),
86 86 (' ', 1),
87 87 ('\n', 0),
88 88 (' \n', 1),
89 89 ('x', 0),
90 90 (' x', 1),
91 91 (' x',2),
92 92 (' x',4),
93 93 # Note: tabs are counted as a single whitespace!
94 94 ('\tx', 1),
95 95 ('\t x', 2),
96 96 ]
97 97 tt.check_pairs(isp.num_ini_spaces, tests)
98 98
99 99
100 100 def test_remove_comments():
101 101 tests = [('text', 'text'),
102 102 ('text # comment', 'text '),
103 103 ('text # comment\n', 'text \n'),
104 104 ('text # comment \n', 'text \n'),
105 105 ('line # c \nline\n','line \nline\n'),
106 106 ('line # c \nline#c2 \nline\nline #c\n\n',
107 107 'line \nline\nline\nline \n\n'),
108 108 ]
109 109 tt.check_pairs(isp.remove_comments, tests)
110 110
111 111 def test_has_comment():
112 112 tests = [('text', False),
113 113 ('text #comment', True),
114 114 ('text #comment\n', True),
115 115 ('#comment', True),
116 116 ('#comment\n', True),
117 117 ('a = "#string"', False),
118 118 ('a = "#string" # comment', True),
119 119 ('a #comment not "string"', True),
120 120 ]
121 121 tt.check_pairs(isp.has_comment, tests)
122 122
123 123
124 124 def test_get_input_encoding():
125 125 encoding = isp.get_input_encoding()
126 126 nt.assert_true(isinstance(encoding, basestring))
127 127 # simple-minded check that at least encoding a simple string works with the
128 128 # encoding we got.
129 129 nt.assert_equal(u'test'.encode(encoding), b'test')
130 130
131 131
132 132 class NoInputEncodingTestCase(unittest.TestCase):
133 133 def setUp(self):
134 134 self.old_stdin = sys.stdin
135 135 class X: pass
136 136 fake_stdin = X()
137 137 sys.stdin = fake_stdin
138 138
139 139 def test(self):
140 140 # Verify that if sys.stdin has no 'encoding' attribute we do the right
141 141 # thing
142 142 enc = isp.get_input_encoding()
143 143 self.assertEqual(enc, 'ascii')
144 144
145 145 def tearDown(self):
146 146 sys.stdin = self.old_stdin
147 147
148 148
149 149 class InputSplitterTestCase(unittest.TestCase):
150 150 def setUp(self):
151 151 self.isp = isp.InputSplitter()
152 152
153 153 def test_reset(self):
154 154 isp = self.isp
155 155 isp.push('x=1')
156 156 isp.reset()
157 157 self.assertEqual(isp._buffer, [])
158 158 self.assertEqual(isp.indent_spaces, 0)
159 159 self.assertEqual(isp.source, '')
160 160 self.assertEqual(isp.code, None)
161 161 self.assertEqual(isp._is_complete, False)
162 162
163 163 def test_source(self):
164 164 self.isp._store('1')
165 165 self.isp._store('2')
166 166 self.assertEqual(self.isp.source, '1\n2\n')
167 167 self.assertTrue(len(self.isp._buffer)>0)
168 168 self.assertEqual(self.isp.source_reset(), '1\n2\n')
169 169 self.assertEqual(self.isp._buffer, [])
170 170 self.assertEqual(self.isp.source, '')
171 171
172 172 def test_indent(self):
173 173 isp = self.isp # shorthand
174 174 isp.push('x=1')
175 175 self.assertEqual(isp.indent_spaces, 0)
176 176 isp.push('if 1:\n x=1')
177 177 self.assertEqual(isp.indent_spaces, 4)
178 178 isp.push('y=2\n')
179 179 self.assertEqual(isp.indent_spaces, 0)
180 180
181 181 def test_indent2(self):
182 182 # In cell mode, inputs must be fed in whole blocks, so skip this test
183 183 if self.isp.input_mode == 'cell': return
184 184
185 185 isp = self.isp
186 186 isp.push('if 1:')
187 187 self.assertEqual(isp.indent_spaces, 4)
188 188 isp.push(' x=1')
189 189 self.assertEqual(isp.indent_spaces, 4)
190 190 # Blank lines shouldn't change the indent level
191 191 isp.push(' '*2)
192 192 self.assertEqual(isp.indent_spaces, 4)
193 193
194 194 def test_indent3(self):
195 195 # In cell mode, inputs must be fed in whole blocks, so skip this test
196 196 if self.isp.input_mode == 'cell': return
197 197
198 198 isp = self.isp
199 199 # When a multiline statement contains parens or multiline strings, we
200 200 # shouldn't get confused.
201 201 isp.push("if 1:")
202 202 isp.push(" x = (1+\n 2)")
203 203 self.assertEqual(isp.indent_spaces, 4)
204 204
205 205 def test_indent4(self):
206 206 # In cell mode, inputs must be fed in whole blocks, so skip this test
207 207 if self.isp.input_mode == 'cell': return
208 208
209 209 isp = self.isp
210 210 # whitespace after ':' should not screw up indent level
211 211 isp.push('if 1: \n x=1')
212 212 self.assertEqual(isp.indent_spaces, 4)
213 213 isp.push('y=2\n')
214 214 self.assertEqual(isp.indent_spaces, 0)
215 215 isp.push('if 1:\t\n x=1')
216 216 self.assertEqual(isp.indent_spaces, 4)
217 217 isp.push('y=2\n')
218 218 self.assertEqual(isp.indent_spaces, 0)
219 219
220 220 def test_dedent_pass(self):
221 221 isp = self.isp # shorthand
222 222 # should NOT cause dedent
223 223 isp.push('if 1:\n passes = 5')
224 224 self.assertEqual(isp.indent_spaces, 4)
225 225 isp.push('if 1:\n pass')
226 226 self.assertEqual(isp.indent_spaces, 0)
227 227 isp.push('if 1:\n pass ')
228 228 self.assertEqual(isp.indent_spaces, 0)
229 229
230 230 def test_dedent_raise(self):
231 231 isp = self.isp # shorthand
232 232 # should NOT cause dedent
233 233 isp.push('if 1:\n raised = 4')
234 234 self.assertEqual(isp.indent_spaces, 4)
235 235 isp.push('if 1:\n raise TypeError()')
236 236 self.assertEqual(isp.indent_spaces, 0)
237 237 isp.push('if 1:\n raise')
238 238 self.assertEqual(isp.indent_spaces, 0)
239 239 isp.push('if 1:\n raise ')
240 240 self.assertEqual(isp.indent_spaces, 0)
241 241
242 242 def test_dedent_return(self):
243 243 isp = self.isp # shorthand
244 244 # should NOT cause dedent
245 245 isp.push('if 1:\n returning = 4')
246 246 self.assertEqual(isp.indent_spaces, 4)
247 247 isp.push('if 1:\n return 5 + 493')
248 248 self.assertEqual(isp.indent_spaces, 0)
249 249 isp.push('if 1:\n return')
250 250 self.assertEqual(isp.indent_spaces, 0)
251 251 isp.push('if 1:\n return ')
252 252 self.assertEqual(isp.indent_spaces, 0)
253 253 isp.push('if 1:\n return(0)')
254 254 self.assertEqual(isp.indent_spaces, 0)
255 255
256 256 def test_push(self):
257 257 isp = self.isp
258 258 self.assertTrue(isp.push('x=1'))
259 259
260 260 def test_push2(self):
261 261 isp = self.isp
262 262 self.assertFalse(isp.push('if 1:'))
263 263 for line in [' x=1', '# a comment', ' y=2']:
264 264 self.assertTrue(isp.push(line))
265 265
266 266 def test_push3(self):
267 267 isp = self.isp
268 268 isp.push('if True:')
269 269 isp.push(' a = 1')
270 270 self.assertFalse(isp.push('b = [1,'))
271 271
272 272 def test_replace_mode(self):
273 273 isp = self.isp
274 274 isp.input_mode = 'cell'
275 275 isp.push('x=1')
276 276 self.assertEqual(isp.source, 'x=1\n')
277 277 isp.push('x=2')
278 278 self.assertEqual(isp.source, 'x=2\n')
279 279
280 280 def test_push_accepts_more(self):
281 281 isp = self.isp
282 282 isp.push('x=1')
283 283 self.assertFalse(isp.push_accepts_more())
284 284
285 285 def test_push_accepts_more2(self):
286 286 # In cell mode, inputs must be fed in whole blocks, so skip this test
287 287 if self.isp.input_mode == 'cell': return
288 288
289 289 isp = self.isp
290 290 isp.push('if 1:')
291 291 self.assertTrue(isp.push_accepts_more())
292 292 isp.push(' x=1')
293 293 self.assertTrue(isp.push_accepts_more())
294 294 isp.push('')
295 295 self.assertFalse(isp.push_accepts_more())
296 296
297 297 def test_push_accepts_more3(self):
298 298 isp = self.isp
299 299 isp.push("x = (2+\n3)")
300 300 self.assertFalse(isp.push_accepts_more())
301 301
302 302 def test_push_accepts_more4(self):
303 303 # In cell mode, inputs must be fed in whole blocks, so skip this test
304 304 if self.isp.input_mode == 'cell': return
305 305
306 306 isp = self.isp
307 307 # When a multiline statement contains parens or multiline strings, we
308 308 # shouldn't get confused.
309 309 # FIXME: we should be able to better handle de-dents in statements like
310 310 # multiline strings and multiline expressions (continued with \ or
311 311 # parens). Right now we aren't handling the indentation tracking quite
312 312 # correctly with this, though in practice it may not be too much of a
313 313 # problem. We'll need to see.
314 314 isp.push("if 1:")
315 315 isp.push(" x = (2+")
316 316 isp.push(" 3)")
317 317 self.assertTrue(isp.push_accepts_more())
318 318 isp.push(" y = 3")
319 319 self.assertTrue(isp.push_accepts_more())
320 320 isp.push('')
321 321 self.assertFalse(isp.push_accepts_more())
322 322
323 323 def test_push_accepts_more5(self):
324 324 # In cell mode, inputs must be fed in whole blocks, so skip this test
325 325 if self.isp.input_mode == 'cell': return
326 326
327 327 isp = self.isp
328 328 isp.push('try:')
329 329 isp.push(' a = 5')
330 330 isp.push('except:')
331 331 isp.push(' raise')
332 332 self.assertTrue(isp.push_accepts_more())
333 333
334 334 def test_continuation(self):
335 335 isp = self.isp
336 336 isp.push("import os, \\")
337 337 self.assertTrue(isp.push_accepts_more())
338 338 isp.push("sys")
339 339 self.assertFalse(isp.push_accepts_more())
340 340
341 341 def test_syntax_error(self):
342 342 isp = self.isp
343 343 # Syntax errors immediately produce a 'ready' block, so the invalid
344 344 # Python can be sent to the kernel for evaluation with possible ipython
345 345 # special-syntax conversion.
346 346 isp.push('run foo')
347 347 self.assertFalse(isp.push_accepts_more())
348 348
349 349 def test_unicode(self):
350 350 self.isp.push(u"Pérez")
351 351 self.isp.push(u'\xc3\xa9')
352 352 self.isp.push(u"u'\xc3\xa9'")
353 353
354 354 class InteractiveLoopTestCase(unittest.TestCase):
355 355 """Tests for an interactive loop like a python shell.
356 356 """
357 357 def check_ns(self, lines, ns):
358 358 """Validate that the given input lines produce the resulting namespace.
359 359
360 360 Note: the input lines are given exactly as they would be typed in an
361 361 auto-indenting environment, as mini_interactive_loop above already does
362 362 auto-indenting and prepends spaces to the input.
363 363 """
364 364 src = mini_interactive_loop(pseudo_input(lines))
365 365 test_ns = {}
366 366 exec src in test_ns
367 367 # We can't check that the provided ns is identical to the test_ns,
368 368 # because Python fills test_ns with extra keys (copyright, etc). But
369 369 # we can check that the given dict is *contained* in test_ns
370 370 for k,v in ns.iteritems():
371 371 self.assertEqual(test_ns[k], v)
372 372
373 373 def test_simple(self):
374 374 self.check_ns(['x=1'], dict(x=1))
375 375
376 376 def test_simple2(self):
377 377 self.check_ns(['if 1:', 'x=2'], dict(x=2))
378 378
379 379 def test_xy(self):
380 380 self.check_ns(['x=1; y=2'], dict(x=1, y=2))
381 381
382 382 def test_abc(self):
383 383 self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3))
384 384
385 385 def test_multi(self):
386 386 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
387 387
388 388
389 389 def test_LineInfo():
390 390 """Simple test for LineInfo construction and str()"""
391 391 linfo = isp.LineInfo(' %cd /home')
392 392 nt.assert_equals(str(linfo), 'LineInfo [ |%|cd|/home]')
393 393
394 394 # Transformer tests
395 395 def transform_checker(tests, func):
396 396 """Utility to loop over test inputs"""
397 397 for inp, tr in tests:
398 398 nt.assert_equals(func(inp), tr)
399 399
400 400 # Data for all the syntax tests in the form of lists of pairs of
401 401 # raw/transformed input. We store it here as a global dict so that we can use
402 402 # it both within single-function tests and also to validate the behavior of the
403 403 # larger objects
404 404
405 405 syntax = \
406 406 dict(assign_system =
407 407 [(i,py3compat.u_format(o)) for i,o in \
408 408 [('a =! ls', 'a = get_ipython().getoutput({u}"ls")'),
409 409 ('b = !ls', 'b = get_ipython().getoutput({u}"ls")'),
410 410 ('x=1', 'x=1'), # normal input is unmodified
411 411 (' ',' '), # blank lines are kept intact
412 412 ]],
413 413
414 414 assign_magic =
415 415 [(i,py3compat.u_format(o)) for i,o in \
416 416 [('a =% who', 'a = get_ipython().magic({u}"who")'),
417 417 ('b = %who', 'b = get_ipython().magic({u}"who")'),
418 418 ('x=1', 'x=1'), # normal input is unmodified
419 419 (' ',' '), # blank lines are kept intact
420 420 ]],
421 421
422 422 classic_prompt =
423 423 [('>>> x=1', 'x=1'),
424 424 ('x=1', 'x=1'), # normal input is unmodified
425 425 (' ', ' '), # blank lines are kept intact
426 426 ('... ', ''), # continuation prompts
427 427 ],
428 428
429 429 ipy_prompt =
430 430 [('In [1]: x=1', 'x=1'),
431 431 ('x=1', 'x=1'), # normal input is unmodified
432 432 (' ',' '), # blank lines are kept intact
433 433 (' ....: ', ''), # continuation prompts
434 434 ],
435 435
436 436 # Tests for the escape transformer to leave normal code alone
437 437 escaped_noesc =
438 438 [ (' ', ' '),
439 439 ('x=1', 'x=1'),
440 440 ],
441 441
442 442 # System calls
443 443 escaped_shell =
444 444 [(i,py3compat.u_format(o)) for i,o in \
445 445 [ ('!ls', 'get_ipython().system({u}"ls")'),
446 446 # Double-escape shell, this means to capture the output of the
447 447 # subprocess and return it
448 448 ('!!ls', 'get_ipython().getoutput({u}"ls")'),
449 449 ]],
450 450
451 451 # Help/object info
452 452 escaped_help =
453 453 [(i,py3compat.u_format(o)) for i,o in \
454 454 [ ('?', 'get_ipython().show_usage()'),
455 455 ('?x1', 'get_ipython().magic({u}"pinfo x1")'),
456 456 ('??x2', 'get_ipython().magic({u}"pinfo2 x2")'),
457 457 ('?a.*s', 'get_ipython().magic({u}"psearch a.*s")'),
458 458 ('?%hist', 'get_ipython().magic({u}"pinfo %hist")'),
459 459 ('?abc = qwe', 'get_ipython().magic({u}"pinfo abc")'),
460 460 ]],
461 461
462 462 end_help =
463 463 [(i,py3compat.u_format(o)) for i,o in \
464 464 [ ('x3?', 'get_ipython().magic({u}"pinfo x3")'),
465 465 ('x4??', 'get_ipython().magic({u}"pinfo2 x4")'),
466 466 ('%hist?', 'get_ipython().magic({u}"pinfo %hist")'),
467 467 ('f*?', 'get_ipython().magic({u}"psearch f*")'),
468 468 ('ax.*aspe*?', 'get_ipython().magic({u}"psearch ax.*aspe*")'),
469 469 ('a = abc?', 'get_ipython().magic({u}"pinfo abc", next_input={u}"a = abc")'),
470 470 ('a = abc.qe??', 'get_ipython().magic({u}"pinfo2 abc.qe", next_input={u}"a = abc.qe")'),
471 471 ('a = *.items?', 'get_ipython().magic({u}"psearch *.items", next_input={u}"a = *.items")'),
472 472 ('plot(a?', 'get_ipython().magic({u}"pinfo a", next_input={u}"plot(a")'),
473 473 ('a*2 #comment?', 'a*2 #comment?'),
474 474 ]],
475 475
476 476 # Explicit magic calls
477 477 escaped_magic =
478 478 [(i,py3compat.u_format(o)) for i,o in \
479 479 [ ('%cd', 'get_ipython().magic({u}"cd")'),
480 480 ('%cd /home', 'get_ipython().magic({u}"cd /home")'),
481 481 (' %magic', ' get_ipython().magic({u}"magic")'),
482 482 ]],
483 483
484 484 # Quoting with separate arguments
485 485 escaped_quote =
486 486 [ (',f', 'f("")'),
487 487 (',f x', 'f("x")'),
488 488 (' ,f y', ' f("y")'),
489 489 (',f a b', 'f("a", "b")'),
490 490 ],
491 491
492 492 # Quoting with single argument
493 493 escaped_quote2 =
494 494 [ (';f', 'f("")'),
495 495 (';f x', 'f("x")'),
496 496 (' ;f y', ' f("y")'),
497 497 (';f a b', 'f("a b")'),
498 498 ],
499 499
500 500 # Simply apply parens
501 501 escaped_paren =
502 502 [ ('/f', 'f()'),
503 503 ('/f x', 'f(x)'),
504 504 (' /f y', ' f(y)'),
505 505 ('/f a b', 'f(a, b)'),
506 506 ],
507 507
508 508 # Check that we transform prompts before other transforms
509 509 mixed =
510 510 [(i,py3compat.u_format(o)) for i,o in \
511 511 [ ('In [1]: %lsmagic', 'get_ipython().magic({u}"lsmagic")'),
512 512 ('>>> %lsmagic', 'get_ipython().magic({u}"lsmagic")'),
513 513 ('In [2]: !ls', 'get_ipython().system({u}"ls")'),
514 514 ('In [3]: abs?', 'get_ipython().magic({u}"pinfo abs")'),
515 515 ('In [4]: b = %who', 'b = get_ipython().magic({u}"who")'),
516 516 ]],
517 517 )
518 518
519 519 # multiline syntax examples. Each of these should be a list of lists, with
520 520 # each entry itself having pairs of raw/transformed input. The union (with
521 521 # '\n'.join() of the transformed inputs is what the splitter should produce
522 522 # when fed the raw lines one at a time via push.
523 523 syntax_ml = \
524 524 dict(classic_prompt =
525 525 [ [('>>> for i in range(10):','for i in range(10):'),
526 526 ('... print i',' print i'),
527 527 ('... ', ''),
528 528 ],
529 529 ],
530 530
531 531 ipy_prompt =
532 532 [ [('In [24]: for i in range(10):','for i in range(10):'),
533 533 (' ....: print i',' print i'),
534 534 (' ....: ', ''),
535 535 ],
536 536 ],
537
538 multiline_datastructure =
539 [ [('>>> a = [1,','a = [1,'),
540 ('... 2]','2]'),
541 ],
542 ],
537 543 )
538 544
539 545
540 546 def test_assign_system():
541 547 tt.check_pairs(isp.transform_assign_system, syntax['assign_system'])
542 548
543 549
544 550 def test_assign_magic():
545 551 tt.check_pairs(isp.transform_assign_magic, syntax['assign_magic'])
546 552
547 553
548 554 def test_classic_prompt():
549 555 transform_checker(syntax['classic_prompt'], isp.transform_classic_prompt)
550 556 for example in syntax_ml['classic_prompt']:
551 557 transform_checker(example, isp.transform_classic_prompt)
552 558
553 559
554 560 def test_ipy_prompt():
555 561 transform_checker(syntax['ipy_prompt'], isp.transform_ipy_prompt)
556 562 for example in syntax_ml['ipy_prompt']:
557 563 transform_checker(example, isp.transform_ipy_prompt)
558 564
559 565 def test_end_help():
560 566 tt.check_pairs(isp.transform_help_end, syntax['end_help'])
561 567
562 568 def test_escaped_noesc():
563 569 tt.check_pairs(isp.transform_escaped, syntax['escaped_noesc'])
564 570
565 571
566 572 def test_escaped_shell():
567 573 tt.check_pairs(isp.transform_escaped, syntax['escaped_shell'])
568 574
569 575
570 576 def test_escaped_help():
571 577 tt.check_pairs(isp.transform_escaped, syntax['escaped_help'])
572 578
573 579
574 580 def test_escaped_magic():
575 581 tt.check_pairs(isp.transform_escaped, syntax['escaped_magic'])
576 582
577 583
578 584 def test_escaped_quote():
579 585 tt.check_pairs(isp.transform_escaped, syntax['escaped_quote'])
580 586
581 587
582 588 def test_escaped_quote2():
583 589 tt.check_pairs(isp.transform_escaped, syntax['escaped_quote2'])
584 590
585 591
586 592 def test_escaped_paren():
587 593 tt.check_pairs(isp.transform_escaped, syntax['escaped_paren'])
588 594
589 595
590 596 class IPythonInputTestCase(InputSplitterTestCase):
591 597 """By just creating a new class whose .isp is a different instance, we
592 598 re-run the same test battery on the new input splitter.
593 599
594 600 In addition, this runs the tests over the syntax and syntax_ml dicts that
595 601 were tested by individual functions, as part of the OO interface.
596 602
597 603 It also makes some checks on the raw buffer storage.
598 604 """
599 605
600 606 def setUp(self):
601 607 self.isp = isp.IPythonInputSplitter(input_mode='line')
602 608
603 609 def test_syntax(self):
604 610 """Call all single-line syntax tests from the main object"""
605 611 isp = self.isp
606 612 for example in syntax.itervalues():
607 613 for raw, out_t in example:
608 614 if raw.startswith(' '):
609 615 continue
610 616
611 617 isp.push(raw)
612 618 out, out_raw = isp.source_raw_reset()
613 619 self.assertEqual(out.rstrip(), out_t,
614 620 tt.pair_fail_msg.format("inputsplitter",raw, out_t, out))
615 621 self.assertEqual(out_raw.rstrip(), raw.rstrip())
616 622
617 623 def test_syntax_multiline(self):
618 624 isp = self.isp
619 625 for example in syntax_ml.itervalues():
620 626 out_t_parts = []
621 627 raw_parts = []
622 628 for line_pairs in example:
623 629 for lraw, out_t_part in line_pairs:
624 630 isp.push(lraw)
625 631 out_t_parts.append(out_t_part)
626 632 raw_parts.append(lraw)
627 633
628 634 out, out_raw = isp.source_raw_reset()
629 635 out_t = '\n'.join(out_t_parts).rstrip()
630 636 raw = '\n'.join(raw_parts).rstrip()
631 637 self.assertEqual(out.rstrip(), out_t)
632 638 self.assertEqual(out_raw.rstrip(), raw)
633 639
634 640
635 641 class BlockIPythonInputTestCase(IPythonInputTestCase):
636 642
637 643 # Deactivate tests that don't make sense for the block mode
638 644 test_push3 = test_split = lambda s: None
639 645
640 646 def setUp(self):
641 647 self.isp = isp.IPythonInputSplitter(input_mode='cell')
642 648
643 649 def test_syntax_multiline(self):
644 650 isp = self.isp
645 651 for example in syntax_ml.itervalues():
646 652 raw_parts = []
647 653 out_t_parts = []
648 654 for line_pairs in example:
649 655 for raw, out_t_part in line_pairs:
650 656 raw_parts.append(raw)
651 657 out_t_parts.append(out_t_part)
652 658
653 659 raw = '\n'.join(raw_parts)
654 660 out_t = '\n'.join(out_t_parts)
655 661
656 662 isp.push(raw)
657 663 out, out_raw = isp.source_raw_reset()
658 664 # Match ignoring trailing whitespace
659 665 self.assertEqual(out.rstrip(), out_t.rstrip())
660 666 self.assertEqual(out_raw.rstrip(), raw.rstrip())
661 667
662 668
663 669 #-----------------------------------------------------------------------------
664 670 # Main - use as a script, mostly for developer experiments
665 671 #-----------------------------------------------------------------------------
666 672
667 673 if __name__ == '__main__':
668 674 # A simple demo for interactive experimentation. This code will not get
669 675 # picked up by any test suite.
670 676 from IPython.core.inputsplitter import InputSplitter, IPythonInputSplitter
671 677
672 678 # configure here the syntax to use, prompt and whether to autoindent
673 679 #isp, start_prompt = InputSplitter(), '>>> '
674 680 isp, start_prompt = IPythonInputSplitter(), 'In> '
675 681
676 682 autoindent = True
677 683 #autoindent = False
678 684
679 685 try:
680 686 while True:
681 687 prompt = start_prompt
682 688 while isp.push_accepts_more():
683 689 indent = ' '*isp.indent_spaces
684 690 if autoindent:
685 691 line = indent + raw_input(prompt+indent)
686 692 else:
687 693 line = raw_input(prompt)
688 694 isp.push(line)
689 695 prompt = '... '
690 696
691 697 # Here we just return input so we can use it in a test suite, but a
692 698 # real interpreter would instead send it for execution somewhere.
693 699 #src = isp.source; raise EOFError # dbg
694 700 src, raw = isp.source_raw_reset()
695 701 print 'Input source was:\n', src
696 702 print 'Raw source was:\n', raw
697 703 except EOFError:
698 704 print 'Bye'
General Comments 0
You need to be logged in to leave comments. Login now