##// END OF EJS Templates
Allow IPythonInputSplitter to accept cell magics containing blank lines
Thomas Kluyver -
Show More
@@ -480,7 +480,7 b' class IPythonInputSplitter(InputSplitter):'
480 # List with lines of raw input accumulated so far.
480 # List with lines of raw input accumulated so far.
481 _buffer_raw = None
481 _buffer_raw = None
482
482
483 def __init__(self, physical_line_transforms=None,
483 def __init__(self, line_input_checker=False, physical_line_transforms=None,
484 logical_line_transforms=None, python_line_transforms=None):
484 logical_line_transforms=None, python_line_transforms=None):
485 super(IPythonInputSplitter, self).__init__()
485 super(IPythonInputSplitter, self).__init__()
486 self._buffer_raw = []
486 self._buffer_raw = []
@@ -498,7 +498,7 b' class IPythonInputSplitter(InputSplitter):'
498 if logical_line_transforms is not None:
498 if logical_line_transforms is not None:
499 self.logical_line_transforms = logical_line_transforms
499 self.logical_line_transforms = logical_line_transforms
500 else:
500 else:
501 self.logical_line_transforms = [cellmagic(),
501 self.logical_line_transforms = [cellmagic(end_on_blank_line=line_input_checker),
502 help_end(),
502 help_end(),
503 escaped_commands(),
503 escaped_commands(),
504 assign_from_magic(),
504 assign_from_magic(),
@@ -60,8 +60,8 b' class InputTransformer(object):'
60 will allow instantiation with the decorated object.
60 will allow instantiation with the decorated object.
61 """
61 """
62 @functools.wraps(func)
62 @functools.wraps(func)
63 def transformer_factory():
63 def transformer_factory(**kwargs):
64 return cls(func)
64 return cls(func, **kwargs)
65
65
66 return transformer_factory
66 return transformer_factory
67
67
@@ -84,9 +84,9 b' class StatelessInputTransformer(InputTransformer):'
84
84
85 class CoroutineInputTransformer(InputTransformer):
85 class CoroutineInputTransformer(InputTransformer):
86 """Wrapper for an input transformer implemented as a coroutine."""
86 """Wrapper for an input transformer implemented as a coroutine."""
87 def __init__(self, coro):
87 def __init__(self, coro, **kwargs):
88 # Prime it
88 # Prime it
89 self.coro = coro()
89 self.coro = coro(**kwargs)
90 next(self.coro)
90 next(self.coro)
91
91
92 def __repr__(self):
92 def __repr__(self):
@@ -316,7 +316,7 b' def help_end(line):'
316
316
317
317
318 @CoroutineInputTransformer.wrap
318 @CoroutineInputTransformer.wrap
319 def cellmagic():
319 def cellmagic(end_on_blank_line=False):
320 """Captures & transforms cell magics.
320 """Captures & transforms cell magics.
321
321
322 After a cell magic is started, this stores up any lines it gets until it is
322 After a cell magic is started, this stores up any lines it gets until it is
@@ -337,7 +337,8 b' def cellmagic():'
337 first = line
337 first = line
338 body = []
338 body = []
339 line = (yield None)
339 line = (yield None)
340 while (line is not None) and (line.strip() != ''):
340 while (line is not None) and \
341 ((line.strip() != '') or not end_on_blank_line):
341 body.append(line)
342 body.append(line)
342 line = (yield None)
343 line = (yield None)
343
344
@@ -538,39 +538,35 b' class CellMagicsCommon(object):'
538 out = sp.source_reset()
538 out = sp.source_reset()
539 ref = u"get_ipython().run_cell_magic({u}'cellm', {u}'line', {u}'body')\n"
539 ref = u"get_ipython().run_cell_magic({u}'cellm', {u}'line', {u}'body')\n"
540 nt.assert_equal(out, py3compat.u_format(ref))
540 nt.assert_equal(out, py3compat.u_format(ref))
541
542 def test_cellmagic_help(self):
543 self.sp.push('%%cellm?')
544 nt.assert_false(self.sp.push_accepts_more())
541
545
542 def tearDown(self):
546 def tearDown(self):
543 self.sp.reset()
547 self.sp.reset()
544
548
545
549
546 class CellModeCellMagics(CellMagicsCommon, unittest.TestCase):
550 class CellModeCellMagics(CellMagicsCommon, unittest.TestCase):
547 sp = isp.IPythonInputSplitter(input_mode='cell')
551 sp = isp.IPythonInputSplitter(line_input_checker=False)
548
552
549 def test_incremental(self):
553 def test_incremental(self):
550 sp = self.sp
554 sp = self.sp
551 src = '%%cellm line2\n'
555 sp.push('%%cellm firstline\n')
552 sp.push(src)
553 nt.assert_true(sp.push_accepts_more()) #1
556 nt.assert_true(sp.push_accepts_more()) #1
554 src += '\n'
557 sp.push('line2\n')
555 sp.push(src)
558 nt.assert_true(sp.push_accepts_more()) #2
556 # Note: if we ever change the logic to allow full blank lines (see
559 sp.push('\n')
557 # _handle_cell_magic), then the following test should change to true
560 # This should accept a blank line and carry on until the cell is reset
558 nt.assert_false(sp.push_accepts_more()) #2
561 nt.assert_true(sp.push_accepts_more()) #3
559 # By now, even with full blanks allowed, a second blank should signal
560 # the end. For now this test is only a redundancy safety, but don't
561 # delete it in case we change our mind and the previous one goes to
562 # true.
563 src += '\n'
564 sp.push(src)
565 nt.assert_false(sp.push_accepts_more()) #3
566
567
562
568 class LineModeCellMagics(CellMagicsCommon, unittest.TestCase):
563 class LineModeCellMagics(CellMagicsCommon, unittest.TestCase):
569 sp = isp.IPythonInputSplitter(input_mode='line')
564 sp = isp.IPythonInputSplitter(line_input_checker=True)
570
565
571 def test_incremental(self):
566 def test_incremental(self):
572 sp = self.sp
567 sp = self.sp
573 sp.push('%%cellm line2\n')
568 sp.push('%%cellm line2\n')
574 nt.assert_true(sp.push_accepts_more()) #1
569 nt.assert_true(sp.push_accepts_more()) #1
575 sp.push('\n')
570 sp.push('\n')
571 # In this case, a blank line should end the cell magic
576 nt.assert_false(sp.push_accepts_more()) #2
572 nt.assert_false(sp.push_accepts_more()) #2
@@ -19,9 +19,9 b' def transform_and_reset(transformer):'
19 return transform
19 return transform
20
20
21 # Transformer tests
21 # Transformer tests
22 def transform_checker(tests, transformer):
22 def transform_checker(tests, transformer, **kwargs):
23 """Utility to loop over test inputs"""
23 """Utility to loop over test inputs"""
24 transformer = transformer()
24 transformer = transformer(**kwargs)
25 try:
25 try:
26 for inp, tr in tests:
26 for inp, tr in tests:
27 if inp is None:
27 if inp is None:
@@ -223,7 +223,7 b' syntax_ml = \\'
223 ],
223 ],
224 [(u'%%bar 123', None),
224 [(u'%%bar 123', None),
225 (u'hello', None),
225 (u'hello', None),
226 (u'', u_fmt("get_ipython().run_cell_magic({u}'bar', {u}'123', {u}'hello')")),
226 (None , u_fmt("get_ipython().run_cell_magic({u}'bar', {u}'123', {u}'hello')")),
227 ],
227 ],
228 ],
228 ],
229
229
@@ -348,6 +348,12 b' def test_escaped_paren():'
348 def test_cellmagic():
348 def test_cellmagic():
349 for example in syntax_ml['cellmagic']:
349 for example in syntax_ml['cellmagic']:
350 transform_checker(example, ipt.cellmagic)
350 transform_checker(example, ipt.cellmagic)
351
352 line_example = [(u'%%bar 123', None),
353 (u'hello', None),
354 (u'' , u_fmt("get_ipython().run_cell_magic({u}'bar', {u}'123', {u}'hello')")),
355 ]
356 transform_checker(line_example, ipt.cellmagic, end_on_blank_line=True)
351
357
352 def test_has_comment():
358 def test_has_comment():
353 tests = [('text', False),
359 tests = [('text', False),
General Comments 0
You need to be logged in to leave comments. Login now