##// END OF EJS Templates
Simplify input transformers...
Thomas Kluyver -
Show More
@@ -79,7 +79,7 b' from IPython.core.inputtransformer import (leading_indent,'
79 79 cellmagic,
80 80 assemble_logical_lines,
81 81 help_end,
82 escaped_transformer,
82 escaped_commands,
83 83 assign_from_magic,
84 84 assign_from_system,
85 85 assemble_python_lines,
@@ -526,7 +526,7 b' class IPythonInputSplitter(InputSplitter):'
526 526 self.logical_line_transforms = logical_line_transforms or \
527 527 [cellmagic(),
528 528 help_end(),
529 escaped_transformer(),
529 escaped_commands(),
530 530 assign_from_magic(),
531 531 assign_from_system(),
532 532 ]
@@ -61,9 +61,6 b' class InputTransformer(object):'
61 61 """
62 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 64 @classmethod
68 65 def wrap(cls, func):
69 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 69 @functools.wraps(func)
73 70 def transformer_factory():
74 transformer = cls(func)
75 if getattr(transformer_factory, 'look_in_string', False):
76 transformer.look_in_string = True
77 return transformer
71 return cls(func)
78 72
79 73 return transformer_factory
80 74
@@ -214,83 +208,67 b' def _make_help_call(target, esc, lspace, next_input=None):'
214 208 else:
215 209 return '%sget_ipython().set_next_input(%r);get_ipython().magic(%r)' % \
216 210 (lspace, next_input, arg)
217
218 @CoroutineInputTransformer.wrap
219 def escaped_transformer():
220 """Translate lines beginning with one of IPython's escape characters.
221 211
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).
212 # These define the transformations for the different escape characters.
213 def _tr_system(line_info):
214 "Translate lines escaped with: !"
215 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
216 return '%sget_ipython().system(%r)' % (line_info.pre, cmd)
217
218 def _tr_system2(line_info):
219 "Translate lines escaped with: !!"
220 cmd = line_info.line.lstrip()[2:]
221 return '%sget_ipython().getoutput(%r)' % (line_info.pre, cmd)
222
223 def _tr_help(line_info):
224 "Translate lines escaped with: ?/??"
225 # A naked help line should just fire the intro help screen
226 if not line_info.line[1:]:
227 return 'get_ipython().show_usage()'
228
229 return _make_help_call(line_info.ifun, line_info.esc, line_info.pre)
230
231 def _tr_magic(line_info):
232 "Translate lines escaped with: %"
233 tpl = '%sget_ipython().magic(%r)'
234 cmd = ' '.join([line_info.ifun, line_info.the_rest]).strip()
235 return tpl % (line_info.pre, cmd)
236
237 def _tr_quote(line_info):
238 "Translate lines escaped with: ,"
239 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
240 '", "'.join(line_info.the_rest.split()) )
241
242 def _tr_quote2(line_info):
243 "Translate lines escaped with: ;"
244 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
245 line_info.the_rest)
246
247 def _tr_paren(line_info):
248 "Translate lines escaped with: /"
249 return '%s%s(%s)' % (line_info.pre, line_info.ifun,
250 ", ".join(line_info.the_rest.split()))
251
252 tr = { ESC_SHELL : _tr_system,
253 ESC_SH_CAP : _tr_system2,
254 ESC_HELP : _tr_help,
255 ESC_HELP2 : _tr_help,
256 ESC_MAGIC : _tr_magic,
257 ESC_QUOTE : _tr_quote,
258 ESC_QUOTE2 : _tr_quote2,
259 ESC_PAREN : _tr_paren }
260
261 @StatelessInputTransformer.wrap
262 def escaped_commands(line):
263 """Transform escaped commands - %magic, !system, ?help + various autocalls.
224 264 """
265 if not line or line.isspace():
266 return line
267 lineinf = LineInfo(line)
268 if lineinf.esc not in tr:
269 return line
225 270
226 # These define the transformations for the different escape characters.
227 def _tr_system(line_info):
228 "Translate lines escaped with: !"
229 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
230 return '%sget_ipython().system(%r)' % (line_info.pre, cmd)
231
232 def _tr_system2(line_info):
233 "Translate lines escaped with: !!"
234 cmd = line_info.line.lstrip()[2:]
235 return '%sget_ipython().getoutput(%r)' % (line_info.pre, cmd)
236
237 def _tr_help(line_info):
238 "Translate lines escaped with: ?/??"
239 # A naked help line should just fire the intro help screen
240 if not line_info.line[1:]:
241 return 'get_ipython().show_usage()'
242
243 return _make_help_call(line_info.ifun, line_info.esc, line_info.pre)
244
245 def _tr_magic(line_info):
246 "Translate lines escaped with: %"
247 tpl = '%sget_ipython().magic(%r)'
248 cmd = ' '.join([line_info.ifun, line_info.the_rest]).strip()
249 return tpl % (line_info.pre, cmd)
250
251 def _tr_quote(line_info):
252 "Translate lines escaped with: ,"
253 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
254 '", "'.join(line_info.the_rest.split()) )
255
256 def _tr_quote2(line_info):
257 "Translate lines escaped with: ;"
258 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
259 line_info.the_rest)
260
261 def _tr_paren(line_info):
262 "Translate lines escaped with: /"
263 return '%s%s(%s)' % (line_info.pre, line_info.ifun,
264 ", ".join(line_info.the_rest.split()))
265
266 tr = { ESC_SHELL : _tr_system,
267 ESC_SH_CAP : _tr_system2,
268 ESC_HELP : _tr_help,
269 ESC_HELP2 : _tr_help,
270 ESC_MAGIC : _tr_magic,
271 ESC_QUOTE : _tr_quote,
272 ESC_QUOTE2 : _tr_quote2,
273 ESC_PAREN : _tr_paren }
274
275 line = ''
276 while True:
277 line = (yield line)
278 if not line or line.isspace():
279 continue
280 lineinf = LineInfo(line)
281 if lineinf.esc not in tr:
282 continue
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
291 # Output
292 lineinf = LineInfo(' '.join(parts))
293 line = tr[lineinf.esc](lineinf)
271 return tr[lineinf.esc](lineinf)
294 272
295 273 _initial_space_re = re.compile(r'\s*')
296 274
@@ -401,8 +379,6 b' def classic_prompt():'
401 379 prompt2_re = re.compile(r'^(>>> |^\.\.\. )')
402 380 return _strip_prompts(prompt1_re, prompt2_re)
403 381
404 classic_prompt.look_in_string = True
405
406 382 @CoroutineInputTransformer.wrap
407 383 def ipy_prompt():
408 384 """Strip IPython's In [1]:/...: prompts."""
@@ -410,8 +386,6 b' def ipy_prompt():'
410 386 prompt2_re = re.compile(r'^(In \[\d+\]: |^\ \ \ \.\.\.+: )')
411 387 return _strip_prompts(prompt1_re, prompt2_re)
412 388
413 ipy_prompt.look_in_string = True
414
415 389
416 390 @CoroutineInputTransformer.wrap
417 391 def leading_indent():
@@ -440,48 +414,27 b' def leading_indent():'
440 414 while line is not None:
441 415 line = (yield line)
442 416
443 leading_indent.look_in_string = True
444
445 417
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
473 @CoroutineInputTransformer.wrap
474 def assign_from_system():
418 assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
419 r'\s*=\s*!\s*(?P<cmd>.*)')
420 assign_system_template = '%s = get_ipython().getoutput(%r)'
421 @StatelessInputTransformer.wrap
422 def assign_from_system(line):
475 423 """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>.*)')
478 template = '%s = get_ipython().getoutput(%r)'
479 return _special_assignment(assignment_re, template)
424 m = assign_system_re.match(line)
425 if m is None:
426 return line
427
428 return assign_system_template % m.group('lhs', 'cmd')
480 429
481 @CoroutineInputTransformer.wrap
482 def assign_from_magic():
430 assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
431 r'\s*=\s*%\s*(?P<cmd>.*)')
432 assign_magic_template = '%s = get_ipython().magic(%r)'
433 @StatelessInputTransformer.wrap
434 def assign_from_magic(line):
483 435 """Transform assignment from magic commands (e.g. a = %who_ls)"""
484 assignment_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
485 r'\s*=\s*%\s*(?P<cmd>.*)')
486 template = '%s = get_ipython().magic(%r)'
487 return _special_assignment(assignment_re, template)
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 255 def test_assign_system():
256 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 258 def test_assign_magic():
261 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 261 def test_classic_prompt():
267 262 tt.check_pairs(transform_and_reset(ipt.classic_prompt), syntax['classic_prompt'])
@@ -276,39 +271,70 b' def test_ipy_prompt():'
276 271 for example in syntax_ml['ipy_prompt']:
277 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 308 def test_help_end():
280 309 tt.check_pairs(transform_and_reset(ipt.help_end), syntax['end_help'])
281 310
282 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 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 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 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 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 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 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 339 def test_cellmagic():
314 340 for example in syntax_ml['cellmagic']:
General Comments 0
You need to be logged in to leave comments. Login now