##// END OF EJS Templates
First working version of cell magics in inputsplitter in line mode....
Fernando Perez -
Show More
@@ -142,6 +142,21 b' def num_ini_spaces(s):'
142 142 return 0
143 143
144 144
145 def last_blank(src):
146 """Determine if the input source ends in a blank.
147
148 A blank is either a newline or a line consisting of whitespace.
149
150 Parameters
151 ----------
152 src : string
153 A single or multiline string.
154 """
155 if not src: return False
156 ll = src.splitlines()[-1]
157 return (ll == '') or ll.isspace()
158
159
145 160 def remove_comments(src):
146 161 """Remove all comments from input source.
147 162
@@ -685,23 +700,27 b' class IPythonInputSplitter(InputSplitter):'
685 700 # String with raw, untransformed input.
686 701 source_raw = ''
687 702
688 cell_magic_body = None
703 cell_magic_parts = []
704
705 cell_magic_mode = False
689 706
690 707 # Private attributes
691
708
692 709 # List with lines of raw input accumulated so far.
693 710 _buffer_raw = None
694 711
695 712 def __init__(self, input_mode=None):
696 713 super(IPythonInputSplitter, self).__init__(input_mode)
697 714 self._buffer_raw = []
715 self._validate = True
698 716
699 717 def reset(self):
700 718 """Reset the input buffer and associated state."""
701 719 super(IPythonInputSplitter, self).reset()
702 720 self._buffer_raw[:] = []
703 721 self.source_raw = ''
704 self.cell_magic_body = None
722 self.cell_magic_parts = []
723 self.cell_magic_mode = False
705 724
706 725 def source_raw_reset(self):
707 726 """Return input and raw source and perform a full reset.
@@ -711,6 +730,96 b' class IPythonInputSplitter(InputSplitter):'
711 730 self.reset()
712 731 return out, out_r
713 732
733 def push_accepts_more(self):
734 if self.cell_magic_mode:
735 return not self._is_complete
736 else:
737 return super(IPythonInputSplitter, self).push_accepts_more()
738
739 def _push_line_mode(self, lines):
740 """Push in line mode.
741
742 This means that we only get individual 'lines' with each call, though
743 in practice each input may be multiline. But this is in contrast to
744 cell mode, which feeds the entirety of the cell from the start with
745 each call.
746 """
747 # cell magic support
748 #print('#'*10)
749 #print(lines+'\n---') # dbg
750 #print (repr(lines)+'\n+++')
751 #print('raw', self._buffer_raw, 'validate', self.cell_magic_mode)
752 # Only trigger this block if we're at a 'fresh' pumping start.
753 if lines.startswith('%%') and (not self.cell_magic_mode) and \
754 not self._buffer_raw:
755 # Cell magics bypass all further transformations
756 self.cell_magic_mode = True
757 first, _, body = lines.partition('\n')
758 magic_name, _, line = first.partition(' ')
759 magic_name = magic_name.lstrip(ESC_MAGIC)
760 # We store the body of the cell and create a call to a method that
761 # will use this stored value. This is ugly, but it's a first cut to
762 # get it all working, as right now changing the return API of our
763 # methods would require major refactoring.
764 self.cell_magic_parts = [body]
765 tpl = 'get_ipython()._cell_magic(%r, %r)'
766 tlines = tpl % (magic_name, line)
767 self._store(tlines)
768 self._store(lines, self._buffer_raw, 'source_raw')
769 self._is_complete = False
770 return False
771
772 if self.cell_magic_mode:
773 # Find out if the last stored block has a whitespace line as its
774 # last line and also this line is whitespace, case in which we're
775 # done (two contiguous blank lines signal termination). Note that
776 # the storage logic *enforces* that every stored block is
777 # newline-terminated, so we grab everything but the last character
778 # so we can have the body of the block alone.
779 last_block = self.cell_magic_parts[-1]
780 self._is_complete = last_blank(last_block) and lines.isspace()
781 # Only store the raw input. For lines beyond the first one, we
782 # only store them for history purposes, and for execution we want
783 # the caller to only receive the _cell_magic() call.
784 self._store(lines, self._buffer_raw, 'source_raw')
785 self.cell_magic_parts.append(lines)
786 return self._is_complete
787
788 lines_list = lines.splitlines()
789
790 transforms = [transform_ipy_prompt, transform_classic_prompt,
791 transform_help_end, transform_escaped,
792 transform_assign_system, transform_assign_magic]
793
794 # Transform logic
795 #
796 # We only apply the line transformers to the input if we have either no
797 # input yet, or complete input, or if the last line of the buffer ends
798 # with ':' (opening an indented block). This prevents the accidental
799 # transformation of escapes inside multiline expressions like
800 # triple-quoted strings or parenthesized expressions.
801 #
802 # The last heuristic, while ugly, ensures that the first line of an
803 # indented block is correctly transformed.
804 #
805 # FIXME: try to find a cleaner approach for this last bit.
806
807 # Store raw source before applying any transformations to it. Note
808 # that this must be done *after* the reset() call that would otherwise
809 # flush the buffer.
810 self._store(lines, self._buffer_raw, 'source_raw')
811
812 push = super(IPythonInputSplitter, self).push
813 buf = self._buffer
814 for line in lines_list:
815 if self._is_complete or not buf or \
816 (buf and buf[-1].rstrip().endswith((':', ','))):
817 for f in transforms:
818 line = f(line)
819
820 out = push(line)
821 return out
822
714 823 def push(self, lines):
715 824 """Push one or more lines of IPython input.
716 825
@@ -734,25 +843,19 b' class IPythonInputSplitter(InputSplitter):'
734 843 this value is also stored as a private attribute (_is_complete), so it
735 844 can be queried at any time.
736 845 """
846 print('mode:', self.input_mode)
847 print('lines:',repr(lines))
737 848 if not lines:
738 849 return super(IPythonInputSplitter, self).push(lines)
739 850
740 851 # We must ensure all input is pure unicode
741 852 lines = cast_unicode(lines, self.encoding)
742 853
743 # cell magic support
744 #print('IM:', self.input_mode,'\n'+lines); print('---') # dbg
745 #if self.input_mode == 'cell' and lines.startswith('%%'):
746 if lines.startswith('%%'):
747 # Cell magics bypass all further transformations
748 self.reset()
749 self._is_complete = is_complete = True
750 first, _, body = lines.partition('\n')
751 magic_name, _, line = first.partition(' ')
752 magic_name = magic_name.lstrip(ESC_MAGIC)
753 self.cell_magic_body = body
754 tpl = 'get_ipython()._cell_magic(%r, %r)'
755 lines = tpl % (magic_name, line)
854 if self.input_mode == 'line':
855 return self._push_line_mode(lines)
856
857 ## else:
858 ## return self._push_cell_mode(lines)
756 859
757 860 lines_list = lines.splitlines()
758 861
@@ -796,8 +899,7 b' class IPythonInputSplitter(InputSplitter):'
796 899 buf = self._buffer
797 900 for line in lines_list:
798 901 if self._is_complete or not buf or \
799 (buf and (buf[-1].rstrip().endswith(':') or
800 buf[-1].rstrip().endswith(',')) ):
902 (buf and buf[-1].rstrip().endswith((':', ','))):
801 903 for f in transforms:
802 904 line = f(line)
803 905
@@ -2027,7 +2027,12 b' class InteractiveShell(SingletonConfigurable):'
2027 2027 """
2028 2028 fn = self.find_line_magic(magic_name)
2029 2029 if fn is None:
2030 error("Line magic function `%%%s` not found." % magic_name)
2030 em = "Line magic function `%%%s` not found" % magic_name
2031 cm = self.find_cell_magic(magic_name)
2032 if cm is not None:
2033 em += (' (Did you by chance mean the cell magic `%%%%%s` '
2034 'instead?).')
2035 error()
2031 2036 else:
2032 2037 # Note: this is the distance in the stack to the user's frame.
2033 2038 # This will need to be updated if the internal calling logic gets
@@ -2469,13 +2474,9 b' class InteractiveShell(SingletonConfigurable):'
2469 2474 self.showtraceback()
2470 2475 warn('Unknown failure executing module: <%s>' % mod_name)
2471 2476
2472 def call_cell_magic(self, raw_cell, store_history=False):
2473 line, _, cell = raw_cell.partition(os.linesep)
2474 magic_name, _, line = line.partition(' ')
2475 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
2476 return self.cell_magic(magic_name, line, cell)
2477
2478 2477 def _cell_magic(self, magic_name, line):
2478 """Special method to call a cell magic with the data stored in self.
2479 """
2479 2480 cell = self._current_cell_magic_body
2480 2481 self._current_cell_magic_body = None
2481 2482 return self.cell_magic(magic_name, line, cell)
@@ -2507,8 +2508,9 b' class InteractiveShell(SingletonConfigurable):'
2507 2508 # ugly, we need to do something cleaner later... Now the logic is
2508 2509 # simply that the input_splitter remembers if there was a cell magic,
2509 2510 # and in that case we grab the cell body.
2510 if self.input_splitter.cell_magic_body is not None:
2511 self._current_cell_magic_body = self.input_splitter.cell_magic_body
2511 if self.input_splitter.cell_magic_parts:
2512 self._current_cell_magic_body = \
2513 ''.join(self.input_splitter.cell_magic_parts)
2512 2514 cell = self.input_splitter.source_reset()
2513 2515
2514 2516 with self.builtin_trap:
@@ -599,6 +599,41 b' def test_escaped_paren():'
599 599 tt.check_pairs(isp.transform_escaped, syntax['escaped_paren'])
600 600
601 601
602 def test_last_blank():
603 nt.assert_false(isp.last_blank(''))
604 nt.assert_false(isp.last_blank('abc'))
605 nt.assert_false(isp.last_blank('abc\n'))
606 nt.assert_false(isp.last_blank('abc\na'))
607 nt.assert_true(isp.last_blank('\n'))
608 nt.assert_true(isp.last_blank('\n '))
609 nt.assert_true(isp.last_blank('abc\n '))
610 nt.assert_true(isp.last_blank('abc\n\n'))
611
612
613 def test_cell_magics():
614 from IPython.core import magic
615
616 cell = """\
617 %%cellm line
618 body
619 """
620 sp = isp.IPythonInputSplitter(input_mode='line')
621 sp.push(cell)
622 nt.assert_equal(sp.cell_magic_parts, ['body\n'])
623 out = sp.source
624 ref = u"get_ipython()._cell_magic(u'cellm', u'line')\n"
625 nt.assert_equal(out, ref)
626
627 sp.reset()
628
629 sp.push('%%cellm line2\n')
630 nt.assert_true(sp.push_accepts_more()) #1
631 sp.push('\n')
632 nt.assert_true(sp.push_accepts_more()) #2
633 sp.push('\n')
634 nt.assert_false(sp.push_accepts_more()) #3
635
636
602 637 class IPythonInputTestCase(InputSplitterTestCase):
603 638 """By just creating a new class whose .isp is a different instance, we
604 639 re-run the same test battery on the new input splitter.
General Comments 0
You need to be logged in to leave comments. Login now