##// END OF EJS Templates
Simplify input transformers...
Thomas Kluyver -
Show More
@@ -79,7 +79,7 b' from IPython.core.inputtransformer import (leading_indent,'
79 cellmagic,
79 cellmagic,
80 assemble_logical_lines,
80 assemble_logical_lines,
81 help_end,
81 help_end,
82 escaped_transformer,
82 escaped_commands,
83 assign_from_magic,
83 assign_from_magic,
84 assign_from_system,
84 assign_from_system,
85 assemble_python_lines,
85 assemble_python_lines,
@@ -526,7 +526,7 b' class IPythonInputSplitter(InputSplitter):'
526 self.logical_line_transforms = logical_line_transforms or \
526 self.logical_line_transforms = logical_line_transforms or \
527 [cellmagic(),
527 [cellmagic(),
528 help_end(),
528 help_end(),
529 escaped_transformer(),
529 escaped_commands(),
530 assign_from_magic(),
530 assign_from_magic(),
531 assign_from_system(),
531 assign_from_system(),
532 ]
532 ]
@@ -61,9 +61,6 b' class InputTransformer(object):'
61 """
61 """
62 pass
62 pass
63
63
64 # Set this to True to allow the transformer to act on lines inside strings.
65 look_in_string = False
66
67 @classmethod
64 @classmethod
68 def wrap(cls, func):
65 def wrap(cls, func):
69 """Can be used by subclasses as a decorator, to return a factory that
66 """Can be used by subclasses as a decorator, to return a factory that
@@ -71,10 +68,7 b' class InputTransformer(object):'
71 """
68 """
72 @functools.wraps(func)
69 @functools.wraps(func)
73 def transformer_factory():
70 def transformer_factory():
74 transformer = cls(func)
71 return cls(func)
75 if getattr(transformer_factory, 'look_in_string', False):
76 transformer.look_in_string = True
77 return transformer
78
72
79 return transformer_factory
73 return transformer_factory
80
74
@@ -215,14 +209,6 b' def _make_help_call(target, esc, lspace, next_input=None):'
215 return '%sget_ipython().set_next_input(%r);get_ipython().magic(%r)' % \
209 return '%sget_ipython().set_next_input(%r);get_ipython().magic(%r)' % \
216 (lspace, next_input, arg)
210 (lspace, next_input, arg)
217
211
218 @CoroutineInputTransformer.wrap
219 def escaped_transformer():
220 """Translate lines beginning with one of IPython's escape characters.
221
222 This is stateful to allow magic commands etc. to be continued over several
223 lines using explicit line continuations (\ at the end of a line).
224 """
225
226 # These define the transformations for the different escape characters.
212 # These define the transformations for the different escape characters.
227 def _tr_system(line_info):
213 def _tr_system(line_info):
228 "Translate lines escaped with: !"
214 "Translate lines escaped with: !"
@@ -272,25 +258,17 b' def escaped_transformer():'
272 ESC_QUOTE2 : _tr_quote2,
258 ESC_QUOTE2 : _tr_quote2,
273 ESC_PAREN : _tr_paren }
259 ESC_PAREN : _tr_paren }
274
260
275 line = ''
261 @StatelessInputTransformer.wrap
276 while True:
262 def escaped_commands(line):
277 line = (yield line)
263 """Transform escaped commands - %magic, !system, ?help + various autocalls.
264 """
278 if not line or line.isspace():
265 if not line or line.isspace():
279 continue
266 return line
280 lineinf = LineInfo(line)
267 lineinf = LineInfo(line)
281 if lineinf.esc not in tr:
268 if lineinf.esc not in tr:
282 continue
269 return line
283
284 parts = []
285 while line is not None:
286 parts.append(line.rstrip('\\'))
287 if not line.endswith('\\'):
288 break
289 line = (yield None)
290
270
291 # Output
271 return tr[lineinf.esc](lineinf)
292 lineinf = LineInfo(' '.join(parts))
293 line = tr[lineinf.esc](lineinf)
294
272
295 _initial_space_re = re.compile(r'\s*')
273 _initial_space_re = re.compile(r'\s*')
296
274
@@ -401,8 +379,6 b' def classic_prompt():'
401 prompt2_re = re.compile(r'^(>>> |^\.\.\. )')
379 prompt2_re = re.compile(r'^(>>> |^\.\.\. )')
402 return _strip_prompts(prompt1_re, prompt2_re)
380 return _strip_prompts(prompt1_re, prompt2_re)
403
381
404 classic_prompt.look_in_string = True
405
406 @CoroutineInputTransformer.wrap
382 @CoroutineInputTransformer.wrap
407 def ipy_prompt():
383 def ipy_prompt():
408 """Strip IPython's In [1]:/...: prompts."""
384 """Strip IPython's In [1]:/...: prompts."""
@@ -410,8 +386,6 b' def ipy_prompt():'
410 prompt2_re = re.compile(r'^(In \[\d+\]: |^\ \ \ \.\.\.+: )')
386 prompt2_re = re.compile(r'^(In \[\d+\]: |^\ \ \ \.\.\.+: )')
411 return _strip_prompts(prompt1_re, prompt2_re)
387 return _strip_prompts(prompt1_re, prompt2_re)
412
388
413 ipy_prompt.look_in_string = True
414
415
389
416 @CoroutineInputTransformer.wrap
390 @CoroutineInputTransformer.wrap
417 def leading_indent():
391 def leading_indent():
@@ -440,48 +414,27 b' def leading_indent():'
440 while line is not None:
414 while line is not None:
441 line = (yield line)
415 line = (yield line)
442
416
443 leading_indent.look_in_string = True
444
445
446 def _special_assignment(assignment_re, template):
447 """Transform assignment from system & magic commands.
448
449 This is stateful so that it can handle magic commands continued on several
450 lines.
451 """
452 line = ''
453 while True:
454 line = (yield line)
455 if not line or line.isspace():
456 continue
457
458 m = assignment_re.match(line)
459 if not m:
460 continue
461
462 parts = []
463 while line is not None:
464 parts.append(line.rstrip('\\'))
465 if not line.endswith('\\'):
466 break
467 line = (yield None)
468
469 # Output
470 whole = assignment_re.match(' '.join(parts))
471 line = template % (whole.group('lhs'), whole.group('cmd'))
472
417
473 @CoroutineInputTransformer.wrap
418 assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
474 def assign_from_system():
475 """Transform assignment from system commands (e.g. files = !ls)"""
476 assignment_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
477 r'\s*=\s*!\s*(?P<cmd>.*)')
419 r'\s*=\s*!\s*(?P<cmd>.*)')
478 template = '%s = get_ipython().getoutput(%r)'
420 assign_system_template = '%s = get_ipython().getoutput(%r)'
479 return _special_assignment(assignment_re, template)
421 @StatelessInputTransformer.wrap
422 def assign_from_system(line):
423 """Transform assignment from system commands (e.g. files = !ls)"""
424 m = assign_system_re.match(line)
425 if m is None:
426 return line
480
427
481 @CoroutineInputTransformer.wrap
428 return assign_system_template % m.group('lhs', 'cmd')
482 def assign_from_magic():
429
483 """Transform assignment from magic commands (e.g. a = %who_ls)"""
430 assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
484 assignment_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
485 r'\s*=\s*%\s*(?P<cmd>.*)')
431 r'\s*=\s*%\s*(?P<cmd>.*)')
486 template = '%s = get_ipython().magic(%r)'
432 assign_magic_template = '%s = get_ipython().magic(%r)'
487 return _special_assignment(assignment_re, template)
433 @StatelessInputTransformer.wrap
434 def assign_from_magic(line):
435 """Transform assignment from magic commands (e.g. a = %who_ls)"""
436 m = assign_magic_re.match(line)
437 if m is None:
438 return line
439
440 return assign_magic_template % m.group('lhs', 'cmd')
@@ -254,14 +254,9 b' syntax_ml = \\'
254
254
255 def test_assign_system():
255 def test_assign_system():
256 tt.check_pairs(transform_and_reset(ipt.assign_from_system), syntax['assign_system'])
256 tt.check_pairs(transform_and_reset(ipt.assign_from_system), syntax['assign_system'])
257 for example in syntax_ml['assign_system']:
258 transform_checker(example, ipt.assign_from_system)
259
257
260 def test_assign_magic():
258 def test_assign_magic():
261 tt.check_pairs(transform_and_reset(ipt.assign_from_magic), syntax['assign_magic'])
259 tt.check_pairs(transform_and_reset(ipt.assign_from_magic), syntax['assign_magic'])
262 for example in syntax_ml['assign_magic']:
263 transform_checker(example, ipt.assign_from_magic)
264
265
260
266 def test_classic_prompt():
261 def test_classic_prompt():
267 tt.check_pairs(transform_and_reset(ipt.classic_prompt), syntax['classic_prompt'])
262 tt.check_pairs(transform_and_reset(ipt.classic_prompt), syntax['classic_prompt'])
@@ -276,39 +271,70 b' def test_ipy_prompt():'
276 for example in syntax_ml['ipy_prompt']:
271 for example in syntax_ml['ipy_prompt']:
277 transform_checker(example, ipt.ipy_prompt)
272 transform_checker(example, ipt.ipy_prompt)
278
273
274 def test_assemble_logical_lines():
275 tests = \
276 [ [(u"a = \\", None),
277 (u"123", u"a = 123"),
278 ],
279 [(u"a = \\", None), # Test resetting when within a multi-line string
280 (u"12 *\\", None),
281 (None, u"a = 12 *"),
282 ],
283 ]
284 for example in tests:
285 transform_checker(example, ipt.assemble_logical_lines)
286
287 def test_assemble_python_lines():
288 tests = \
289 [ [(u"a = '''", None),
290 (u"abc'''", u"a = '''\nabc'''"),
291 ],
292 [(u"a = '''", None), # Test resetting when within a multi-line string
293 (u"def", None),
294 (None, u"a = '''\ndef"),
295 ],
296 [(u"a = [1,", None),
297 (u"2]", u"a = [1,\n2]"),
298 ],
299 [(u"a = [1,", None), # Test resetting when within a multi-line string
300 (u"2,", None),
301 (None, u"a = [1,\n2,"),
302 ],
303 ]
304 for example in tests:
305 transform_checker(example, ipt.assemble_python_lines)
306
307
279 def test_help_end():
308 def test_help_end():
280 tt.check_pairs(transform_and_reset(ipt.help_end), syntax['end_help'])
309 tt.check_pairs(transform_and_reset(ipt.help_end), syntax['end_help'])
281
310
282 def test_escaped_noesc():
311 def test_escaped_noesc():
283 tt.check_pairs(transform_and_reset(ipt.escaped_transformer), syntax['escaped_noesc'])
312 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_noesc'])
284
313
285
314
286 def test_escaped_shell():
315 def test_escaped_shell():
287 tt.check_pairs(transform_and_reset(ipt.escaped_transformer), syntax['escaped_shell'])
316 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_shell'])
288
317
289
318
290 def test_escaped_help():
319 def test_escaped_help():
291 tt.check_pairs(transform_and_reset(ipt.escaped_transformer), syntax['escaped_help'])
320 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_help'])
292
321
293
322
294 def test_escaped_magic():
323 def test_escaped_magic():
295 tt.check_pairs(transform_and_reset(ipt.escaped_transformer), syntax['escaped_magic'])
324 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_magic'])
296
325
297
326
298 def test_escaped_quote():
327 def test_escaped_quote():
299 tt.check_pairs(transform_and_reset(ipt.escaped_transformer), syntax['escaped_quote'])
328 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_quote'])
300
329
301
330
302 def test_escaped_quote2():
331 def test_escaped_quote2():
303 tt.check_pairs(transform_and_reset(ipt.escaped_transformer), syntax['escaped_quote2'])
332 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_quote2'])
304
333
305
334
306 def test_escaped_paren():
335 def test_escaped_paren():
307 tt.check_pairs(transform_and_reset(ipt.escaped_transformer), syntax['escaped_paren'])
336 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_paren'])
308
337
309 def test_escaped_multiline():
310 for example in syntax_ml['escaped']:
311 transform_checker(example, ipt.escaped_transformer)
312
338
313 def test_cellmagic():
339 def test_cellmagic():
314 for example in syntax_ml['cellmagic']:
340 for example in syntax_ml['cellmagic']:
General Comments 0
You need to be logged in to leave comments. Login now