##// END OF EJS Templates
Merge pull request #13310 from Kojoley/suppress-deprecation-from-inputsplitter...
Matthias Bussonnier -
r27117:b7f20475 merge
parent child Browse files
Show More
@@ -1,641 +1,642
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) IPython Development Team.
5 # Copyright (c) IPython Development Team.
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7
7
8 import unittest
8 import unittest
9 import pytest
9 import pytest
10 import sys
10 import sys
11
11
12 from IPython.core import inputsplitter as isp
12 with pytest.warns(DeprecationWarning, match="inputsplitter"):
13 from IPython.core import inputsplitter as isp
13 from IPython.core.inputtransformer import InputTransformer
14 from IPython.core.inputtransformer import InputTransformer
14 from IPython.core.tests.test_inputtransformer import syntax, syntax_ml
15 from IPython.core.tests.test_inputtransformer import syntax, syntax_ml
15 from IPython.testing import tools as tt
16 from IPython.testing import tools as tt
16
17
17 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
18 # Semi-complete examples (also used as tests)
19 # Semi-complete examples (also used as tests)
19 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
20
21
21 # Note: at the bottom, there's a slightly more complete version of this that
22 # Note: at the bottom, there's a slightly more complete version of this that
22 # can be useful during development of code here.
23 # can be useful during development of code here.
23
24
24 def mini_interactive_loop(input_func):
25 def mini_interactive_loop(input_func):
25 """Minimal example of the logic of an interactive interpreter loop.
26 """Minimal example of the logic of an interactive interpreter loop.
26
27
27 This serves as an example, and it is used by the test system with a fake
28 This serves as an example, and it is used by the test system with a fake
28 raw_input that simulates interactive input."""
29 raw_input that simulates interactive input."""
29
30
30 from IPython.core.inputsplitter import InputSplitter
31 from IPython.core.inputsplitter import InputSplitter
31
32
32 isp = InputSplitter()
33 isp = InputSplitter()
33 # In practice, this input loop would be wrapped in an outside loop to read
34 # In practice, this input loop would be wrapped in an outside loop to read
34 # input indefinitely, until some exit/quit command was issued. Here we
35 # input indefinitely, until some exit/quit command was issued. Here we
35 # only illustrate the basic inner loop.
36 # only illustrate the basic inner loop.
36 while isp.push_accepts_more():
37 while isp.push_accepts_more():
37 indent = ' '*isp.get_indent_spaces()
38 indent = ' '*isp.get_indent_spaces()
38 prompt = '>>> ' + indent
39 prompt = '>>> ' + indent
39 line = indent + input_func(prompt)
40 line = indent + input_func(prompt)
40 isp.push(line)
41 isp.push(line)
41
42
42 # Here we just return input so we can use it in a test suite, but a real
43 # Here we just return input so we can use it in a test suite, but a real
43 # interpreter would instead send it for execution somewhere.
44 # interpreter would instead send it for execution somewhere.
44 src = isp.source_reset()
45 src = isp.source_reset()
45 #print 'Input source was:\n', src # dbg
46 #print 'Input source was:\n', src # dbg
46 return src
47 return src
47
48
48 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
49 # Test utilities, just for local use
50 # Test utilities, just for local use
50 #-----------------------------------------------------------------------------
51 #-----------------------------------------------------------------------------
51
52
52
53
53 def pseudo_input(lines):
54 def pseudo_input(lines):
54 """Return a function that acts like raw_input but feeds the input list."""
55 """Return a function that acts like raw_input but feeds the input list."""
55 ilines = iter(lines)
56 ilines = iter(lines)
56 def raw_in(prompt):
57 def raw_in(prompt):
57 try:
58 try:
58 return next(ilines)
59 return next(ilines)
59 except StopIteration:
60 except StopIteration:
60 return ''
61 return ''
61 return raw_in
62 return raw_in
62
63
63 #-----------------------------------------------------------------------------
64 #-----------------------------------------------------------------------------
64 # Tests
65 # Tests
65 #-----------------------------------------------------------------------------
66 #-----------------------------------------------------------------------------
66 def test_spaces():
67 def test_spaces():
67 tests = [('', 0),
68 tests = [('', 0),
68 (' ', 1),
69 (' ', 1),
69 ('\n', 0),
70 ('\n', 0),
70 (' \n', 1),
71 (' \n', 1),
71 ('x', 0),
72 ('x', 0),
72 (' x', 1),
73 (' x', 1),
73 (' x',2),
74 (' x',2),
74 (' x',4),
75 (' x',4),
75 # Note: tabs are counted as a single whitespace!
76 # Note: tabs are counted as a single whitespace!
76 ('\tx', 1),
77 ('\tx', 1),
77 ('\t x', 2),
78 ('\t x', 2),
78 ]
79 ]
79 tt.check_pairs(isp.num_ini_spaces, tests)
80 tt.check_pairs(isp.num_ini_spaces, tests)
80
81
81
82
82 def test_remove_comments():
83 def test_remove_comments():
83 tests = [('text', 'text'),
84 tests = [('text', 'text'),
84 ('text # comment', 'text '),
85 ('text # comment', 'text '),
85 ('text # comment\n', 'text \n'),
86 ('text # comment\n', 'text \n'),
86 ('text # comment \n', 'text \n'),
87 ('text # comment \n', 'text \n'),
87 ('line # c \nline\n','line \nline\n'),
88 ('line # c \nline\n','line \nline\n'),
88 ('line # c \nline#c2 \nline\nline #c\n\n',
89 ('line # c \nline#c2 \nline\nline #c\n\n',
89 'line \nline\nline\nline \n\n'),
90 'line \nline\nline\nline \n\n'),
90 ]
91 ]
91 tt.check_pairs(isp.remove_comments, tests)
92 tt.check_pairs(isp.remove_comments, tests)
92
93
93
94
94 def test_get_input_encoding():
95 def test_get_input_encoding():
95 encoding = isp.get_input_encoding()
96 encoding = isp.get_input_encoding()
96 assert isinstance(encoding, str)
97 assert isinstance(encoding, str)
97 # simple-minded check that at least encoding a simple string works with the
98 # simple-minded check that at least encoding a simple string works with the
98 # encoding we got.
99 # encoding we got.
99 assert "test".encode(encoding) == b"test"
100 assert "test".encode(encoding) == b"test"
100
101
101
102
102 class NoInputEncodingTestCase(unittest.TestCase):
103 class NoInputEncodingTestCase(unittest.TestCase):
103 def setUp(self):
104 def setUp(self):
104 self.old_stdin = sys.stdin
105 self.old_stdin = sys.stdin
105 class X: pass
106 class X: pass
106 fake_stdin = X()
107 fake_stdin = X()
107 sys.stdin = fake_stdin
108 sys.stdin = fake_stdin
108
109
109 def test(self):
110 def test(self):
110 # Verify that if sys.stdin has no 'encoding' attribute we do the right
111 # Verify that if sys.stdin has no 'encoding' attribute we do the right
111 # thing
112 # thing
112 enc = isp.get_input_encoding()
113 enc = isp.get_input_encoding()
113 self.assertEqual(enc, 'ascii')
114 self.assertEqual(enc, 'ascii')
114
115
115 def tearDown(self):
116 def tearDown(self):
116 sys.stdin = self.old_stdin
117 sys.stdin = self.old_stdin
117
118
118
119
119 class InputSplitterTestCase(unittest.TestCase):
120 class InputSplitterTestCase(unittest.TestCase):
120 def setUp(self):
121 def setUp(self):
121 self.isp = isp.InputSplitter()
122 self.isp = isp.InputSplitter()
122
123
123 def test_reset(self):
124 def test_reset(self):
124 isp = self.isp
125 isp = self.isp
125 isp.push('x=1')
126 isp.push('x=1')
126 isp.reset()
127 isp.reset()
127 self.assertEqual(isp._buffer, [])
128 self.assertEqual(isp._buffer, [])
128 self.assertEqual(isp.get_indent_spaces(), 0)
129 self.assertEqual(isp.get_indent_spaces(), 0)
129 self.assertEqual(isp.source, '')
130 self.assertEqual(isp.source, '')
130 self.assertEqual(isp.code, None)
131 self.assertEqual(isp.code, None)
131 self.assertEqual(isp._is_complete, False)
132 self.assertEqual(isp._is_complete, False)
132
133
133 def test_source(self):
134 def test_source(self):
134 self.isp._store('1')
135 self.isp._store('1')
135 self.isp._store('2')
136 self.isp._store('2')
136 self.assertEqual(self.isp.source, '1\n2\n')
137 self.assertEqual(self.isp.source, '1\n2\n')
137 self.assertEqual(len(self.isp._buffer)>0, True)
138 self.assertEqual(len(self.isp._buffer)>0, True)
138 self.assertEqual(self.isp.source_reset(), '1\n2\n')
139 self.assertEqual(self.isp.source_reset(), '1\n2\n')
139 self.assertEqual(self.isp._buffer, [])
140 self.assertEqual(self.isp._buffer, [])
140 self.assertEqual(self.isp.source, '')
141 self.assertEqual(self.isp.source, '')
141
142
142 def test_indent(self):
143 def test_indent(self):
143 isp = self.isp # shorthand
144 isp = self.isp # shorthand
144 isp.push('x=1')
145 isp.push('x=1')
145 self.assertEqual(isp.get_indent_spaces(), 0)
146 self.assertEqual(isp.get_indent_spaces(), 0)
146 isp.push('if 1:\n x=1')
147 isp.push('if 1:\n x=1')
147 self.assertEqual(isp.get_indent_spaces(), 4)
148 self.assertEqual(isp.get_indent_spaces(), 4)
148 isp.push('y=2\n')
149 isp.push('y=2\n')
149 self.assertEqual(isp.get_indent_spaces(), 0)
150 self.assertEqual(isp.get_indent_spaces(), 0)
150
151
151 def test_indent2(self):
152 def test_indent2(self):
152 isp = self.isp
153 isp = self.isp
153 isp.push('if 1:')
154 isp.push('if 1:')
154 self.assertEqual(isp.get_indent_spaces(), 4)
155 self.assertEqual(isp.get_indent_spaces(), 4)
155 isp.push(' x=1')
156 isp.push(' x=1')
156 self.assertEqual(isp.get_indent_spaces(), 4)
157 self.assertEqual(isp.get_indent_spaces(), 4)
157 # Blank lines shouldn't change the indent level
158 # Blank lines shouldn't change the indent level
158 isp.push(' '*2)
159 isp.push(' '*2)
159 self.assertEqual(isp.get_indent_spaces(), 4)
160 self.assertEqual(isp.get_indent_spaces(), 4)
160
161
161 def test_indent3(self):
162 def test_indent3(self):
162 isp = self.isp
163 isp = self.isp
163 # When a multiline statement contains parens or multiline strings, we
164 # When a multiline statement contains parens or multiline strings, we
164 # shouldn't get confused.
165 # shouldn't get confused.
165 isp.push("if 1:")
166 isp.push("if 1:")
166 isp.push(" x = (1+\n 2)")
167 isp.push(" x = (1+\n 2)")
167 self.assertEqual(isp.get_indent_spaces(), 4)
168 self.assertEqual(isp.get_indent_spaces(), 4)
168
169
169 def test_indent4(self):
170 def test_indent4(self):
170 isp = self.isp
171 isp = self.isp
171 # whitespace after ':' should not screw up indent level
172 # whitespace after ':' should not screw up indent level
172 isp.push('if 1: \n x=1')
173 isp.push('if 1: \n x=1')
173 self.assertEqual(isp.get_indent_spaces(), 4)
174 self.assertEqual(isp.get_indent_spaces(), 4)
174 isp.push('y=2\n')
175 isp.push('y=2\n')
175 self.assertEqual(isp.get_indent_spaces(), 0)
176 self.assertEqual(isp.get_indent_spaces(), 0)
176 isp.push('if 1:\t\n x=1')
177 isp.push('if 1:\t\n x=1')
177 self.assertEqual(isp.get_indent_spaces(), 4)
178 self.assertEqual(isp.get_indent_spaces(), 4)
178 isp.push('y=2\n')
179 isp.push('y=2\n')
179 self.assertEqual(isp.get_indent_spaces(), 0)
180 self.assertEqual(isp.get_indent_spaces(), 0)
180
181
181 def test_dedent_pass(self):
182 def test_dedent_pass(self):
182 isp = self.isp # shorthand
183 isp = self.isp # shorthand
183 # should NOT cause dedent
184 # should NOT cause dedent
184 isp.push('if 1:\n passes = 5')
185 isp.push('if 1:\n passes = 5')
185 self.assertEqual(isp.get_indent_spaces(), 4)
186 self.assertEqual(isp.get_indent_spaces(), 4)
186 isp.push('if 1:\n pass')
187 isp.push('if 1:\n pass')
187 self.assertEqual(isp.get_indent_spaces(), 0)
188 self.assertEqual(isp.get_indent_spaces(), 0)
188 isp.push('if 1:\n pass ')
189 isp.push('if 1:\n pass ')
189 self.assertEqual(isp.get_indent_spaces(), 0)
190 self.assertEqual(isp.get_indent_spaces(), 0)
190
191
191 def test_dedent_break(self):
192 def test_dedent_break(self):
192 isp = self.isp # shorthand
193 isp = self.isp # shorthand
193 # should NOT cause dedent
194 # should NOT cause dedent
194 isp.push('while 1:\n breaks = 5')
195 isp.push('while 1:\n breaks = 5')
195 self.assertEqual(isp.get_indent_spaces(), 4)
196 self.assertEqual(isp.get_indent_spaces(), 4)
196 isp.push('while 1:\n break')
197 isp.push('while 1:\n break')
197 self.assertEqual(isp.get_indent_spaces(), 0)
198 self.assertEqual(isp.get_indent_spaces(), 0)
198 isp.push('while 1:\n break ')
199 isp.push('while 1:\n break ')
199 self.assertEqual(isp.get_indent_spaces(), 0)
200 self.assertEqual(isp.get_indent_spaces(), 0)
200
201
201 def test_dedent_continue(self):
202 def test_dedent_continue(self):
202 isp = self.isp # shorthand
203 isp = self.isp # shorthand
203 # should NOT cause dedent
204 # should NOT cause dedent
204 isp.push('while 1:\n continues = 5')
205 isp.push('while 1:\n continues = 5')
205 self.assertEqual(isp.get_indent_spaces(), 4)
206 self.assertEqual(isp.get_indent_spaces(), 4)
206 isp.push('while 1:\n continue')
207 isp.push('while 1:\n continue')
207 self.assertEqual(isp.get_indent_spaces(), 0)
208 self.assertEqual(isp.get_indent_spaces(), 0)
208 isp.push('while 1:\n continue ')
209 isp.push('while 1:\n continue ')
209 self.assertEqual(isp.get_indent_spaces(), 0)
210 self.assertEqual(isp.get_indent_spaces(), 0)
210
211
211 def test_dedent_raise(self):
212 def test_dedent_raise(self):
212 isp = self.isp # shorthand
213 isp = self.isp # shorthand
213 # should NOT cause dedent
214 # should NOT cause dedent
214 isp.push('if 1:\n raised = 4')
215 isp.push('if 1:\n raised = 4')
215 self.assertEqual(isp.get_indent_spaces(), 4)
216 self.assertEqual(isp.get_indent_spaces(), 4)
216 isp.push('if 1:\n raise TypeError()')
217 isp.push('if 1:\n raise TypeError()')
217 self.assertEqual(isp.get_indent_spaces(), 0)
218 self.assertEqual(isp.get_indent_spaces(), 0)
218 isp.push('if 1:\n raise')
219 isp.push('if 1:\n raise')
219 self.assertEqual(isp.get_indent_spaces(), 0)
220 self.assertEqual(isp.get_indent_spaces(), 0)
220 isp.push('if 1:\n raise ')
221 isp.push('if 1:\n raise ')
221 self.assertEqual(isp.get_indent_spaces(), 0)
222 self.assertEqual(isp.get_indent_spaces(), 0)
222
223
223 def test_dedent_return(self):
224 def test_dedent_return(self):
224 isp = self.isp # shorthand
225 isp = self.isp # shorthand
225 # should NOT cause dedent
226 # should NOT cause dedent
226 isp.push('if 1:\n returning = 4')
227 isp.push('if 1:\n returning = 4')
227 self.assertEqual(isp.get_indent_spaces(), 4)
228 self.assertEqual(isp.get_indent_spaces(), 4)
228 isp.push('if 1:\n return 5 + 493')
229 isp.push('if 1:\n return 5 + 493')
229 self.assertEqual(isp.get_indent_spaces(), 0)
230 self.assertEqual(isp.get_indent_spaces(), 0)
230 isp.push('if 1:\n return')
231 isp.push('if 1:\n return')
231 self.assertEqual(isp.get_indent_spaces(), 0)
232 self.assertEqual(isp.get_indent_spaces(), 0)
232 isp.push('if 1:\n return ')
233 isp.push('if 1:\n return ')
233 self.assertEqual(isp.get_indent_spaces(), 0)
234 self.assertEqual(isp.get_indent_spaces(), 0)
234 isp.push('if 1:\n return(0)')
235 isp.push('if 1:\n return(0)')
235 self.assertEqual(isp.get_indent_spaces(), 0)
236 self.assertEqual(isp.get_indent_spaces(), 0)
236
237
237 def test_push(self):
238 def test_push(self):
238 isp = self.isp
239 isp = self.isp
239 self.assertEqual(isp.push('x=1'), True)
240 self.assertEqual(isp.push('x=1'), True)
240
241
241 def test_push2(self):
242 def test_push2(self):
242 isp = self.isp
243 isp = self.isp
243 self.assertEqual(isp.push('if 1:'), False)
244 self.assertEqual(isp.push('if 1:'), False)
244 for line in [' x=1', '# a comment', ' y=2']:
245 for line in [' x=1', '# a comment', ' y=2']:
245 print(line)
246 print(line)
246 self.assertEqual(isp.push(line), True)
247 self.assertEqual(isp.push(line), True)
247
248
248 def test_push3(self):
249 def test_push3(self):
249 isp = self.isp
250 isp = self.isp
250 isp.push('if True:')
251 isp.push('if True:')
251 isp.push(' a = 1')
252 isp.push(' a = 1')
252 self.assertEqual(isp.push('b = [1,'), False)
253 self.assertEqual(isp.push('b = [1,'), False)
253
254
254 def test_push_accepts_more(self):
255 def test_push_accepts_more(self):
255 isp = self.isp
256 isp = self.isp
256 isp.push('x=1')
257 isp.push('x=1')
257 self.assertEqual(isp.push_accepts_more(), False)
258 self.assertEqual(isp.push_accepts_more(), False)
258
259
259 def test_push_accepts_more2(self):
260 def test_push_accepts_more2(self):
260 isp = self.isp
261 isp = self.isp
261 isp.push('if 1:')
262 isp.push('if 1:')
262 self.assertEqual(isp.push_accepts_more(), True)
263 self.assertEqual(isp.push_accepts_more(), True)
263 isp.push(' x=1')
264 isp.push(' x=1')
264 self.assertEqual(isp.push_accepts_more(), True)
265 self.assertEqual(isp.push_accepts_more(), True)
265 isp.push('')
266 isp.push('')
266 self.assertEqual(isp.push_accepts_more(), False)
267 self.assertEqual(isp.push_accepts_more(), False)
267
268
268 def test_push_accepts_more3(self):
269 def test_push_accepts_more3(self):
269 isp = self.isp
270 isp = self.isp
270 isp.push("x = (2+\n3)")
271 isp.push("x = (2+\n3)")
271 self.assertEqual(isp.push_accepts_more(), False)
272 self.assertEqual(isp.push_accepts_more(), False)
272
273
273 def test_push_accepts_more4(self):
274 def test_push_accepts_more4(self):
274 isp = self.isp
275 isp = self.isp
275 # When a multiline statement contains parens or multiline strings, we
276 # When a multiline statement contains parens or multiline strings, we
276 # shouldn't get confused.
277 # shouldn't get confused.
277 # FIXME: we should be able to better handle de-dents in statements like
278 # FIXME: we should be able to better handle de-dents in statements like
278 # multiline strings and multiline expressions (continued with \ or
279 # multiline strings and multiline expressions (continued with \ or
279 # parens). Right now we aren't handling the indentation tracking quite
280 # parens). Right now we aren't handling the indentation tracking quite
280 # correctly with this, though in practice it may not be too much of a
281 # correctly with this, though in practice it may not be too much of a
281 # problem. We'll need to see.
282 # problem. We'll need to see.
282 isp.push("if 1:")
283 isp.push("if 1:")
283 isp.push(" x = (2+")
284 isp.push(" x = (2+")
284 isp.push(" 3)")
285 isp.push(" 3)")
285 self.assertEqual(isp.push_accepts_more(), True)
286 self.assertEqual(isp.push_accepts_more(), True)
286 isp.push(" y = 3")
287 isp.push(" y = 3")
287 self.assertEqual(isp.push_accepts_more(), True)
288 self.assertEqual(isp.push_accepts_more(), True)
288 isp.push('')
289 isp.push('')
289 self.assertEqual(isp.push_accepts_more(), False)
290 self.assertEqual(isp.push_accepts_more(), False)
290
291
291 def test_push_accepts_more5(self):
292 def test_push_accepts_more5(self):
292 isp = self.isp
293 isp = self.isp
293 isp.push('try:')
294 isp.push('try:')
294 isp.push(' a = 5')
295 isp.push(' a = 5')
295 isp.push('except:')
296 isp.push('except:')
296 isp.push(' raise')
297 isp.push(' raise')
297 # We want to be able to add an else: block at this point, so it should
298 # We want to be able to add an else: block at this point, so it should
298 # wait for a blank line.
299 # wait for a blank line.
299 self.assertEqual(isp.push_accepts_more(), True)
300 self.assertEqual(isp.push_accepts_more(), True)
300
301
301 def test_continuation(self):
302 def test_continuation(self):
302 isp = self.isp
303 isp = self.isp
303 isp.push("import os, \\")
304 isp.push("import os, \\")
304 self.assertEqual(isp.push_accepts_more(), True)
305 self.assertEqual(isp.push_accepts_more(), True)
305 isp.push("sys")
306 isp.push("sys")
306 self.assertEqual(isp.push_accepts_more(), False)
307 self.assertEqual(isp.push_accepts_more(), False)
307
308
308 def test_syntax_error(self):
309 def test_syntax_error(self):
309 isp = self.isp
310 isp = self.isp
310 # Syntax errors immediately produce a 'ready' block, so the invalid
311 # Syntax errors immediately produce a 'ready' block, so the invalid
311 # Python can be sent to the kernel for evaluation with possible ipython
312 # Python can be sent to the kernel for evaluation with possible ipython
312 # special-syntax conversion.
313 # special-syntax conversion.
313 isp.push('run foo')
314 isp.push('run foo')
314 self.assertEqual(isp.push_accepts_more(), False)
315 self.assertEqual(isp.push_accepts_more(), False)
315
316
316 def test_unicode(self):
317 def test_unicode(self):
317 self.isp.push(u"Pérez")
318 self.isp.push(u"Pérez")
318 self.isp.push(u'\xc3\xa9')
319 self.isp.push(u'\xc3\xa9')
319 self.isp.push(u"u'\xc3\xa9'")
320 self.isp.push(u"u'\xc3\xa9'")
320
321
321 @pytest.mark.xfail(
322 @pytest.mark.xfail(
322 reason="Bug in python 3.9.8 – bpo 45738",
323 reason="Bug in python 3.9.8 – bpo 45738",
323 condition=sys.version_info in [(3, 9, 8, "final", 0), (3, 11, 0, "alpha", 2)],
324 condition=sys.version_info in [(3, 9, 8, "final", 0), (3, 11, 0, "alpha", 2)],
324 raises=SystemError,
325 raises=SystemError,
325 strict=True,
326 strict=True,
326 )
327 )
327 def test_line_continuation(self):
328 def test_line_continuation(self):
328 """ Test issue #2108."""
329 """ Test issue #2108."""
329 isp = self.isp
330 isp = self.isp
330 # A blank line after a line continuation should not accept more
331 # A blank line after a line continuation should not accept more
331 isp.push("1 \\\n\n")
332 isp.push("1 \\\n\n")
332 self.assertEqual(isp.push_accepts_more(), False)
333 self.assertEqual(isp.push_accepts_more(), False)
333 # Whitespace after a \ is a SyntaxError. The only way to test that
334 # Whitespace after a \ is a SyntaxError. The only way to test that
334 # here is to test that push doesn't accept more (as with
335 # here is to test that push doesn't accept more (as with
335 # test_syntax_error() above).
336 # test_syntax_error() above).
336 isp.push(r"1 \ ")
337 isp.push(r"1 \ ")
337 self.assertEqual(isp.push_accepts_more(), False)
338 self.assertEqual(isp.push_accepts_more(), False)
338 # Even if the line is continuable (c.f. the regular Python
339 # Even if the line is continuable (c.f. the regular Python
339 # interpreter)
340 # interpreter)
340 isp.push(r"(1 \ ")
341 isp.push(r"(1 \ ")
341 self.assertEqual(isp.push_accepts_more(), False)
342 self.assertEqual(isp.push_accepts_more(), False)
342
343
343 def test_check_complete(self):
344 def test_check_complete(self):
344 isp = self.isp
345 isp = self.isp
345 self.assertEqual(isp.check_complete("a = 1"), ('complete', None))
346 self.assertEqual(isp.check_complete("a = 1"), ('complete', None))
346 self.assertEqual(isp.check_complete("for a in range(5):"), ('incomplete', 4))
347 self.assertEqual(isp.check_complete("for a in range(5):"), ('incomplete', 4))
347 self.assertEqual(isp.check_complete("raise = 2"), ('invalid', None))
348 self.assertEqual(isp.check_complete("raise = 2"), ('invalid', None))
348 self.assertEqual(isp.check_complete("a = [1,\n2,"), ('incomplete', 0))
349 self.assertEqual(isp.check_complete("a = [1,\n2,"), ('incomplete', 0))
349 self.assertEqual(isp.check_complete("def a():\n x=1\n global x"), ('invalid', None))
350 self.assertEqual(isp.check_complete("def a():\n x=1\n global x"), ('invalid', None))
350
351
351 class InteractiveLoopTestCase(unittest.TestCase):
352 class InteractiveLoopTestCase(unittest.TestCase):
352 """Tests for an interactive loop like a python shell.
353 """Tests for an interactive loop like a python shell.
353 """
354 """
354 def check_ns(self, lines, ns):
355 def check_ns(self, lines, ns):
355 """Validate that the given input lines produce the resulting namespace.
356 """Validate that the given input lines produce the resulting namespace.
356
357
357 Note: the input lines are given exactly as they would be typed in an
358 Note: the input lines are given exactly as they would be typed in an
358 auto-indenting environment, as mini_interactive_loop above already does
359 auto-indenting environment, as mini_interactive_loop above already does
359 auto-indenting and prepends spaces to the input.
360 auto-indenting and prepends spaces to the input.
360 """
361 """
361 src = mini_interactive_loop(pseudo_input(lines))
362 src = mini_interactive_loop(pseudo_input(lines))
362 test_ns = {}
363 test_ns = {}
363 exec(src, test_ns)
364 exec(src, test_ns)
364 # We can't check that the provided ns is identical to the test_ns,
365 # We can't check that the provided ns is identical to the test_ns,
365 # because Python fills test_ns with extra keys (copyright, etc). But
366 # because Python fills test_ns with extra keys (copyright, etc). But
366 # we can check that the given dict is *contained* in test_ns
367 # we can check that the given dict is *contained* in test_ns
367 for k,v in ns.items():
368 for k,v in ns.items():
368 self.assertEqual(test_ns[k], v)
369 self.assertEqual(test_ns[k], v)
369
370
370 def test_simple(self):
371 def test_simple(self):
371 self.check_ns(['x=1'], dict(x=1))
372 self.check_ns(['x=1'], dict(x=1))
372
373
373 def test_simple2(self):
374 def test_simple2(self):
374 self.check_ns(['if 1:', 'x=2'], dict(x=2))
375 self.check_ns(['if 1:', 'x=2'], dict(x=2))
375
376
376 def test_xy(self):
377 def test_xy(self):
377 self.check_ns(['x=1; y=2'], dict(x=1, y=2))
378 self.check_ns(['x=1; y=2'], dict(x=1, y=2))
378
379
379 def test_abc(self):
380 def test_abc(self):
380 self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3))
381 self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3))
381
382
382 def test_multi(self):
383 def test_multi(self):
383 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
384 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
384
385
385
386
386 class IPythonInputTestCase(InputSplitterTestCase):
387 class IPythonInputTestCase(InputSplitterTestCase):
387 """By just creating a new class whose .isp is a different instance, we
388 """By just creating a new class whose .isp is a different instance, we
388 re-run the same test battery on the new input splitter.
389 re-run the same test battery on the new input splitter.
389
390
390 In addition, this runs the tests over the syntax and syntax_ml dicts that
391 In addition, this runs the tests over the syntax and syntax_ml dicts that
391 were tested by individual functions, as part of the OO interface.
392 were tested by individual functions, as part of the OO interface.
392
393
393 It also makes some checks on the raw buffer storage.
394 It also makes some checks on the raw buffer storage.
394 """
395 """
395
396
396 def setUp(self):
397 def setUp(self):
397 self.isp = isp.IPythonInputSplitter()
398 self.isp = isp.IPythonInputSplitter()
398
399
399 def test_syntax(self):
400 def test_syntax(self):
400 """Call all single-line syntax tests from the main object"""
401 """Call all single-line syntax tests from the main object"""
401 isp = self.isp
402 isp = self.isp
402 for example in syntax.values():
403 for example in syntax.values():
403 for raw, out_t in example:
404 for raw, out_t in example:
404 if raw.startswith(' '):
405 if raw.startswith(' '):
405 continue
406 continue
406
407
407 isp.push(raw+'\n')
408 isp.push(raw+'\n')
408 out_raw = isp.source_raw
409 out_raw = isp.source_raw
409 out = isp.source_reset()
410 out = isp.source_reset()
410 self.assertEqual(out.rstrip(), out_t,
411 self.assertEqual(out.rstrip(), out_t,
411 tt.pair_fail_msg.format("inputsplitter",raw, out_t, out))
412 tt.pair_fail_msg.format("inputsplitter",raw, out_t, out))
412 self.assertEqual(out_raw.rstrip(), raw.rstrip())
413 self.assertEqual(out_raw.rstrip(), raw.rstrip())
413
414
414 def test_syntax_multiline(self):
415 def test_syntax_multiline(self):
415 isp = self.isp
416 isp = self.isp
416 for example in syntax_ml.values():
417 for example in syntax_ml.values():
417 for line_pairs in example:
418 for line_pairs in example:
418 out_t_parts = []
419 out_t_parts = []
419 raw_parts = []
420 raw_parts = []
420 for lraw, out_t_part in line_pairs:
421 for lraw, out_t_part in line_pairs:
421 if out_t_part is not None:
422 if out_t_part is not None:
422 out_t_parts.append(out_t_part)
423 out_t_parts.append(out_t_part)
423
424
424 if lraw is not None:
425 if lraw is not None:
425 isp.push(lraw)
426 isp.push(lraw)
426 raw_parts.append(lraw)
427 raw_parts.append(lraw)
427
428
428 out_raw = isp.source_raw
429 out_raw = isp.source_raw
429 out = isp.source_reset()
430 out = isp.source_reset()
430 out_t = '\n'.join(out_t_parts).rstrip()
431 out_t = '\n'.join(out_t_parts).rstrip()
431 raw = '\n'.join(raw_parts).rstrip()
432 raw = '\n'.join(raw_parts).rstrip()
432 self.assertEqual(out.rstrip(), out_t)
433 self.assertEqual(out.rstrip(), out_t)
433 self.assertEqual(out_raw.rstrip(), raw)
434 self.assertEqual(out_raw.rstrip(), raw)
434
435
435 def test_syntax_multiline_cell(self):
436 def test_syntax_multiline_cell(self):
436 isp = self.isp
437 isp = self.isp
437 for example in syntax_ml.values():
438 for example in syntax_ml.values():
438
439
439 out_t_parts = []
440 out_t_parts = []
440 for line_pairs in example:
441 for line_pairs in example:
441 raw = '\n'.join(r for r, _ in line_pairs if r is not None)
442 raw = '\n'.join(r for r, _ in line_pairs if r is not None)
442 out_t = '\n'.join(t for _,t in line_pairs if t is not None)
443 out_t = '\n'.join(t for _,t in line_pairs if t is not None)
443 out = isp.transform_cell(raw)
444 out = isp.transform_cell(raw)
444 # Match ignoring trailing whitespace
445 # Match ignoring trailing whitespace
445 self.assertEqual(out.rstrip(), out_t.rstrip())
446 self.assertEqual(out.rstrip(), out_t.rstrip())
446
447
447 def test_cellmagic_preempt(self):
448 def test_cellmagic_preempt(self):
448 isp = self.isp
449 isp = self.isp
449 for raw, name, line, cell in [
450 for raw, name, line, cell in [
450 ("%%cellm a\nIn[1]:", u'cellm', u'a', u'In[1]:'),
451 ("%%cellm a\nIn[1]:", u'cellm', u'a', u'In[1]:'),
451 ("%%cellm \nline\n>>> hi", u'cellm', u'', u'line\n>>> hi'),
452 ("%%cellm \nline\n>>> hi", u'cellm', u'', u'line\n>>> hi'),
452 (">>> %%cellm \nline\n>>> hi", u'cellm', u'', u'line\nhi'),
453 (">>> %%cellm \nline\n>>> hi", u'cellm', u'', u'line\nhi'),
453 ("%%cellm \n>>> hi", u'cellm', u'', u'>>> hi'),
454 ("%%cellm \n>>> hi", u'cellm', u'', u'>>> hi'),
454 ("%%cellm \nline1\nline2", u'cellm', u'', u'line1\nline2'),
455 ("%%cellm \nline1\nline2", u'cellm', u'', u'line1\nline2'),
455 ("%%cellm \nline1\\\\\nline2", u'cellm', u'', u'line1\\\\\nline2'),
456 ("%%cellm \nline1\\\\\nline2", u'cellm', u'', u'line1\\\\\nline2'),
456 ]:
457 ]:
457 expected = "get_ipython().run_cell_magic(%r, %r, %r)" % (
458 expected = "get_ipython().run_cell_magic(%r, %r, %r)" % (
458 name, line, cell
459 name, line, cell
459 )
460 )
460 out = isp.transform_cell(raw)
461 out = isp.transform_cell(raw)
461 self.assertEqual(out.rstrip(), expected.rstrip())
462 self.assertEqual(out.rstrip(), expected.rstrip())
462
463
463 def test_multiline_passthrough(self):
464 def test_multiline_passthrough(self):
464 isp = self.isp
465 isp = self.isp
465 class CommentTransformer(InputTransformer):
466 class CommentTransformer(InputTransformer):
466 def __init__(self):
467 def __init__(self):
467 self._lines = []
468 self._lines = []
468
469
469 def push(self, line):
470 def push(self, line):
470 self._lines.append(line + '#')
471 self._lines.append(line + '#')
471
472
472 def reset(self):
473 def reset(self):
473 text = '\n'.join(self._lines)
474 text = '\n'.join(self._lines)
474 self._lines = []
475 self._lines = []
475 return text
476 return text
476
477
477 isp.physical_line_transforms.insert(0, CommentTransformer())
478 isp.physical_line_transforms.insert(0, CommentTransformer())
478
479
479 for raw, expected in [
480 for raw, expected in [
480 ("a=5", "a=5#"),
481 ("a=5", "a=5#"),
481 ("%ls foo", "get_ipython().run_line_magic(%r, %r)" % (u'ls', u'foo#')),
482 ("%ls foo", "get_ipython().run_line_magic(%r, %r)" % (u'ls', u'foo#')),
482 ("!ls foo\n%ls bar", "get_ipython().system(%r)\nget_ipython().run_line_magic(%r, %r)" % (
483 ("!ls foo\n%ls bar", "get_ipython().system(%r)\nget_ipython().run_line_magic(%r, %r)" % (
483 u'ls foo#', u'ls', u'bar#'
484 u'ls foo#', u'ls', u'bar#'
484 )),
485 )),
485 ("1\n2\n3\n%ls foo\n4\n5", "1#\n2#\n3#\nget_ipython().run_line_magic(%r, %r)\n4#\n5#" % (u'ls', u'foo#')),
486 ("1\n2\n3\n%ls foo\n4\n5", "1#\n2#\n3#\nget_ipython().run_line_magic(%r, %r)\n4#\n5#" % (u'ls', u'foo#')),
486 ]:
487 ]:
487 out = isp.transform_cell(raw)
488 out = isp.transform_cell(raw)
488 self.assertEqual(out.rstrip(), expected.rstrip())
489 self.assertEqual(out.rstrip(), expected.rstrip())
489
490
490 #-----------------------------------------------------------------------------
491 #-----------------------------------------------------------------------------
491 # Main - use as a script, mostly for developer experiments
492 # Main - use as a script, mostly for developer experiments
492 #-----------------------------------------------------------------------------
493 #-----------------------------------------------------------------------------
493
494
494 if __name__ == '__main__':
495 if __name__ == '__main__':
495 # A simple demo for interactive experimentation. This code will not get
496 # A simple demo for interactive experimentation. This code will not get
496 # picked up by any test suite.
497 # picked up by any test suite.
497 from IPython.core.inputsplitter import IPythonInputSplitter
498 from IPython.core.inputsplitter import IPythonInputSplitter
498
499
499 # configure here the syntax to use, prompt and whether to autoindent
500 # configure here the syntax to use, prompt and whether to autoindent
500 #isp, start_prompt = InputSplitter(), '>>> '
501 #isp, start_prompt = InputSplitter(), '>>> '
501 isp, start_prompt = IPythonInputSplitter(), 'In> '
502 isp, start_prompt = IPythonInputSplitter(), 'In> '
502
503
503 autoindent = True
504 autoindent = True
504 #autoindent = False
505 #autoindent = False
505
506
506 try:
507 try:
507 while True:
508 while True:
508 prompt = start_prompt
509 prompt = start_prompt
509 while isp.push_accepts_more():
510 while isp.push_accepts_more():
510 indent = ' '*isp.get_indent_spaces()
511 indent = ' '*isp.get_indent_spaces()
511 if autoindent:
512 if autoindent:
512 line = indent + input(prompt+indent)
513 line = indent + input(prompt+indent)
513 else:
514 else:
514 line = input(prompt)
515 line = input(prompt)
515 isp.push(line)
516 isp.push(line)
516 prompt = '... '
517 prompt = '... '
517
518
518 # Here we just return input so we can use it in a test suite, but a
519 # Here we just return input so we can use it in a test suite, but a
519 # real interpreter would instead send it for execution somewhere.
520 # real interpreter would instead send it for execution somewhere.
520 #src = isp.source; raise EOFError # dbg
521 #src = isp.source; raise EOFError # dbg
521 raw = isp.source_raw
522 raw = isp.source_raw
522 src = isp.source_reset()
523 src = isp.source_reset()
523 print('Input source was:\n', src)
524 print('Input source was:\n', src)
524 print('Raw source was:\n', raw)
525 print('Raw source was:\n', raw)
525 except EOFError:
526 except EOFError:
526 print('Bye')
527 print('Bye')
527
528
528 # Tests for cell magics support
529 # Tests for cell magics support
529
530
530 def test_last_blank():
531 def test_last_blank():
531 assert isp.last_blank("") is False
532 assert isp.last_blank("") is False
532 assert isp.last_blank("abc") is False
533 assert isp.last_blank("abc") is False
533 assert isp.last_blank("abc\n") is False
534 assert isp.last_blank("abc\n") is False
534 assert isp.last_blank("abc\na") is False
535 assert isp.last_blank("abc\na") is False
535
536
536 assert isp.last_blank("\n") is True
537 assert isp.last_blank("\n") is True
537 assert isp.last_blank("\n ") is True
538 assert isp.last_blank("\n ") is True
538 assert isp.last_blank("abc\n ") is True
539 assert isp.last_blank("abc\n ") is True
539 assert isp.last_blank("abc\n\n") is True
540 assert isp.last_blank("abc\n\n") is True
540 assert isp.last_blank("abc\nd\n\n") is True
541 assert isp.last_blank("abc\nd\n\n") is True
541 assert isp.last_blank("abc\nd\ne\n\n") is True
542 assert isp.last_blank("abc\nd\ne\n\n") is True
542 assert isp.last_blank("abc \n \n \n\n") is True
543 assert isp.last_blank("abc \n \n \n\n") is True
543
544
544
545
545 def test_last_two_blanks():
546 def test_last_two_blanks():
546 assert isp.last_two_blanks("") is False
547 assert isp.last_two_blanks("") is False
547 assert isp.last_two_blanks("abc") is False
548 assert isp.last_two_blanks("abc") is False
548 assert isp.last_two_blanks("abc\n") is False
549 assert isp.last_two_blanks("abc\n") is False
549 assert isp.last_two_blanks("abc\n\na") is False
550 assert isp.last_two_blanks("abc\n\na") is False
550 assert isp.last_two_blanks("abc\n \n") is False
551 assert isp.last_two_blanks("abc\n \n") is False
551 assert isp.last_two_blanks("abc\n\n") is False
552 assert isp.last_two_blanks("abc\n\n") is False
552
553
553 assert isp.last_two_blanks("\n\n") is True
554 assert isp.last_two_blanks("\n\n") is True
554 assert isp.last_two_blanks("\n\n ") is True
555 assert isp.last_two_blanks("\n\n ") is True
555 assert isp.last_two_blanks("\n \n") is True
556 assert isp.last_two_blanks("\n \n") is True
556 assert isp.last_two_blanks("abc\n\n ") is True
557 assert isp.last_two_blanks("abc\n\n ") is True
557 assert isp.last_two_blanks("abc\n\n\n") is True
558 assert isp.last_two_blanks("abc\n\n\n") is True
558 assert isp.last_two_blanks("abc\n\n \n") is True
559 assert isp.last_two_blanks("abc\n\n \n") is True
559 assert isp.last_two_blanks("abc\n\n \n ") is True
560 assert isp.last_two_blanks("abc\n\n \n ") is True
560 assert isp.last_two_blanks("abc\n\n \n \n") is True
561 assert isp.last_two_blanks("abc\n\n \n \n") is True
561 assert isp.last_two_blanks("abc\nd\n\n\n") is True
562 assert isp.last_two_blanks("abc\nd\n\n\n") is True
562 assert isp.last_two_blanks("abc\nd\ne\nf\n\n\n") is True
563 assert isp.last_two_blanks("abc\nd\ne\nf\n\n\n") is True
563
564
564
565
565 class CellMagicsCommon(object):
566 class CellMagicsCommon(object):
566
567
567 def test_whole_cell(self):
568 def test_whole_cell(self):
568 src = "%%cellm line\nbody\n"
569 src = "%%cellm line\nbody\n"
569 out = self.sp.transform_cell(src)
570 out = self.sp.transform_cell(src)
570 ref = "get_ipython().run_cell_magic('cellm', 'line', 'body')\n"
571 ref = "get_ipython().run_cell_magic('cellm', 'line', 'body')\n"
571 assert out == ref
572 assert out == ref
572
573
573 def test_cellmagic_help(self):
574 def test_cellmagic_help(self):
574 self.sp.push('%%cellm?')
575 self.sp.push('%%cellm?')
575 assert self.sp.push_accepts_more() is False
576 assert self.sp.push_accepts_more() is False
576
577
577 def tearDown(self):
578 def tearDown(self):
578 self.sp.reset()
579 self.sp.reset()
579
580
580
581
581 class CellModeCellMagics(CellMagicsCommon, unittest.TestCase):
582 class CellModeCellMagics(CellMagicsCommon, unittest.TestCase):
582 sp = isp.IPythonInputSplitter(line_input_checker=False)
583 sp = isp.IPythonInputSplitter(line_input_checker=False)
583
584
584 def test_incremental(self):
585 def test_incremental(self):
585 sp = self.sp
586 sp = self.sp
586 sp.push("%%cellm firstline\n")
587 sp.push("%%cellm firstline\n")
587 assert sp.push_accepts_more() is True # 1
588 assert sp.push_accepts_more() is True # 1
588 sp.push("line2\n")
589 sp.push("line2\n")
589 assert sp.push_accepts_more() is True # 2
590 assert sp.push_accepts_more() is True # 2
590 sp.push("\n")
591 sp.push("\n")
591 # This should accept a blank line and carry on until the cell is reset
592 # This should accept a blank line and carry on until the cell is reset
592 assert sp.push_accepts_more() is True # 3
593 assert sp.push_accepts_more() is True # 3
593
594
594 def test_no_strip_coding(self):
595 def test_no_strip_coding(self):
595 src = '\n'.join([
596 src = '\n'.join([
596 '%%writefile foo.py',
597 '%%writefile foo.py',
597 '# coding: utf-8',
598 '# coding: utf-8',
598 'print(u"üñîçø∂é")',
599 'print(u"üñîçø∂é")',
599 ])
600 ])
600 out = self.sp.transform_cell(src)
601 out = self.sp.transform_cell(src)
601 assert "# coding: utf-8" in out
602 assert "# coding: utf-8" in out
602
603
603
604
604 class LineModeCellMagics(CellMagicsCommon, unittest.TestCase):
605 class LineModeCellMagics(CellMagicsCommon, unittest.TestCase):
605 sp = isp.IPythonInputSplitter(line_input_checker=True)
606 sp = isp.IPythonInputSplitter(line_input_checker=True)
606
607
607 def test_incremental(self):
608 def test_incremental(self):
608 sp = self.sp
609 sp = self.sp
609 sp.push("%%cellm line2\n")
610 sp.push("%%cellm line2\n")
610 assert sp.push_accepts_more() is True # 1
611 assert sp.push_accepts_more() is True # 1
611 sp.push("\n")
612 sp.push("\n")
612 # In this case, a blank line should end the cell magic
613 # In this case, a blank line should end the cell magic
613 assert sp.push_accepts_more() is False # 2
614 assert sp.push_accepts_more() is False # 2
614
615
615
616
616 indentation_samples = [
617 indentation_samples = [
617 ('a = 1', 0),
618 ('a = 1', 0),
618 ('for a in b:', 4),
619 ('for a in b:', 4),
619 ('def f():', 4),
620 ('def f():', 4),
620 ('def f(): #comment', 4),
621 ('def f(): #comment', 4),
621 ('a = ":#not a comment"', 0),
622 ('a = ":#not a comment"', 0),
622 ('def f():\n a = 1', 4),
623 ('def f():\n a = 1', 4),
623 ('def f():\n return 1', 0),
624 ('def f():\n return 1', 0),
624 ('for a in b:\n'
625 ('for a in b:\n'
625 ' if a < 0:'
626 ' if a < 0:'
626 ' continue', 3),
627 ' continue', 3),
627 ('a = {', 4),
628 ('a = {', 4),
628 ('a = {\n'
629 ('a = {\n'
629 ' 1,', 5),
630 ' 1,', 5),
630 ('b = """123', 0),
631 ('b = """123', 0),
631 ('', 0),
632 ('', 0),
632 ('def f():\n pass', 0),
633 ('def f():\n pass', 0),
633 ('class Bar:\n def f():\n pass', 4),
634 ('class Bar:\n def f():\n pass', 4),
634 ('class Bar:\n def f():\n raise', 4),
635 ('class Bar:\n def f():\n raise', 4),
635 ]
636 ]
636
637
637 def test_find_next_indent():
638 def test_find_next_indent():
638 for code, exp in indentation_samples:
639 for code, exp in indentation_samples:
639 res = isp.find_next_indent(code)
640 res = isp.find_next_indent(code)
640 msg = "{!r} != {!r} (expected)\n Code: {!r}".format(res, exp, code)
641 msg = "{!r} != {!r} (expected)\n Code: {!r}".format(res, exp, code)
641 assert res == exp, msg
642 assert res == exp, msg
General Comments 0
You need to be logged in to leave comments. Login now