##// END OF EJS Templates
Fix tests treating singular ')' as an incomplete line
Blazej Michalik -
Show More
@@ -1,355 +1,355 b''
1 1 """Tests for the token-based transformers in IPython.core.inputtransformer2
2 2
3 3 Line-based transformers are the simpler ones; token-based transformers are
4 4 more complex. See test_inputtransformer2_line for tests for line-based
5 5 transformations.
6 6 """
7 7 import nose.tools as nt
8 8 import string
9 9
10 10 from IPython.core import inputtransformer2 as ipt2
11 11 from IPython.core.inputtransformer2 import make_tokens_by_line, _find_assign_op
12 12
13 13 from textwrap import dedent
14 14
15 15 MULTILINE_MAGIC = ("""\
16 16 a = f()
17 17 %foo \\
18 18 bar
19 19 g()
20 20 """.splitlines(keepends=True), (2, 0), """\
21 21 a = f()
22 22 get_ipython().run_line_magic('foo', ' bar')
23 23 g()
24 24 """.splitlines(keepends=True))
25 25
26 26 INDENTED_MAGIC = ("""\
27 27 for a in range(5):
28 28 %ls
29 29 """.splitlines(keepends=True), (2, 4), """\
30 30 for a in range(5):
31 31 get_ipython().run_line_magic('ls', '')
32 32 """.splitlines(keepends=True))
33 33
34 34 CRLF_MAGIC = ([
35 35 "a = f()\n",
36 36 "%ls\r\n",
37 37 "g()\n"
38 38 ], (2, 0), [
39 39 "a = f()\n",
40 40 "get_ipython().run_line_magic('ls', '')\n",
41 41 "g()\n"
42 42 ])
43 43
44 44 MULTILINE_MAGIC_ASSIGN = ("""\
45 45 a = f()
46 46 b = %foo \\
47 47 bar
48 48 g()
49 49 """.splitlines(keepends=True), (2, 4), """\
50 50 a = f()
51 51 b = get_ipython().run_line_magic('foo', ' bar')
52 52 g()
53 53 """.splitlines(keepends=True))
54 54
55 55 MULTILINE_SYSTEM_ASSIGN = ("""\
56 56 a = f()
57 57 b = !foo \\
58 58 bar
59 59 g()
60 60 """.splitlines(keepends=True), (2, 4), """\
61 61 a = f()
62 62 b = get_ipython().getoutput('foo bar')
63 63 g()
64 64 """.splitlines(keepends=True))
65 65
66 66 #####
67 67
68 68 MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT = ("""\
69 69 def test():
70 70 for i in range(1):
71 71 print(i)
72 72 res =! ls
73 73 """.splitlines(keepends=True), (4, 7), '''\
74 74 def test():
75 75 for i in range(1):
76 76 print(i)
77 77 res =get_ipython().getoutput(\' ls\')
78 78 '''.splitlines(keepends=True))
79 79
80 80 ######
81 81
82 82 AUTOCALL_QUOTE = (
83 83 [",f 1 2 3\n"], (1, 0),
84 84 ['f("1", "2", "3")\n']
85 85 )
86 86
87 87 AUTOCALL_QUOTE2 = (
88 88 [";f 1 2 3\n"], (1, 0),
89 89 ['f("1 2 3")\n']
90 90 )
91 91
92 92 AUTOCALL_PAREN = (
93 93 ["/f 1 2 3\n"], (1, 0),
94 94 ['f(1, 2, 3)\n']
95 95 )
96 96
97 97 SIMPLE_HELP = (
98 98 ["foo?\n"], (1, 0),
99 99 ["get_ipython().run_line_magic('pinfo', 'foo')\n"]
100 100 )
101 101
102 102 DETAILED_HELP = (
103 103 ["foo??\n"], (1, 0),
104 104 ["get_ipython().run_line_magic('pinfo2', 'foo')\n"]
105 105 )
106 106
107 107 MAGIC_HELP = (
108 108 ["%foo?\n"], (1, 0),
109 109 ["get_ipython().run_line_magic('pinfo', '%foo')\n"]
110 110 )
111 111
112 112 HELP_IN_EXPR = (
113 113 ["a = b + c?\n"], (1, 0),
114 114 ["get_ipython().set_next_input('a = b + c');"
115 115 "get_ipython().run_line_magic('pinfo', 'c')\n"]
116 116 )
117 117
118 118 HELP_CONTINUED_LINE = ("""\
119 119 a = \\
120 120 zip?
121 121 """.splitlines(keepends=True), (1, 0),
122 122 [r"get_ipython().set_next_input('a = \\\nzip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
123 123 )
124 124
125 125 HELP_MULTILINE = ("""\
126 126 (a,
127 127 b) = zip?
128 128 """.splitlines(keepends=True), (1, 0),
129 129 [r"get_ipython().set_next_input('(a,\nb) = zip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
130 130 )
131 131
132 132 HELP_UNICODE = (
133 133 ["Ο€.foo?\n"], (1, 0),
134 134 ["get_ipython().run_line_magic('pinfo', 'Ο€.foo')\n"]
135 135 )
136 136
137 137
138 138 def null_cleanup_transformer(lines):
139 139 """
140 140 A cleanup transform that returns an empty list.
141 141 """
142 142 return []
143 143
144 144 def check_make_token_by_line_never_ends_empty():
145 145 """
146 146 Check that not sequence of single or double characters ends up leading to en empty list of tokens
147 147 """
148 148 from string import printable
149 149 for c in printable:
150 150 nt.assert_not_equal(make_tokens_by_line(c)[-1], [])
151 151 for k in printable:
152 152 nt.assert_not_equal(make_tokens_by_line(c+k)[-1], [])
153 153
154 154 def check_find(transformer, case, match=True):
155 155 sample, expected_start, _ = case
156 156 tbl = make_tokens_by_line(sample)
157 157 res = transformer.find(tbl)
158 158 if match:
159 159 # start_line is stored 0-indexed, expected values are 1-indexed
160 160 nt.assert_equal((res.start_line+1, res.start_col), expected_start)
161 161 return res
162 162 else:
163 163 nt.assert_is(res, None)
164 164
165 165 def check_transform(transformer_cls, case):
166 166 lines, start, expected = case
167 167 transformer = transformer_cls(start)
168 168 nt.assert_equal(transformer.transform(lines), expected)
169 169
170 170 def test_continued_line():
171 171 lines = MULTILINE_MAGIC_ASSIGN[0]
172 172 nt.assert_equal(ipt2.find_end_of_continued_line(lines, 1), 2)
173 173
174 174 nt.assert_equal(ipt2.assemble_continued_line(lines, (1, 5), 2), "foo bar")
175 175
176 176 def test_find_assign_magic():
177 177 check_find(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
178 178 check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN, match=False)
179 179 check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT, match=False)
180 180
181 181 def test_transform_assign_magic():
182 182 check_transform(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
183 183
184 184 def test_find_assign_system():
185 185 check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
186 186 check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
187 187 check_find(ipt2.SystemAssign, (["a = !ls\n"], (1, 5), None))
188 188 check_find(ipt2.SystemAssign, (["a=!ls\n"], (1, 2), None))
189 189 check_find(ipt2.SystemAssign, MULTILINE_MAGIC_ASSIGN, match=False)
190 190
191 191 def test_transform_assign_system():
192 192 check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
193 193 check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
194 194
195 195 def test_find_magic_escape():
196 196 check_find(ipt2.EscapedCommand, MULTILINE_MAGIC)
197 197 check_find(ipt2.EscapedCommand, INDENTED_MAGIC)
198 198 check_find(ipt2.EscapedCommand, MULTILINE_MAGIC_ASSIGN, match=False)
199 199
200 200 def test_transform_magic_escape():
201 201 check_transform(ipt2.EscapedCommand, MULTILINE_MAGIC)
202 202 check_transform(ipt2.EscapedCommand, INDENTED_MAGIC)
203 203 check_transform(ipt2.EscapedCommand, CRLF_MAGIC)
204 204
205 205 def test_find_autocalls():
206 206 for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
207 207 print("Testing %r" % case[0])
208 208 check_find(ipt2.EscapedCommand, case)
209 209
210 210 def test_transform_autocall():
211 211 for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
212 212 print("Testing %r" % case[0])
213 213 check_transform(ipt2.EscapedCommand, case)
214 214
215 215 def test_find_help():
216 216 for case in [SIMPLE_HELP, DETAILED_HELP, MAGIC_HELP, HELP_IN_EXPR]:
217 217 check_find(ipt2.HelpEnd, case)
218 218
219 219 tf = check_find(ipt2.HelpEnd, HELP_CONTINUED_LINE)
220 220 nt.assert_equal(tf.q_line, 1)
221 221 nt.assert_equal(tf.q_col, 3)
222 222
223 223 tf = check_find(ipt2.HelpEnd, HELP_MULTILINE)
224 224 nt.assert_equal(tf.q_line, 1)
225 225 nt.assert_equal(tf.q_col, 8)
226 226
227 227 # ? in a comment does not trigger help
228 228 check_find(ipt2.HelpEnd, (["foo # bar?\n"], None, None), match=False)
229 229 # Nor in a string
230 230 check_find(ipt2.HelpEnd, (["foo = '''bar?\n"], None, None), match=False)
231 231
232 232 def test_transform_help():
233 233 tf = ipt2.HelpEnd((1, 0), (1, 9))
234 234 nt.assert_equal(tf.transform(HELP_IN_EXPR[0]), HELP_IN_EXPR[2])
235 235
236 236 tf = ipt2.HelpEnd((1, 0), (2, 3))
237 237 nt.assert_equal(tf.transform(HELP_CONTINUED_LINE[0]), HELP_CONTINUED_LINE[2])
238 238
239 239 tf = ipt2.HelpEnd((1, 0), (2, 8))
240 240 nt.assert_equal(tf.transform(HELP_MULTILINE[0]), HELP_MULTILINE[2])
241 241
242 242 tf = ipt2.HelpEnd((1, 0), (1, 0))
243 243 nt.assert_equal(tf.transform(HELP_UNICODE[0]), HELP_UNICODE[2])
244 244
245 245 def test_find_assign_op_dedent():
246 246 """
247 247 be careful that empty token like dedent are not counted as parens
248 248 """
249 249 class Tk:
250 250 def __init__(self, s):
251 251 self.string = s
252 252
253 253 nt.assert_equal(_find_assign_op([Tk(s) for s in ('','a','=','b')]), 2)
254 254 nt.assert_equal(_find_assign_op([Tk(s) for s in ('','(', 'a','=','b', ')', '=' ,'5')]), 6)
255 255
256 256 def test_check_complete():
257 257 cc = ipt2.TransformerManager().check_complete
258 258 nt.assert_equal(cc("a = 1"), ('complete', None))
259 259 nt.assert_equal(cc("for a in range(5):"), ('incomplete', 4))
260 260 nt.assert_equal(cc("for a in range(5):\n if a > 0:"), ('incomplete', 8))
261 261 nt.assert_equal(cc("raise = 2"), ('invalid', None))
262 262 nt.assert_equal(cc("a = [1,\n2,"), ('incomplete', 0))
263 nt.assert_equal(cc(")"), ('incomplete', 0))
263 nt.assert_equal(cc("(\n))"), ('incomplete', 0))
264 264 nt.assert_equal(cc("\\\r\n"), ('incomplete', 0))
265 265 nt.assert_equal(cc("a = '''\n hi"), ('incomplete', 3))
266 266 nt.assert_equal(cc("def a():\n x=1\n global x"), ('invalid', None))
267 267 nt.assert_equal(cc("a \\ "), ('invalid', None)) # Nothing allowed after backslash
268 268 nt.assert_equal(cc("1\\\n+2"), ('complete', None))
269 269 nt.assert_equal(cc("exit"), ('complete', None))
270 270
271 271 example = dedent("""
272 272 if True:
273 273 a=1""" )
274 274
275 275 nt.assert_equal(cc(example), ('incomplete', 4))
276 276 nt.assert_equal(cc(example+'\n'), ('complete', None))
277 277 nt.assert_equal(cc(example+'\n '), ('complete', None))
278 278
279 279 # no need to loop on all the letters/numbers.
280 280 short = '12abAB'+string.printable[62:]
281 281 for c in short:
282 282 # test does not raise:
283 283 cc(c)
284 284 for k in short:
285 285 cc(c+k)
286 286
287 287 nt.assert_equal(cc("def f():\n x=0\n \\\n "), ('incomplete', 2))
288 288
289 289 def test_check_complete_II():
290 290 """
291 291 Test that multiple line strings are properly handled.
292 292
293 293 Separate test function for convenience
294 294
295 295 """
296 296 cc = ipt2.TransformerManager().check_complete
297 297 nt.assert_equal(cc('''def foo():\n """'''), ('incomplete', 4))
298 298
299 299
300 300 def test_check_complete_invalidates_sunken_brackets():
301 301 """
302 302 Test that a single line with more closing brackets than the opening ones is
303 303 interpretted as invalid
304 304 """
305 305 cc = ipt2.TransformerManager().check_complete
306 306 nt.assert_equal(cc(")"), ("invalid", None))
307 307 nt.assert_equal(cc("]"), ("invalid", None))
308 308 nt.assert_equal(cc("}"), ("invalid", None))
309 309 nt.assert_equal(cc(")("), ("invalid", None))
310 310 nt.assert_equal(cc("]["), ("invalid", None))
311 311 nt.assert_equal(cc("}{"), ("invalid", None))
312 312 nt.assert_equal(cc("]()("), ("invalid", None))
313 313 nt.assert_equal(cc("())("), ("invalid", None))
314 314 nt.assert_equal(cc(")[]("), ("invalid", None))
315 315 nt.assert_equal(cc("()]("), ("invalid", None))
316 316
317 317
318 318 def test_null_cleanup_transformer():
319 319 manager = ipt2.TransformerManager()
320 320 manager.cleanup_transforms.insert(0, null_cleanup_transformer)
321 321 assert manager.transform_cell("") == ""
322 322
323 323
324 324
325 325
326 326 def test_side_effects_I():
327 327 count = 0
328 328 def counter(lines):
329 329 nonlocal count
330 330 count += 1
331 331 return lines
332 332
333 333 counter.has_side_effects = True
334 334
335 335 manager = ipt2.TransformerManager()
336 336 manager.cleanup_transforms.insert(0, counter)
337 337 assert manager.check_complete("a=1\n") == ('complete', None)
338 338 assert count == 0
339 339
340 340
341 341
342 342
343 343 def test_side_effects_II():
344 344 count = 0
345 345 def counter(lines):
346 346 nonlocal count
347 347 count += 1
348 348 return lines
349 349
350 350 counter.has_side_effects = True
351 351
352 352 manager = ipt2.TransformerManager()
353 353 manager.line_transforms.insert(0, counter)
354 354 assert manager.check_complete("b=1\n") == ('complete', None)
355 355 assert count == 0
General Comments 0
You need to be logged in to leave comments. Login now