##// END OF EJS Templates
Update inputsplitter to use new input transformers
Thomas Kluyver -
Show More
@@ -69,36 +69,24 b' import ast'
69 import codeop
69 import codeop
70 import re
70 import re
71 import sys
71 import sys
72 import tokenize
73 from StringIO import StringIO
74
72
75 # IPython modules
73 # IPython modules
76 from IPython.core.splitinput import split_user_input, LineInfo
74 from IPython.core.splitinput import split_user_input, LineInfo
77 from IPython.utils.py3compat import cast_unicode
75 from IPython.utils.py3compat import cast_unicode
78
76 from IPython.core.inputtransformer import (leading_indent,
79 #-----------------------------------------------------------------------------
77 classic_prompt,
80 # Globals
78 ipy_prompt,
81 #-----------------------------------------------------------------------------
79 cellmagic,
82
80 help_end,
83 # The escape sequences that define the syntax transformations IPython will
81 escaped_transformer,
84 # apply to user input. These can NOT be just changed here: many regular
82 assign_from_magic,
85 # expressions and other parts of the code may use their hardcoded values, and
83 assign_from_system,
86 # for all intents and purposes they constitute the 'IPython syntax', so they
84 )
87 # should be considered fixed.
85
88
86 # Temporary!
89 ESC_SHELL = '!' # Send line to underlying system shell
87 from IPython.core.inputtransformer import (ESC_SHELL, ESC_SH_CAP, ESC_HELP,
90 ESC_SH_CAP = '!!' # Send line to system shell and capture output
88 ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,
91 ESC_HELP = '?' # Find information about object
89 ESC_QUOTE, ESC_QUOTE2, ESC_PAREN, ESC_SEQUENCES)
92 ESC_HELP2 = '??' # Find extra-detailed information about object
93 ESC_MAGIC = '%' # Call magic function
94 ESC_MAGIC2 = '%%' # Call cell-magic function
95 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
96 ESC_QUOTE2 = ';' # Quote all args as a single string, call
97 ESC_PAREN = '/' # Call first argument with rest of line as arguments
98
99 ESC_SEQUENCES = [ESC_SHELL, ESC_SH_CAP, ESC_HELP ,\
100 ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,\
101 ESC_QUOTE, ESC_QUOTE2, ESC_PAREN ]
102
90
103 #-----------------------------------------------------------------------------
91 #-----------------------------------------------------------------------------
104 # Utilities
92 # Utilities
@@ -205,29 +193,6 b' def remove_comments(src):'
205
193
206 return re.sub('#.*', '', src)
194 return re.sub('#.*', '', src)
207
195
208 def has_comment(src):
209 """Indicate whether an input line has (i.e. ends in, or is) a comment.
210
211 This uses tokenize, so it can distinguish comments from # inside strings.
212
213 Parameters
214 ----------
215 src : string
216 A single line input string.
217
218 Returns
219 -------
220 Boolean: True if source has a comment.
221 """
222 readline = StringIO(src).readline
223 toktypes = set()
224 try:
225 for t in tokenize.generate_tokens(readline):
226 toktypes.add(t[0])
227 except tokenize.TokenError:
228 pass
229 return(tokenize.COMMENT in toktypes)
230
231
196
232 def get_input_encoding():
197 def get_input_encoding():
233 """Return the default standard input encoding.
198 """Return the default standard input encoding.
@@ -524,219 +489,15 b' class InputSplitter(object):'
524 return u''.join(buffer)
489 return u''.join(buffer)
525
490
526
491
527 #-----------------------------------------------------------------------------
528 # Functions and classes for IPython-specific syntactic support
529 #-----------------------------------------------------------------------------
530
531 # The escaped translators ALL receive a line where their own escape has been
532 # stripped. Only '?' is valid at the end of the line, all others can only be
533 # placed at the start.
534
535 # Transformations of the special syntaxes that don't rely on an explicit escape
536 # character but instead on patterns on the input line
537
538 # The core transformations are implemented as standalone functions that can be
539 # tested and validated in isolation. Each of these uses a regexp, we
540 # pre-compile these and keep them close to each function definition for clarity
541
542 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
543 r'\s*=\s*!\s*(?P<cmd>.*)')
544
545 def transform_assign_system(line):
546 """Handle the `files = !ls` syntax."""
547 m = _assign_system_re.match(line)
548 if m is not None:
549 cmd = m.group('cmd')
550 lhs = m.group('lhs')
551 new_line = '%s = get_ipython().getoutput(%r)' % (lhs, cmd)
552 return new_line
553 return line
554
555
556 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
557 r'\s*=\s*%\s*(?P<cmd>.*)')
558
559 def transform_assign_magic(line):
560 """Handle the `a = %who` syntax."""
561 m = _assign_magic_re.match(line)
562 if m is not None:
563 cmd = m.group('cmd')
564 lhs = m.group('lhs')
565 new_line = '%s = get_ipython().magic(%r)' % (lhs, cmd)
566 return new_line
567 return line
568
569
570 _classic_prompt_re = re.compile(r'^([ \t]*>>> |^[ \t]*\.\.\. )')
571
572 def transform_classic_prompt(line):
573 """Handle inputs that start with '>>> ' syntax."""
574
575 if not line or line.isspace():
576 return line
577 m = _classic_prompt_re.match(line)
578 if m:
579 return line[len(m.group(0)):]
580 else:
581 return line
582
583
584 _ipy_prompt_re = re.compile(r'^([ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
585
586 def transform_ipy_prompt(line):
587 """Handle inputs that start classic IPython prompt syntax."""
588
589 if not line or line.isspace():
590 return line
591 #print 'LINE: %r' % line # dbg
592 m = _ipy_prompt_re.match(line)
593 if m:
594 #print 'MATCH! %r -> %r' % (line, line[len(m.group(0)):]) # dbg
595 return line[len(m.group(0)):]
596 else:
597 return line
598
599
600 def _make_help_call(target, esc, lspace, next_input=None):
601 """Prepares a pinfo(2)/psearch call from a target name and the escape
602 (i.e. ? or ??)"""
603 method = 'pinfo2' if esc == '??' \
604 else 'psearch' if '*' in target \
605 else 'pinfo'
606 arg = " ".join([method, target])
607 if next_input is None:
608 return '%sget_ipython().magic(%r)' % (lspace, arg)
609 else:
610 return '%sget_ipython().set_next_input(%r);get_ipython().magic(%r)' % \
611 (lspace, next_input, arg)
612
613
614 _initial_space_re = re.compile(r'\s*')
615
616 _help_end_re = re.compile(r"""(%{0,2}
617 [a-zA-Z_*][\w*]* # Variable name
618 (\.[a-zA-Z_*][\w*]*)* # .etc.etc
619 )
620 (\?\??)$ # ? or ??""",
621 re.VERBOSE)
622
623
624 def transform_help_end(line):
625 """Translate lines with ?/?? at the end"""
626 m = _help_end_re.search(line)
627 if m is None or has_comment(line):
628 return line
629 target = m.group(1)
630 esc = m.group(3)
631 lspace = _initial_space_re.match(line).group(0)
632
633 # If we're mid-command, put it back on the next prompt for the user.
634 next_input = line.rstrip('?') if line.strip() != m.group(0) else None
635
636 return _make_help_call(target, esc, lspace, next_input)
637
638
639 class EscapedTransformer(object):
640 """Class to transform lines that are explicitly escaped out."""
641
642 def __init__(self):
643 tr = { ESC_SHELL : self._tr_system,
644 ESC_SH_CAP : self._tr_system2,
645 ESC_HELP : self._tr_help,
646 ESC_HELP2 : self._tr_help,
647 ESC_MAGIC : self._tr_magic,
648 ESC_QUOTE : self._tr_quote,
649 ESC_QUOTE2 : self._tr_quote2,
650 ESC_PAREN : self._tr_paren }
651 self.tr = tr
652
653 # Support for syntax transformations that use explicit escapes typed by the
654 # user at the beginning of a line
655 @staticmethod
656 def _tr_system(line_info):
657 "Translate lines escaped with: !"
658 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
659 return '%sget_ipython().system(%r)' % (line_info.pre, cmd)
660
661 @staticmethod
662 def _tr_system2(line_info):
663 "Translate lines escaped with: !!"
664 cmd = line_info.line.lstrip()[2:]
665 return '%sget_ipython().getoutput(%r)' % (line_info.pre, cmd)
666
667 @staticmethod
668 def _tr_help(line_info):
669 "Translate lines escaped with: ?/??"
670 # A naked help line should just fire the intro help screen
671 if not line_info.line[1:]:
672 return 'get_ipython().show_usage()'
673
674 return _make_help_call(line_info.ifun, line_info.esc, line_info.pre)
675
676 @staticmethod
677 def _tr_magic(line_info):
678 "Translate lines escaped with: %"
679 tpl = '%sget_ipython().magic(%r)'
680 cmd = ' '.join([line_info.ifun, line_info.the_rest]).strip()
681 return tpl % (line_info.pre, cmd)
682
683 @staticmethod
684 def _tr_quote(line_info):
685 "Translate lines escaped with: ,"
686 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
687 '", "'.join(line_info.the_rest.split()) )
688
689 @staticmethod
690 def _tr_quote2(line_info):
691 "Translate lines escaped with: ;"
692 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
693 line_info.the_rest)
694
695 @staticmethod
696 def _tr_paren(line_info):
697 "Translate lines escaped with: /"
698 return '%s%s(%s)' % (line_info.pre, line_info.ifun,
699 ", ".join(line_info.the_rest.split()))
700
701 def __call__(self, line):
702 """Class to transform lines that are explicitly escaped out.
703
704 This calls the above _tr_* static methods for the actual line
705 translations."""
706
707 # Empty lines just get returned unmodified
708 if not line or line.isspace():
709 return line
710
711 # Get line endpoints, where the escapes can be
712 line_info = LineInfo(line)
713
714 if not line_info.esc in self.tr:
715 # If we don't recognize the escape, don't modify the line
716 return line
717
718 return self.tr[line_info.esc](line_info)
719
720
721 # A function-looking object to be used by the rest of the code. The purpose of
722 # the class in this case is to organize related functionality, more than to
723 # manage state.
724 transform_escaped = EscapedTransformer()
725
726
727 class IPythonInputSplitter(InputSplitter):
492 class IPythonInputSplitter(InputSplitter):
728 """An input splitter that recognizes all of IPython's special syntax."""
493 """An input splitter that recognizes all of IPython's special syntax."""
729
494
730 # String with raw, untransformed input.
495 # String with raw, untransformed input.
731 source_raw = ''
496 source_raw = ''
732
497
733 # Flag to track when we're in the middle of processing a cell magic, since
498 # Flag to track when a transformer has stored input that it hasn't given
734 # the logic has to change. In that case, we apply no transformations at
499 # back yet.
735 # all.
500 transformer_accumulating = False
736 processing_cell_magic = False
737
738 # Storage for all blocks of input that make up a cell magic
739 cell_magic_parts = []
740
501
741 # Private attributes
502 # Private attributes
742
503
@@ -747,14 +508,22 b' class IPythonInputSplitter(InputSplitter):'
747 super(IPythonInputSplitter, self).__init__(input_mode)
508 super(IPythonInputSplitter, self).__init__(input_mode)
748 self._buffer_raw = []
509 self._buffer_raw = []
749 self._validate = True
510 self._validate = True
511 self.transforms = [leading_indent,
512 classic_prompt,
513 ipy_prompt,
514 cellmagic,
515 help_end,
516 escaped_transformer,
517 assign_from_magic,
518 assign_from_system,
519 ]
750
520
751 def reset(self):
521 def reset(self):
752 """Reset the input buffer and associated state."""
522 """Reset the input buffer and associated state."""
753 super(IPythonInputSplitter, self).reset()
523 super(IPythonInputSplitter, self).reset()
754 self._buffer_raw[:] = []
524 self._buffer_raw[:] = []
755 self.source_raw = ''
525 self.source_raw = ''
756 self.cell_magic_parts = []
526 self.transformer_accumulating = False
757 self.processing_cell_magic = False
758
527
759 def source_raw_reset(self):
528 def source_raw_reset(self):
760 """Return input and raw source and perform a full reset.
529 """Return input and raw source and perform a full reset.
@@ -765,56 +534,11 b' class IPythonInputSplitter(InputSplitter):'
765 return out, out_r
534 return out, out_r
766
535
767 def push_accepts_more(self):
536 def push_accepts_more(self):
768 if self.processing_cell_magic:
537 if self.transformer_accumulating:
769 return not self._is_complete
538 return True
770 else:
539 else:
771 return super(IPythonInputSplitter, self).push_accepts_more()
540 return super(IPythonInputSplitter, self).push_accepts_more()
772
541
773 def _handle_cell_magic(self, lines):
774 """Process lines when they start with %%, which marks cell magics.
775 """
776 self.processing_cell_magic = True
777 first, _, body = lines.partition('\n')
778 magic_name, _, line = first.partition(' ')
779 magic_name = magic_name.lstrip(ESC_MAGIC)
780 # We store the body of the cell and create a call to a method that
781 # will use this stored value. This is ugly, but it's a first cut to
782 # get it all working, as right now changing the return API of our
783 # methods would require major refactoring.
784 self.cell_magic_parts = [body]
785 tpl = 'get_ipython()._run_cached_cell_magic(%r, %r)'
786 tlines = tpl % (magic_name, line)
787 self._store(tlines)
788 self._store(lines, self._buffer_raw, 'source_raw')
789 # We can actually choose whether to allow for single blank lines here
790 # during input for clients that use cell mode to decide when to stop
791 # pushing input (currently only the Qt console).
792 # My first implementation did that, and then I realized it wasn't
793 # consistent with the terminal behavior, so I've reverted it to one
794 # line. But I'm leaving it here so we can easily test both behaviors,
795 # I kind of liked having full blank lines allowed in the cell magics...
796 #self._is_complete = last_two_blanks(lines)
797 self._is_complete = last_blank(lines)
798 return self._is_complete
799
800 def _line_mode_cell_append(self, lines):
801 """Append new content for a cell magic in line mode.
802 """
803 # Only store the raw input. Lines beyond the first one are only only
804 # stored for history purposes; for execution the caller will grab the
805 # magic pieces from cell_magic_parts and will assemble the cell body
806 self._store(lines, self._buffer_raw, 'source_raw')
807 self.cell_magic_parts.append(lines)
808 # Find out if the last stored block has a whitespace line as its
809 # last line and also this line is whitespace, case in which we're
810 # done (two contiguous blank lines signal termination). Note that
811 # the storage logic *enforces* that every stored block is
812 # newline-terminated, so we grab everything but the last character
813 # so we can have the body of the block alone.
814 last_block = self.cell_magic_parts[-1]
815 self._is_complete = last_blank(last_block) and lines.isspace()
816 return self._is_complete
817
818 def transform_cell(self, cell):
542 def transform_cell(self, cell):
819 """Process and translate a cell of input.
543 """Process and translate a cell of input.
820 """
544 """
@@ -851,24 +575,10 b' class IPythonInputSplitter(InputSplitter):'
851 # We must ensure all input is pure unicode
575 # We must ensure all input is pure unicode
852 lines = cast_unicode(lines, self.encoding)
576 lines = cast_unicode(lines, self.encoding)
853
577
854 # If the entire input block is a cell magic, return after handling it
855 # as the rest of the transformation logic should be skipped.
856 if lines.startswith('%%') and not \
857 (len(lines.splitlines()) == 1 and lines.strip().endswith('?')):
858 return self._handle_cell_magic(lines)
859
860 # In line mode, a cell magic can arrive in separate pieces
861 if self.input_mode == 'line' and self.processing_cell_magic:
862 return self._line_mode_cell_append(lines)
863
864 # The rest of the processing is for 'normal' content, i.e. IPython
578 # The rest of the processing is for 'normal' content, i.e. IPython
865 # source that we process through our transformations pipeline.
579 # source that we process through our transformations pipeline.
866 lines_list = lines.splitlines()
580 lines_list = lines.splitlines()
867
581
868 transforms = [transform_ipy_prompt, transform_classic_prompt,
869 transform_help_end, transform_escaped,
870 transform_assign_system, transform_assign_magic]
871
872 # Transform logic
582 # Transform logic
873 #
583 #
874 # We only apply the line transformers to the input if we have either no
584 # We only apply the line transformers to the input if we have either no
@@ -901,16 +611,24 b' class IPythonInputSplitter(InputSplitter):'
901 self._store(lines, self._buffer_raw, 'source_raw')
611 self._store(lines, self._buffer_raw, 'source_raw')
902
612
903 try:
613 try:
904 push = super(IPythonInputSplitter, self).push
905 buf = self._buffer
906 for line in lines_list:
614 for line in lines_list:
907 if self._is_complete or not buf or \
615 out = self.push_line(line)
908 (buf and buf[-1].rstrip().endswith((':', ','))):
909 for f in transforms:
910 line = f(line)
911
912 out = push(line)
913 finally:
616 finally:
914 if changed_input_mode:
617 if changed_input_mode:
915 self.input_mode = saved_input_mode
618 self.input_mode = saved_input_mode
619
916 return out
620 return out
621
622 def push_line(self, line):
623 buf = self._buffer
624 not_in_string = self._is_complete or not buf or \
625 (buf and buf[-1].rstrip().endswith((':', ',')))
626 for transformer in self.transforms:
627 if not_in_string or transformer.look_in_string:
628 line = transformer.push(line)
629 if line is None:
630 self.transformer_accumulating = True
631 return False
632
633 self.transformer_accumulating = False
634 return super(IPythonInputSplitter, self).push(line)
@@ -1,11 +1,35 b''
1 import abc
1 import abc
2 import re
2 import re
3 from StringIO import StringIO
4 import tokenize
3
5
4 from IPython.core.splitinput import split_user_input, LineInfo
6 from IPython.core.splitinput import split_user_input, LineInfo
5 from IPython.core.inputsplitter import (ESC_SHELL, ESC_SH_CAP, ESC_HELP,
7
6 ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,
8 #-----------------------------------------------------------------------------
7 ESC_QUOTE, ESC_QUOTE2, ESC_PAREN)
9 # Globals
8 from IPython.core.inputsplitter import EscapedTransformer, _make_help_call, has_comment
10 #-----------------------------------------------------------------------------
11
12 # The escape sequences that define the syntax transformations IPython will
13 # apply to user input. These can NOT be just changed here: many regular
14 # expressions and other parts of the code may use their hardcoded values, and
15 # for all intents and purposes they constitute the 'IPython syntax', so they
16 # should be considered fixed.
17
18 ESC_SHELL = '!' # Send line to underlying system shell
19 ESC_SH_CAP = '!!' # Send line to system shell and capture output
20 ESC_HELP = '?' # Find information about object
21 ESC_HELP2 = '??' # Find extra-detailed information about object
22 ESC_MAGIC = '%' # Call magic function
23 ESC_MAGIC2 = '%%' # Call cell-magic function
24 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
25 ESC_QUOTE2 = ';' # Quote all args as a single string, call
26 ESC_PAREN = '/' # Call first argument with rest of line as arguments
27
28 ESC_SEQUENCES = [ESC_SHELL, ESC_SH_CAP, ESC_HELP ,\
29 ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,\
30 ESC_QUOTE, ESC_QUOTE2, ESC_PAREN ]
31
32
9
33
10 class InputTransformer(object):
34 class InputTransformer(object):
11 __metaclass__ = abc.ABCMeta
35 __metaclass__ = abc.ABCMeta
@@ -44,16 +68,81 b' class CoroutineInputTransformer(InputTransformer):'
44 def reset(self):
68 def reset(self):
45 self.coro.send(None)
69 self.coro.send(None)
46
70
71
72 # Utilities
73 def _make_help_call(target, esc, lspace, next_input=None):
74 """Prepares a pinfo(2)/psearch call from a target name and the escape
75 (i.e. ? or ??)"""
76 method = 'pinfo2' if esc == '??' \
77 else 'psearch' if '*' in target \
78 else 'pinfo'
79 arg = " ".join([method, target])
80 if next_input is None:
81 return '%sget_ipython().magic(%r)' % (lspace, arg)
82 else:
83 return '%sget_ipython().set_next_input(%r);get_ipython().magic(%r)' % \
84 (lspace, next_input, arg)
85
47 @CoroutineInputTransformer
86 @CoroutineInputTransformer
48 def escaped_transformer():
87 def escaped_transformer():
49 et = EscapedTransformer()
88 """Translate lines beginning with one of IPython's escape characters."""
89
90 # These define the transformations for the different escape characters.
91 def _tr_system(line_info):
92 "Translate lines escaped with: !"
93 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
94 return '%sget_ipython().system(%r)' % (line_info.pre, cmd)
95
96 def _tr_system2(line_info):
97 "Translate lines escaped with: !!"
98 cmd = line_info.line.lstrip()[2:]
99 return '%sget_ipython().getoutput(%r)' % (line_info.pre, cmd)
100
101 def _tr_help(line_info):
102 "Translate lines escaped with: ?/??"
103 # A naked help line should just fire the intro help screen
104 if not line_info.line[1:]:
105 return 'get_ipython().show_usage()'
106
107 return _make_help_call(line_info.ifun, line_info.esc, line_info.pre)
108
109 def _tr_magic(line_info):
110 "Translate lines escaped with: %"
111 tpl = '%sget_ipython().magic(%r)'
112 cmd = ' '.join([line_info.ifun, line_info.the_rest]).strip()
113 return tpl % (line_info.pre, cmd)
114
115 def _tr_quote(line_info):
116 "Translate lines escaped with: ,"
117 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
118 '", "'.join(line_info.the_rest.split()) )
119
120 def _tr_quote2(line_info):
121 "Translate lines escaped with: ;"
122 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
123 line_info.the_rest)
124
125 def _tr_paren(line_info):
126 "Translate lines escaped with: /"
127 return '%s%s(%s)' % (line_info.pre, line_info.ifun,
128 ", ".join(line_info.the_rest.split()))
129
130 tr = { ESC_SHELL : _tr_system,
131 ESC_SH_CAP : _tr_system2,
132 ESC_HELP : _tr_help,
133 ESC_HELP2 : _tr_help,
134 ESC_MAGIC : _tr_magic,
135 ESC_QUOTE : _tr_quote,
136 ESC_QUOTE2 : _tr_quote2,
137 ESC_PAREN : _tr_paren }
138
50 line = ''
139 line = ''
51 while True:
140 while True:
52 line = (yield line)
141 line = (yield line)
53 if not line or line.isspace():
142 if not line or line.isspace():
54 continue
143 continue
55 lineinf = LineInfo(line)
144 lineinf = LineInfo(line)
56 if lineinf.esc not in et.tr:
145 if lineinf.esc not in tr:
57 continue
146 continue
58
147
59 parts = []
148 parts = []
@@ -65,7 +154,7 b' def escaped_transformer():'
65
154
66 # Output
155 # Output
67 lineinf = LineInfo(' '.join(parts))
156 lineinf = LineInfo(' '.join(parts))
68 line = et.tr[lineinf.esc](lineinf)
157 line = tr[lineinf.esc](lineinf)
69
158
70 _initial_space_re = re.compile(r'\s*')
159 _initial_space_re = re.compile(r'\s*')
71
160
@@ -76,8 +165,31 b' _help_end_re = re.compile(r"""(%{0,2}'
76 (\?\??)$ # ? or ??""",
165 (\?\??)$ # ? or ??""",
77 re.VERBOSE)
166 re.VERBOSE)
78
167
168 def has_comment(src):
169 """Indicate whether an input line has (i.e. ends in, or is) a comment.
170
171 This uses tokenize, so it can distinguish comments from # inside strings.
172
173 Parameters
174 ----------
175 src : string
176 A single line input string.
177
178 Returns
179 -------
180 Boolean: True if source has a comment.
181 """
182 readline = StringIO(src).readline
183 toktypes = set()
184 try:
185 for t in tokenize.generate_tokens(readline):
186 toktypes.add(t[0])
187 except tokenize.TokenError:
188 pass
189 return(tokenize.COMMENT in toktypes)
190
79 @StatelessInputTransformer
191 @StatelessInputTransformer
80 def transform_help_end(line):
192 def help_end(line):
81 """Translate lines with ?/?? at the end"""
193 """Translate lines with ?/?? at the end"""
82 m = _help_end_re.search(line)
194 m = _help_end_re.search(line)
83 if m is None or has_comment(line):
195 if m is None or has_comment(line):
@@ -2591,13 +2591,6 b' class InteractiveShell(SingletonConfigurable):'
2591
2591
2592 self.input_splitter.push(raw_cell)
2592 self.input_splitter.push(raw_cell)
2593
2593
2594 # Check for cell magics, which leave state behind. This interface is
2595 # ugly, we need to do something cleaner later... Now the logic is
2596 # simply that the input_splitter remembers if there was a cell magic,
2597 # and in that case we grab the cell body.
2598 if self.input_splitter.cell_magic_parts:
2599 self._current_cell_magic_body = \
2600 ''.join(self.input_splitter.cell_magic_parts)
2601 cell = self.input_splitter.source_reset()
2594 cell = self.input_splitter.source_reset()
2602
2595
2603 # Our own compiler remembers the __future__ environment. If we want to
2596 # Our own compiler remembers the __future__ environment. If we want to
@@ -37,7 +37,7 b' def test_transform_escaped():'
37 tt.check_pairs(wrap_transform(inputtransformer.escaped_transformer), esctransform_tests)
37 tt.check_pairs(wrap_transform(inputtransformer.escaped_transformer), esctransform_tests)
38
38
39 def endhelp_test():
39 def endhelp_test():
40 tt.check_pairs(inputtransformer.transform_help_end.push, syntax['end_help'])
40 tt.check_pairs(inputtransformer.help_end.push, syntax['end_help'])
41
41
42 classic_prompt_tests = [
42 classic_prompt_tests = [
43 (['>>> a=1'], ['a=1']),
43 (['>>> a=1'], ['a=1']),
General Comments 0
You need to be logged in to leave comments. Login now