##// END OF EJS Templates
Merge pull request #3203 from takluyver/cell-magics-wholecell...
Min RK -
r10256:410df964 merge
parent child Browse files
Show More
@@ -247,8 +247,6 b' class InputSplitter(object):'
247 247 # synced to the source, so it can be queried at any time to obtain the code
248 248 # object; it will be None if the source doesn't compile to valid Python.
249 249 code = None
250 # Input mode
251 input_mode = 'line'
252 250
253 251 # Private attributes
254 252
@@ -261,32 +259,12 b' class InputSplitter(object):'
261 259 # Boolean indicating whether the current block is complete
262 260 _is_complete = None
263 261
264 def __init__(self, input_mode=None):
262 def __init__(self):
265 263 """Create a new InputSplitter instance.
266
267 Parameters
268 ----------
269 input_mode : str
270
271 One of ['line', 'cell']; default is 'line'.
272
273 The input_mode parameter controls how new inputs are used when fed via
274 the :meth:`push` method:
275
276 - 'line': meant for line-oriented clients, inputs are appended one at a
277 time to the internal buffer and the whole buffer is compiled.
278
279 - 'cell': meant for clients that can edit multi-line 'cells' of text at
280 a time. A cell can contain one or more blocks that can be compile in
281 'single' mode by Python. In this mode, each new input new input
282 completely replaces all prior inputs. Cell mode is thus equivalent
283 to prepending a full reset() to every push() call.
284 264 """
285 265 self._buffer = []
286 266 self._compile = codeop.CommandCompiler()
287 267 self.encoding = get_input_encoding()
288 self.input_mode = InputSplitter.input_mode if input_mode is None \
289 else input_mode
290 268
291 269 def reset(self):
292 270 """Reset the input buffer and associated state."""
@@ -326,9 +304,6 b' class InputSplitter(object):'
326 304 this value is also stored as a private attribute (``_is_complete``), so it
327 305 can be queried at any time.
328 306 """
329 if self.input_mode == 'cell':
330 self.reset()
331
332 307 self._store(lines)
333 308 source = self.source
334 309
@@ -365,20 +340,14 b' class InputSplitter(object):'
365 340 This method is meant to be used by line-oriented frontends, who need to
366 341 guess whether a block is complete or not based solely on prior and
367 342 current input lines. The InputSplitter considers it has a complete
368 interactive block and will not accept more input only when either a
369 SyntaxError is raised, or *all* of the following are true:
370
371 1. The input compiles to a complete statement.
372
373 2. The indentation level is flush-left (because if we are indented,
374 like inside a function definition or for loop, we need to keep
375 reading new input).
343 interactive block and will not accept more input when either:
344
345 * A SyntaxError is raised
376 346
377 3. There is one extra line consisting only of whitespace.
347 * The code is complete and consists of a single line or a single
348 non-compound statement
378 349
379 Because of condition #3, this method should be used only by
380 *line-oriented* frontends, since it means that intermediate blank lines
381 are not allowed in function definitions (or any other indented block).
350 * The code is complete and has a blank line at the end
382 351
383 352 If the current input produces a syntax error, this method immediately
384 353 returns False but does *not* raise the syntax error exception, as
@@ -388,39 +357,37 b' class InputSplitter(object):'
388 357 """
389 358
390 359 # With incomplete input, unconditionally accept more
360 # A syntax error also sets _is_complete to True - see push()
391 361 if not self._is_complete:
362 #print("Not complete") # debug
392 363 return True
393
394 # If we already have complete input and we're flush left, the answer
395 # depends. In line mode, if there hasn't been any indentation,
396 # that's it. If we've come back from some indentation, we need
397 # the blank final line to finish.
398 # In cell mode, we need to check how many blocks the input so far
399 # compiles into, because if there's already more than one full
400 # independent block of input, then the client has entered full
401 # 'cell' mode and is feeding lines that each is complete. In this
402 # case we should then keep accepting. The Qt terminal-like console
403 # does precisely this, to provide the convenience of terminal-like
404 # input of single expressions, but allowing the user (with a
405 # separate keystroke) to switch to 'cell' mode and type multiple
406 # expressions in one shot.
364
365 # The user can make any (complete) input execute by leaving a blank line
366 last_line = self.source.splitlines()[-1]
367 if (not last_line) or last_line.isspace():
368 #print("Blank line") # debug
369 return False
370
371 # If there's just a single line or AST node, and we're flush left, as is
372 # the case after a simple statement such as 'a=1', we want to execute it
373 # straight away.
407 374 if self.indent_spaces==0:
408 if self.input_mode=='line':
409 if not self._full_dedent:
410 return False
375 if len(self.source.splitlines()) <= 1:
376 return False
377
378 try:
379 code_ast = ast.parse(u''.join(self._buffer))
380 except Exception:
381 #print("Can't parse AST") # debug
382 return False
411 383 else:
412 try:
413 code_ast = ast.parse(u''.join(self._buffer))
414 except Exception:
384 if len(code_ast.body) == 1 and \
385 not hasattr(code_ast.body[0], 'body'):
386 #print("Simple statement") # debug
415 387 return False
416 else:
417 if len(code_ast.body) == 1:
418 return False
419 388
420 # When input is complete, then termination is marked by an extra blank
421 # line at the end.
422 last_line = self.source.splitlines()[-1]
423 return bool(last_line and not last_line.isspace())
389 # General fallback - accept more code
390 return True
424 391
425 392 #------------------------------------------------------------------------
426 393 # Private interface
@@ -510,9 +477,9 b' class IPythonInputSplitter(InputSplitter):'
510 477 # List with lines of raw input accumulated so far.
511 478 _buffer_raw = None
512 479
513 def __init__(self, input_mode=None, physical_line_transforms=None,
480 def __init__(self, line_input_checker=False, physical_line_transforms=None,
514 481 logical_line_transforms=None, python_line_transforms=None):
515 super(IPythonInputSplitter, self).__init__(input_mode)
482 super(IPythonInputSplitter, self).__init__()
516 483 self._buffer_raw = []
517 484 self._validate = True
518 485
@@ -528,7 +495,7 b' class IPythonInputSplitter(InputSplitter):'
528 495 if logical_line_transforms is not None:
529 496 self.logical_line_transforms = logical_line_transforms
530 497 else:
531 self.logical_line_transforms = [cellmagic(),
498 self.logical_line_transforms = [cellmagic(end_on_blank_line=line_input_checker),
532 499 help_end(),
533 500 escaped_commands(),
534 501 assign_from_magic(),
@@ -641,44 +608,14 b' class IPythonInputSplitter(InputSplitter):'
641 608 if not lines_list:
642 609 lines_list = ['']
643 610
644 # Transform logic
645 #
646 # We only apply the line transformers to the input if we have either no
647 # input yet, or complete input, or if the last line of the buffer ends
648 # with ':' (opening an indented block). This prevents the accidental
649 # transformation of escapes inside multiline expressions like
650 # triple-quoted strings or parenthesized expressions.
651 #
652 # The last heuristic, while ugly, ensures that the first line of an
653 # indented block is correctly transformed.
654 #
655 # FIXME: try to find a cleaner approach for this last bit.
656
657 # If we were in 'block' mode, since we're going to pump the parent
658 # class by hand line by line, we need to temporarily switch out to
659 # 'line' mode, do a single manual reset and then feed the lines one
660 # by one. Note that this only matters if the input has more than one
661 # line.
662 changed_input_mode = False
663
664 if self.input_mode == 'cell':
665 self.reset()
666 changed_input_mode = True
667 saved_input_mode = 'cell'
668 self.input_mode = 'line'
669
670 611 # Store raw source before applying any transformations to it. Note
671 612 # that this must be done *after* the reset() call that would otherwise
672 613 # flush the buffer.
673 614 self._store(lines, self._buffer_raw, 'source_raw')
674 615
675 try:
676 for line in lines_list:
677 out = self.push_line(line)
678 finally:
679 if changed_input_mode:
680 self.input_mode = saved_input_mode
681
616 for line in lines_list:
617 out = self.push_line(line)
618
682 619 return out
683 620
684 621 def push_line(self, line):
@@ -60,8 +60,8 b' class InputTransformer(object):'
60 60 will allow instantiation with the decorated object.
61 61 """
62 62 @functools.wraps(func)
63 def transformer_factory():
64 return cls(func)
63 def transformer_factory(**kwargs):
64 return cls(func, **kwargs)
65 65
66 66 return transformer_factory
67 67
@@ -84,9 +84,9 b' class StatelessInputTransformer(InputTransformer):'
84 84
85 85 class CoroutineInputTransformer(InputTransformer):
86 86 """Wrapper for an input transformer implemented as a coroutine."""
87 def __init__(self, coro):
87 def __init__(self, coro, **kwargs):
88 88 # Prime it
89 self.coro = coro()
89 self.coro = coro(**kwargs)
90 90 next(self.coro)
91 91
92 92 def __repr__(self):
@@ -316,7 +316,7 b' def help_end(line):'
316 316
317 317
318 318 @CoroutineInputTransformer.wrap
319 def cellmagic():
319 def cellmagic(end_on_blank_line=False):
320 320 """Captures & transforms cell magics.
321 321
322 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 337 first = line
338 338 body = []
339 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 342 body.append(line)
342 343 line = (yield None)
343 344
@@ -283,10 +283,16 b' class InteractiveShell(SingletonConfigurable):'
283 283 filename = Unicode("<ipython console>")
284 284 ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__
285 285
286 # Input splitter, to split entire cells of input into either individual
287 # interactive statements or whole blocks.
286 # Input splitter, to transform input line by line and detect when a block
287 # is ready to be executed.
288 288 input_splitter = Instance('IPython.core.inputsplitter.IPythonInputSplitter',
289 (), {})
289 (), {'line_input_checker': True})
290
291 # This InputSplitter instance is used to transform completed cells before
292 # running them. It allows cell magics to contain blank lines.
293 input_transformer_manager = Instance('IPython.core.inputsplitter.IPythonInputSplitter',
294 (), {'line_input_checker': False})
295
290 296 logstart = CBool(False, config=True, help=
291 297 """
292 298 Start logging to the default log file.
@@ -2581,10 +2587,9 b' class InteractiveShell(SingletonConfigurable):'
2581 2587 if silent:
2582 2588 store_history = False
2583 2589
2584 self.input_splitter.push(raw_cell)
2590 self.input_transformer_manager.push(raw_cell)
2591 cell = self.input_transformer_manager.source_reset()
2585 2592
2586 cell = self.input_splitter.source_reset()
2587
2588 2593 # Our own compiler remembers the __future__ environment. If we want to
2589 2594 # run code with a separate __future__ environment, use the default
2590 2595 # compiler
@@ -168,9 +168,6 b' class InputSplitterTestCase(unittest.TestCase):'
168 168 self.assertEqual(isp.indent_spaces, 0)
169 169
170 170 def test_indent2(self):
171 # In cell mode, inputs must be fed in whole blocks, so skip this test
172 if self.isp.input_mode == 'cell': return
173
174 171 isp = self.isp
175 172 isp.push('if 1:')
176 173 self.assertEqual(isp.indent_spaces, 4)
@@ -181,9 +178,6 b' class InputSplitterTestCase(unittest.TestCase):'
181 178 self.assertEqual(isp.indent_spaces, 4)
182 179
183 180 def test_indent3(self):
184 # In cell mode, inputs must be fed in whole blocks, so skip this test
185 if self.isp.input_mode == 'cell': return
186
187 181 isp = self.isp
188 182 # When a multiline statement contains parens or multiline strings, we
189 183 # shouldn't get confused.
@@ -192,9 +186,6 b' class InputSplitterTestCase(unittest.TestCase):'
192 186 self.assertEqual(isp.indent_spaces, 4)
193 187
194 188 def test_indent4(self):
195 # In cell mode, inputs must be fed in whole blocks, so skip this test
196 if self.isp.input_mode == 'cell': return
197
198 189 isp = self.isp
199 190 # whitespace after ':' should not screw up indent level
200 191 isp.push('if 1: \n x=1')
@@ -279,23 +270,12 b' class InputSplitterTestCase(unittest.TestCase):'
279 270 isp.push(' a = 1')
280 271 self.assertFalse(isp.push('b = [1,'))
281 272
282 def test_replace_mode(self):
283 isp = self.isp
284 isp.input_mode = 'cell'
285 isp.push('x=1')
286 self.assertEqual(isp.source, 'x=1\n')
287 isp.push('x=2')
288 self.assertEqual(isp.source, 'x=2\n')
289
290 273 def test_push_accepts_more(self):
291 274 isp = self.isp
292 275 isp.push('x=1')
293 276 self.assertFalse(isp.push_accepts_more())
294 277
295 278 def test_push_accepts_more2(self):
296 # In cell mode, inputs must be fed in whole blocks, so skip this test
297 if self.isp.input_mode == 'cell': return
298
299 279 isp = self.isp
300 280 isp.push('if 1:')
301 281 self.assertTrue(isp.push_accepts_more())
@@ -310,9 +290,6 b' class InputSplitterTestCase(unittest.TestCase):'
310 290 self.assertFalse(isp.push_accepts_more())
311 291
312 292 def test_push_accepts_more4(self):
313 # In cell mode, inputs must be fed in whole blocks, so skip this test
314 if self.isp.input_mode == 'cell': return
315
316 293 isp = self.isp
317 294 # When a multiline statement contains parens or multiline strings, we
318 295 # shouldn't get confused.
@@ -331,14 +308,13 b' class InputSplitterTestCase(unittest.TestCase):'
331 308 self.assertFalse(isp.push_accepts_more())
332 309
333 310 def test_push_accepts_more5(self):
334 # In cell mode, inputs must be fed in whole blocks, so skip this test
335 if self.isp.input_mode == 'cell': return
336
337 311 isp = self.isp
338 312 isp.push('try:')
339 313 isp.push(' a = 5')
340 314 isp.push('except:')
341 315 isp.push(' raise')
316 # We want to be able to add an else: block at this point, so it should
317 # wait for a blank line.
342 318 self.assertTrue(isp.push_accepts_more())
343 319
344 320 def test_continuation(self):
@@ -431,7 +407,7 b' class IPythonInputTestCase(InputSplitterTestCase):'
431 407 """
432 408
433 409 def setUp(self):
434 self.isp = isp.IPythonInputSplitter(input_mode='line')
410 self.isp = isp.IPythonInputSplitter()
435 411
436 412 def test_syntax(self):
437 413 """Call all single-line syntax tests from the main object"""
@@ -467,32 +443,6 b' class IPythonInputTestCase(InputSplitterTestCase):'
467 443 self.assertEqual(out.rstrip(), out_t)
468 444 self.assertEqual(out_raw.rstrip(), raw)
469 445
470
471 class BlockIPythonInputTestCase(IPythonInputTestCase):
472
473 # Deactivate tests that don't make sense for the block mode
474 test_push3 = test_split = lambda s: None
475
476 def setUp(self):
477 self.isp = isp.IPythonInputSplitter(input_mode='cell')
478
479 def test_syntax_multiline(self):
480 isp = self.isp
481 for example in syntax_ml.itervalues():
482 raw_parts = []
483 out_t_parts = []
484 for line_pairs in example:
485 raw_parts, out_t_parts = zip(*line_pairs)
486
487 raw = '\n'.join(r for r in raw_parts if r is not None)
488 out_t = '\n'.join(o for o in out_t_parts if o is not None)
489
490 isp.push(raw)
491 out, out_raw = isp.source_raw_reset()
492 # Match ignoring trailing whitespace
493 self.assertEqual(out.rstrip(), out_t.rstrip())
494 self.assertEqual(out_raw.rstrip(), raw.rstrip())
495
496 446 def test_syntax_multiline_cell(self):
497 447 isp = self.isp
498 448 for example in syntax_ml.itervalues():
@@ -588,39 +538,35 b' class CellMagicsCommon(object):'
588 538 out = sp.source_reset()
589 539 ref = u"get_ipython().run_cell_magic({u}'cellm', {u}'line', {u}'body')\n"
590 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())
591 545
592 546 def tearDown(self):
593 547 self.sp.reset()
594 548
595 549
596 550 class CellModeCellMagics(CellMagicsCommon, unittest.TestCase):
597 sp = isp.IPythonInputSplitter(input_mode='cell')
551 sp = isp.IPythonInputSplitter(line_input_checker=False)
598 552
599 553 def test_incremental(self):
600 554 sp = self.sp
601 src = '%%cellm line2\n'
602 sp.push(src)
555 sp.push('%%cellm firstline\n')
603 556 nt.assert_true(sp.push_accepts_more()) #1
604 src += '\n'
605 sp.push(src)
606 # Note: if we ever change the logic to allow full blank lines (see
607 # _handle_cell_magic), then the following test should change to true
608 nt.assert_false(sp.push_accepts_more()) #2
609 # By now, even with full blanks allowed, a second blank should signal
610 # the end. For now this test is only a redundancy safety, but don't
611 # delete it in case we change our mind and the previous one goes to
612 # true.
613 src += '\n'
614 sp.push(src)
615 nt.assert_false(sp.push_accepts_more()) #3
616
557 sp.push('line2\n')
558 nt.assert_true(sp.push_accepts_more()) #2
559 sp.push('\n')
560 # This should accept a blank line and carry on until the cell is reset
561 nt.assert_true(sp.push_accepts_more()) #3
617 562
618 563 class LineModeCellMagics(CellMagicsCommon, unittest.TestCase):
619 sp = isp.IPythonInputSplitter(input_mode='line')
564 sp = isp.IPythonInputSplitter(line_input_checker=True)
620 565
621 566 def test_incremental(self):
622 567 sp = self.sp
623 568 sp.push('%%cellm line2\n')
624 569 nt.assert_true(sp.push_accepts_more()) #1
625 570 sp.push('\n')
571 # In this case, a blank line should end the cell magic
626 572 nt.assert_false(sp.push_accepts_more()) #2
@@ -19,9 +19,9 b' def transform_and_reset(transformer):'
19 19 return transform
20 20
21 21 # Transformer tests
22 def transform_checker(tests, transformer):
22 def transform_checker(tests, transformer, **kwargs):
23 23 """Utility to loop over test inputs"""
24 transformer = transformer()
24 transformer = transformer(**kwargs)
25 25 try:
26 26 for inp, tr in tests:
27 27 if inp is None:
@@ -223,7 +223,7 b' syntax_ml = \\'
223 223 ],
224 224 [(u'%%bar 123', None),
225 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 348 def test_cellmagic():
349 349 for example in syntax_ml['cellmagic']:
350 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 358 def test_has_comment():
353 359 tests = [('text', False),
@@ -146,7 +146,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
146 146 self._copy_raw_action = QtGui.QAction('Copy (Raw Text)', None)
147 147 self._hidden = False
148 148 self._highlighter = FrontendHighlighter(self)
149 self._input_splitter = self._input_splitter_class(input_mode='cell')
149 self._input_splitter = self._input_splitter_class()
150 150 self._kernel_manager = None
151 151 self._request_info = {}
152 152 self._request_info['execute'] = {};
@@ -204,6 +204,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
204 204 prompt created. When triggered by an Enter/Return key press,
205 205 'interactive' is True; otherwise, it is False.
206 206 """
207 self._input_splitter.reset()
207 208 complete = self._input_splitter.push(source)
208 209 if interactive:
209 210 complete = not self._input_splitter.push_accepts_more()
@@ -82,7 +82,7 b' def get_pasted_lines(sentinel, l_input=py3compat.input):'
82 82 class TerminalMagics(Magics):
83 83 def __init__(self, shell):
84 84 super(TerminalMagics, self).__init__(shell)
85 self.input_splitter = IPythonInputSplitter(input_mode='line')
85 self.input_splitter = IPythonInputSplitter()
86 86
87 87 def cleanup_input(self, block):
88 88 """Apply all possible IPython cleanups to an input block.
@@ -35,6 +35,14 b' in attributes of :class:`~IPython.core.inputsplitter.IPythonInputSplitter`:'
35 35 passed to these, but note that function and class *definitions* are still a
36 36 series of separate statements. IPython does not use any of these by default.
37 37
38 An InteractiveShell instance actually has two
39 :class:`~IPython.core.inputsplitter.IPythonInputSplitter` instances, as the
40 attributes :attr:`~IPython.core.interactiveshell.InteractiveShell.input_splitter`,
41 to tell when a block of input is complete, and
42 :attr:`~IPython.core.interactiveshell.InteractiveShell.input_transformer_manager`,
43 to transform complete cells. If you add a transformer, you should make sure that
44 it gets added to both.
45
38 46 Stateless transformations
39 47 -------------------------
40 48
General Comments 0
You need to be logged in to leave comments. Login now