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_ |
|
|
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_ |
|
|
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 |
tr |
|
|
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_ |
|
|
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_ |
|
|
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_ |
|
|
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_ |
|
|
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_ |
|
|
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_ |
|
|
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_ |
|
|
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