##// END OF EJS Templates
Merge pull request #2299 from takluyver/remove-duplicate-input-transforms...
Fernando Perez -
r8219:06a7a574 merge
parent child Browse files
Show More
@@ -391,85 +391,6 b' class PrefilterTransformer(Configurable):'
391 391 self.__class__.__name__, self.priority, self.enabled)
392 392
393 393
394 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
395 r'\s*=\s*!(?P<cmd>.*)')
396
397
398 class AssignSystemTransformer(PrefilterTransformer):
399 """Handle the `files = !ls` syntax."""
400
401 priority = Integer(100, config=True)
402
403 def transform(self, line, continue_prompt):
404 m = _assign_system_re.match(line)
405 if m is not None:
406 cmd = m.group('cmd')
407 lhs = m.group('lhs')
408 expr = "sc =%s" % cmd
409 new_line = '%s = get_ipython().magic(%r)' % (lhs, expr)
410 return new_line
411 return line
412
413
414 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
415 r'\s*=\s*%(?P<cmd>.*)')
416
417 class AssignMagicTransformer(PrefilterTransformer):
418 """Handle the `a = %who` syntax."""
419
420 priority = Integer(200, config=True)
421
422 def transform(self, line, continue_prompt):
423 m = _assign_magic_re.match(line)
424 if m is not None:
425 cmd = m.group('cmd')
426 lhs = m.group('lhs')
427 new_line = '%s = get_ipython().magic(%r)' % (lhs, cmd)
428 return new_line
429 return line
430
431
432 _classic_prompt_re = re.compile(r'(^[ \t]*>>> |^[ \t]*\.\.\. )')
433
434 class PyPromptTransformer(PrefilterTransformer):
435 """Handle inputs that start with '>>> ' syntax."""
436
437 priority = Integer(50, config=True)
438
439 def transform(self, line, continue_prompt):
440
441 if not line or line.isspace() or line.strip() == '...':
442 # This allows us to recognize multiple input prompts separated by
443 # blank lines and pasted in a single chunk, very common when
444 # pasting doctests or long tutorial passages.
445 return ''
446 m = _classic_prompt_re.match(line)
447 if m:
448 return line[len(m.group(0)):]
449 else:
450 return line
451
452
453 _ipy_prompt_re = re.compile(r'(^[ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
454
455 class IPyPromptTransformer(PrefilterTransformer):
456 """Handle inputs that start classic IPython prompt syntax."""
457
458 priority = Integer(50, config=True)
459
460 def transform(self, line, continue_prompt):
461
462 if not line or line.isspace() or line.strip() == '...':
463 # This allows us to recognize multiple input prompts separated by
464 # blank lines and pasted in a single chunk, very common when
465 # pasting doctests or long tutorial passages.
466 return ''
467 m = _ipy_prompt_re.match(line)
468 if m:
469 return line[len(m.group(0)):]
470 else:
471 return line
472
473 394 #-----------------------------------------------------------------------------
474 395 # Prefilter checkers
475 396 #-----------------------------------------------------------------------------
@@ -511,15 +432,6 b' class EmacsChecker(PrefilterChecker):'
511 432 return None
512 433
513 434
514 class ShellEscapeChecker(PrefilterChecker):
515
516 priority = Integer(200, config=True)
517
518 def check(self, line_info):
519 if line_info.line.lstrip().startswith(ESC_SHELL):
520 return self.prefilter_manager.get_handler_by_name('shell')
521
522
523 435 class MacroChecker(PrefilterChecker):
524 436
525 437 priority = Integer(250, config=True)
@@ -546,43 +458,6 b' class IPyAutocallChecker(PrefilterChecker):'
546 458 return None
547 459
548 460
549 class MultiLineMagicChecker(PrefilterChecker):
550
551 priority = Integer(400, config=True)
552
553 def check(self, line_info):
554 "Allow ! and !! in multi-line statements if multi_line_specials is on"
555 # Note that this one of the only places we check the first character of
556 # ifun and *not* the pre_char. Also note that the below test matches
557 # both ! and !!.
558 if line_info.continue_prompt \
559 and self.prefilter_manager.multi_line_specials:
560 if line_info.esc == ESC_MAGIC:
561 return self.prefilter_manager.get_handler_by_name('magic')
562 else:
563 return None
564
565
566 class EscCharsChecker(PrefilterChecker):
567
568 priority = Integer(500, config=True)
569
570 def check(self, line_info):
571 """Check for escape character and return either a handler to handle it,
572 or None if there is no escape char."""
573 if line_info.line[-1] == ESC_HELP \
574 and line_info.esc != ESC_SHELL \
575 and line_info.esc != ESC_SH_CAP:
576 # the ? can be at the end, but *not* for either kind of shell escape,
577 # because a ? can be a vaild final char in a shell cmd
578 return self.prefilter_manager.get_handler_by_name('help')
579 else:
580 if line_info.pre:
581 return None
582 # This returns None like it should if no handler exists
583 return self.prefilter_manager.get_handler_by_esc(line_info.esc)
584
585
586 461 class AssignmentChecker(PrefilterChecker):
587 462
588 463 priority = Integer(600, config=True)
@@ -742,33 +617,6 b' class AliasHandler(PrefilterHandler):'
742 617 return line_out
743 618
744 619
745 class ShellEscapeHandler(PrefilterHandler):
746
747 handler_name = Unicode('shell')
748 esc_strings = List([ESC_SHELL, ESC_SH_CAP])
749
750 def handle(self, line_info):
751 """Execute the line in a shell, empty return value"""
752 magic_handler = self.prefilter_manager.get_handler_by_name('magic')
753
754 line = line_info.line
755 if line.lstrip().startswith(ESC_SH_CAP):
756 # rewrite LineInfo's line, ifun and the_rest to properly hold the
757 # call to %sx and the actual command to be executed, so
758 # handle_magic can work correctly. Note that this works even if
759 # the line is indented, so it handles multi_line_specials
760 # properly.
761 new_rest = line.lstrip()[2:]
762 line_info.line = '%ssx %s' % (ESC_MAGIC, new_rest)
763 line_info.ifun = 'sx'
764 line_info.the_rest = new_rest
765 return magic_handler.handle(line_info)
766 else:
767 cmd = line.lstrip().lstrip(ESC_SHELL)
768 line_out = '%sget_ipython().system(%r)' % (line_info.pre_whitespace, cmd)
769 return line_out
770
771
772 620 class MacroHandler(PrefilterHandler):
773 621 handler_name = Unicode("macro")
774 622
@@ -865,44 +713,6 b' class AutoHandler(PrefilterHandler):'
865 713 return newcmd
866 714
867 715
868 class HelpHandler(PrefilterHandler):
869
870 handler_name = Unicode('help')
871 esc_strings = List([ESC_HELP])
872
873 def handle(self, line_info):
874 """Try to get some help for the object.
875
876 obj? or ?obj -> basic information.
877 obj?? or ??obj -> more details.
878 """
879 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
880 line = line_info.line
881 # We need to make sure that we don't process lines which would be
882 # otherwise valid python, such as "x=1 # what?"
883 try:
884 codeop.compile_command(line)
885 except SyntaxError:
886 # We should only handle as help stuff which is NOT valid syntax
887 if line[0]==ESC_HELP:
888 line = line[1:]
889 elif line[-1]==ESC_HELP:
890 line = line[:-1]
891 if line:
892 #print 'line:<%r>' % line # dbg
893 self.shell.magic('pinfo %s' % line_info.ifun)
894 else:
895 self.shell.show_usage()
896 return '' # Empty string is needed here!
897 except:
898 raise
899 # Pass any other exceptions through to the normal handler
900 return normal_handler.handle(line_info)
901 else:
902 # If the code compiles ok, we should handle it normally
903 return normal_handler.handle(line_info)
904
905
906 716 class EmacsHandler(PrefilterHandler):
907 717
908 718 handler_name = Unicode('emacs')
@@ -924,19 +734,12 b' class EmacsHandler(PrefilterHandler):'
924 734
925 735
926 736 _default_transformers = [
927 AssignSystemTransformer,
928 AssignMagicTransformer,
929 PyPromptTransformer,
930 IPyPromptTransformer,
931 737 ]
932 738
933 739 _default_checkers = [
934 740 EmacsChecker,
935 ShellEscapeChecker,
936 741 MacroChecker,
937 742 IPyAutocallChecker,
938 MultiLineMagicChecker,
939 EscCharsChecker,
940 743 AssignmentChecker,
941 744 AutoMagicChecker,
942 745 AliasChecker,
@@ -947,10 +750,8 b' _default_checkers = ['
947 750 _default_handlers = [
948 751 PrefilterHandler,
949 752 AliasHandler,
950 ShellEscapeHandler,
951 753 MacroHandler,
952 754 MagicHandler,
953 755 AutoHandler,
954 HelpHandler,
955 756 EmacsHandler
956 757 ]
@@ -75,49 +75,8 b' def test_handlers():'
75 75 # line.
76 76 run([(i,py3compat.u_format(o)) for i,o in \
77 77 [('"no change"', '"no change"'), # normal
78 (u"!true", "get_ipython().system({u}'true')"), # shell_escapes
79 (u"!! true", "get_ipython().magic({u}'sx true')"), # shell_escapes + magic
80 (u"!!true", "get_ipython().magic({u}'sx true')"), # shell_escapes + magic
81 (u"%lsmagic", "get_ipython().magic({u}'lsmagic ')"), # magic
82 78 (u"lsmagic", "get_ipython().magic({u}'lsmagic ')"), # magic
83 79 #("a = b # PYTHON-MODE", '_i'), # emacs -- avoids _in cache
84
85 # post-esc-char whitespace goes inside
86 (u"! true", "get_ipython().system({u}' true')"),
87
88 # handle_help
89
90 # These are weak tests -- just looking at what the help handlers
91 # logs, which is not how it really does its work. But it still
92 # lets us check the key paths through the handler.
93
94 ("x=1 # what?", "x=1 # what?"), # no help if valid python
95 ]])
96
97 # multi_line_specials
98 ip.prefilter_manager.multi_line_specials = False
99 # W/ multi_line_specials off, leading ws kills esc chars/autoexpansion
100 run([
101 (u'if 1:\n !true', u'if 1:\n !true'),
102 (u'if 1:\n lsmagic', u'if 1:\n lsmagic'),
103 (u'if 1:\n an_alias', u'if 1:\n an_alias'),
104 ])
105
106 ip.prefilter_manager.multi_line_specials = True
107 # initial indents must be preserved.
108 run([(i,py3compat.u_format(o)) for i,o in \
109 [(u'if 1:\n !true', "if 1:\n get_ipython().system({u}'true')"),
110 (u'if 2:\n lsmagic', "if 2:\n get_ipython().magic({u}'lsmagic ')"),
111 (u'if 1:\n an_alias', "if 1:\n get_ipython().system({u}'true ')"),
112 # Weird one
113 (u'if 1:\n !!true', "if 1:\n get_ipython().magic({u}'sx true')"),
114
115 # Even with m_l_s on, autocall is off even with special chars
116 ('if 1:\n /fun 1 2', 'if 1:\n /fun 1 2'),
117 ('if 1:\n ;fun 1 2', 'if 1:\n ;fun 1 2'),
118 ('if 1:\n ,fun 1 2', 'if 1:\n ,fun 1 2'),
119 ('if 1:\n ?fun 1 2', 'if 1:\n ?fun 1 2'),
120 # What about !!
121 80 ]])
122 81
123 82 # Objects which are instances of IPyAutocall are *always* autocalled
@@ -133,15 +92,9 b' def test_handlers():'
133 92 ('autocallable', 'autocallable()'),
134 93 # Don't add extra brackets (gh-1117)
135 94 ('autocallable()', 'autocallable()'),
136 (",list 1 2 3", 'list("1", "2", "3")'),
137 (";list 1 2 3", 'list("1 2 3")'),
138 ("/len range(1,4)", 'len(range(1,4))'),
139 95 ])
140 96 ip.magic('autocall 1')
141 97 run([
142 (",list 1 2 3", 'list("1", "2", "3")'),
143 (";list 1 2 3", 'list("1 2 3")'),
144 ("/len range(1,4)", 'len(range(1,4))'),
145 98 ('len "abc"', 'len("abc")'),
146 99 ('len "abc";', 'len("abc");'), # ; is special -- moves out of parens
147 100 # Autocall is turned off if first arg is [] and the object
@@ -153,9 +106,6 b' def test_handlers():'
153 106 ])
154 107 ip.magic('autocall 2')
155 108 run([
156 (",list 1 2 3", 'list("1", "2", "3")'),
157 (";list 1 2 3", 'list("1 2 3")'),
158 ("/len range(1,4)", 'len(range(1,4))'),
159 109 ('len "abc"', 'len("abc")'),
160 110 ('len "abc";', 'len("abc");'),
161 111 ('len [1,2]', 'len([1,2])'),
@@ -283,22 +283,18 b' def test_tb_syntaxerror():'
283 283 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
284 284
285 285
286 @py3compat.doctest_refactor_print
287 def doctest_time():
288 """
289 In [10]: %time None
290 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
291 Wall time: 0.00 s
286 def test_time():
287 ip = get_ipython()
292 288
293 In [11]: def f(kmjy):
294 ....: %time print 2*kmjy
289 with tt.AssertPrints("CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s"):
290 ip.run_cell("%time None")
295 291
296 In [12]: f(3)
297 6
298 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
299 Wall time: 0.00 s
300 """
292 ip.run_cell("def f(kmjy):\n"
293 " %time print (2*kmjy)")
301 294
295 with tt.AssertPrints("CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s"):
296 with tt.AssertPrints("hihi", suppress=False):
297 ip.run_cell("f('hi')")
302 298
303 299 def test_doctest_mode():
304 300 "Toggle doctest_mode twice, it should be a no-op and run without error"
@@ -20,17 +20,6 b' def test_prefilter():'
20 20
21 21 # pairs of (raw, expected correct) input
22 22 pairs = [ ('2+2','2+2'),
23 ('>>> 2+2','2+2'),
24 ('>>> # This is a comment\n'
25 '... 2+2',
26 '# This is a comment\n'
27 '2+2'),
28 # Some IPython input
29 ('In [1]: 1', '1'),
30 ('In [2]: for i in range(5):\n'
31 ' ...: print i,',
32 'for i in range(5):\n'
33 ' print i,'),
34 23 ]
35 24
36 25 for raw, correct in pairs:
@@ -47,6 +47,12 b' import nose.core'
47 47 from nose.plugins import doctests, Plugin
48 48 from nose.util import anyp, getpackage, test_address, resolve_name, tolist
49 49
50 # Our own imports
51
52 # We're temporarily using TerminalMagics.cleanup_input() until the functionality
53 # is moved into core.
54 from IPython.frontend.terminal.interactiveshell import TerminalMagics
55
50 56 #-----------------------------------------------------------------------------
51 57 # Module globals and other constants
52 58 #-----------------------------------------------------------------------------
@@ -380,17 +386,7 b' class IPDocTestParser(doctest.DocTestParser):'
380 386
381 387 def ip2py(self,source):
382 388 """Convert input IPython source into valid Python."""
383 out = []
384 newline = out.append
385 #print 'IPSRC:\n',source,'\n###' # dbg
386 # The input source must be first stripped of all bracketing whitespace
387 # and turned into lines, so it looks to the parser like regular user
388 # input
389 for lnum,line in enumerate(source.strip().splitlines()):
390 newline(_ip.prefilter(line,lnum>0))
391 newline('') # ensure a closing newline, needed by doctest
392 #print "PYSRC:", '\n'.join(out) # dbg
393 return '\n'.join(out)
389 return TerminalMagics(_ip).cleanup_input(source)
394 390
395 391 def parse(self, string, name='<string>'):
396 392 """
@@ -11,3 +11,13 b' especially intenting/deindenting blocks that is now bound to Ctrl+] and ctr+['
11 11 * Exception types can now be displayed with a custom traceback, by defining a
12 12 ``_render_traceback_()`` method which returns a list of strings, each
13 13 containing one line of the traceback.
14
15 Backwards incompatible changes
16 ------------------------------
17
18 * Calling :meth:`InteractiveShell.prefilter` will no longer perform static
19 transformations - the processing of escaped commands such as ``%magic`` and
20 ``!system``, and stripping input prompts from code blocks. This functionality
21 was duplicated in :mod:`IPython.core.inputsplitter`, and the latter version
22 was already what IPython relied on. A new API to transform input will be ready
23 before release.
General Comments 0
You need to be logged in to leave comments. Login now