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