Show More
@@ -247,8 +247,6 b' class InputSplitter(object):' | |||||
247 | # synced to the source, so it can be queried at any time to obtain the code |
|
247 | # synced to the source, so it can be queried at any time to obtain the code | |
248 | # object; it will be None if the source doesn't compile to valid Python. |
|
248 | # object; it will be None if the source doesn't compile to valid Python. | |
249 | code = None |
|
249 | code = None | |
250 | # Input mode |
|
|||
251 | input_mode = 'line' |
|
|||
252 |
|
250 | |||
253 | # Private attributes |
|
251 | # Private attributes | |
254 |
|
252 | |||
@@ -261,32 +259,12 b' class InputSplitter(object):' | |||||
261 | # Boolean indicating whether the current block is complete |
|
259 | # Boolean indicating whether the current block is complete | |
262 | _is_complete = None |
|
260 | _is_complete = None | |
263 |
|
261 | |||
264 |
def __init__(self |
|
262 | def __init__(self): | |
265 | """Create a new InputSplitter instance. |
|
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 | self._buffer = [] |
|
265 | self._buffer = [] | |
286 | self._compile = codeop.CommandCompiler() |
|
266 | self._compile = codeop.CommandCompiler() | |
287 | self.encoding = get_input_encoding() |
|
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 | def reset(self): |
|
269 | def reset(self): | |
292 | """Reset the input buffer and associated state.""" |
|
270 | """Reset the input buffer and associated state.""" | |
@@ -326,9 +304,6 b' class InputSplitter(object):' | |||||
326 | this value is also stored as a private attribute (``_is_complete``), so it |
|
304 | this value is also stored as a private attribute (``_is_complete``), so it | |
327 | can be queried at any time. |
|
305 | can be queried at any time. | |
328 | """ |
|
306 | """ | |
329 | if self.input_mode == 'cell': |
|
|||
330 | self.reset() |
|
|||
331 |
|
||||
332 | self._store(lines) |
|
307 | self._store(lines) | |
333 | source = self.source |
|
308 | source = self.source | |
334 |
|
309 | |||
@@ -365,20 +340,14 b' class InputSplitter(object):' | |||||
365 | This method is meant to be used by line-oriented frontends, who need to |
|
340 | This method is meant to be used by line-oriented frontends, who need to | |
366 | guess whether a block is complete or not based solely on prior and |
|
341 | guess whether a block is complete or not based solely on prior and | |
367 | current input lines. The InputSplitter considers it has a complete |
|
342 | current input lines. The InputSplitter considers it has a complete | |
368 |
interactive block and will not accept more input |
|
343 | interactive block and will not accept more input when either: | |
369 | SyntaxError is raised, or *all* of the following are true: |
|
344 | ||
370 |
|
345 | * A SyntaxError is raised | ||
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). |
|
|||
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 |
|
350 | * The code is complete and has a blank line at the end | |
380 | *line-oriented* frontends, since it means that intermediate blank lines |
|
|||
381 | are not allowed in function definitions (or any other indented block). |
|
|||
382 |
|
351 | |||
383 | If the current input produces a syntax error, this method immediately |
|
352 | If the current input produces a syntax error, this method immediately | |
384 | returns False but does *not* raise the syntax error exception, as |
|
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 | # With incomplete input, unconditionally accept more |
|
359 | # With incomplete input, unconditionally accept more | |
|
360 | # A syntax error also sets _is_complete to True - see push() | |||
391 | if not self._is_complete: |
|
361 | if not self._is_complete: | |
|
362 | #print("Not complete") # debug | |||
392 | return True |
|
363 | return True | |
393 |
|
364 | |||
394 | # If we already have complete input and we're flush left, the answer |
|
365 | # The user can make any (complete) input execute by leaving a blank line | |
395 | # depends. In line mode, if there hasn't been any indentation, |
|
366 | last_line = self.source.splitlines()[-1] | |
396 | # that's it. If we've come back from some indentation, we need |
|
367 | if (not last_line) or last_line.isspace(): | |
397 | # the blank final line to finish. |
|
368 | #print("Blank line") # debug | |
398 | # In cell mode, we need to check how many blocks the input so far |
|
369 | return False | |
399 | # compiles into, because if there's already more than one full |
|
370 | ||
400 | # independent block of input, then the client has entered full |
|
371 | # If there's just a single line or AST node, and we're flush left, as is | |
401 | # 'cell' mode and is feeding lines that each is complete. In this |
|
372 | # the case after a simple statement such as 'a=1', we want to execute it | |
402 | # case we should then keep accepting. The Qt terminal-like console |
|
373 | # straight away. | |
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. |
|
|||
407 | if self.indent_spaces==0: |
|
374 | if self.indent_spaces==0: | |
408 |
if self. |
|
375 | if len(self.source.splitlines()) <= 1: | |
409 | if not self._full_dedent: |
|
376 | return False | |
410 | 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 | else: |
|
383 | else: | |
412 | try: |
|
384 | if len(code_ast.body) == 1 and \ | |
413 | code_ast = ast.parse(u''.join(self._buffer)) |
|
385 | not hasattr(code_ast.body[0], 'body'): | |
414 | except Exception: |
|
386 | #print("Simple statement") # debug | |
415 | return False |
|
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 |
|
389 | # General fallback - accept more code | |
421 | # line at the end. |
|
390 | return True | |
422 | last_line = self.source.splitlines()[-1] |
|
|||
423 | return bool(last_line and not last_line.isspace()) |
|
|||
424 |
|
391 | |||
425 | #------------------------------------------------------------------------ |
|
392 | #------------------------------------------------------------------------ | |
426 | # Private interface |
|
393 | # Private interface | |
@@ -510,9 +477,9 b' class IPythonInputSplitter(InputSplitter):' | |||||
510 | # List with lines of raw input accumulated so far. |
|
477 | # List with lines of raw input accumulated so far. | |
511 | _buffer_raw = None |
|
478 | _buffer_raw = None | |
512 |
|
479 | |||
513 |
def __init__(self, input_ |
|
480 | def __init__(self, line_input_checker=False, physical_line_transforms=None, | |
514 | logical_line_transforms=None, python_line_transforms=None): |
|
481 | logical_line_transforms=None, python_line_transforms=None): | |
515 |
super(IPythonInputSplitter, self).__init__( |
|
482 | super(IPythonInputSplitter, self).__init__() | |
516 | self._buffer_raw = [] |
|
483 | self._buffer_raw = [] | |
517 | self._validate = True |
|
484 | self._validate = True | |
518 |
|
485 | |||
@@ -528,7 +495,7 b' class IPythonInputSplitter(InputSplitter):' | |||||
528 | if logical_line_transforms is not None: |
|
495 | if logical_line_transforms is not None: | |
529 | self.logical_line_transforms = logical_line_transforms |
|
496 | self.logical_line_transforms = logical_line_transforms | |
530 | else: |
|
497 | else: | |
531 | self.logical_line_transforms = [cellmagic(), |
|
498 | self.logical_line_transforms = [cellmagic(end_on_blank_line=line_input_checker), | |
532 | help_end(), |
|
499 | help_end(), | |
533 | escaped_commands(), |
|
500 | escaped_commands(), | |
534 | assign_from_magic(), |
|
501 | assign_from_magic(), | |
@@ -641,44 +608,14 b' class IPythonInputSplitter(InputSplitter):' | |||||
641 | if not lines_list: |
|
608 | if not lines_list: | |
642 | lines_list = [''] |
|
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 | # Store raw source before applying any transformations to it. Note |
|
611 | # Store raw source before applying any transformations to it. Note | |
671 | # that this must be done *after* the reset() call that would otherwise |
|
612 | # that this must be done *after* the reset() call that would otherwise | |
672 | # flush the buffer. |
|
613 | # flush the buffer. | |
673 | self._store(lines, self._buffer_raw, 'source_raw') |
|
614 | self._store(lines, self._buffer_raw, 'source_raw') | |
674 |
|
615 | |||
675 | try: |
|
616 | for line in lines_list: | |
676 | for line in lines_list: |
|
617 | out = self.push_line(line) | |
677 | out = self.push_line(line) |
|
618 | ||
678 | finally: |
|
|||
679 | if changed_input_mode: |
|
|||
680 | self.input_mode = saved_input_mode |
|
|||
681 |
|
||||
682 | return out |
|
619 | return out | |
683 |
|
620 | |||
684 | def push_line(self, line): |
|
621 | def push_line(self, line): |
@@ -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 |
|
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 |
@@ -283,10 +283,16 b' class InteractiveShell(SingletonConfigurable):' | |||||
283 | filename = Unicode("<ipython console>") |
|
283 | filename = Unicode("<ipython console>") | |
284 | ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__ |
|
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 |
|
286 | # Input splitter, to transform input line by line and detect when a block | |
287 | # interactive statements or whole blocks. |
|
287 | # is ready to be executed. | |
288 | input_splitter = Instance('IPython.core.inputsplitter.IPythonInputSplitter', |
|
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 | logstart = CBool(False, config=True, help= |
|
296 | logstart = CBool(False, config=True, help= | |
291 | """ |
|
297 | """ | |
292 | Start logging to the default log file. |
|
298 | Start logging to the default log file. | |
@@ -2581,10 +2587,9 b' class InteractiveShell(SingletonConfigurable):' | |||||
2581 | if silent: |
|
2587 | if silent: | |
2582 | store_history = False |
|
2588 | store_history = False | |
2583 |
|
2589 | |||
2584 |
self.input_ |
|
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 | # Our own compiler remembers the __future__ environment. If we want to |
|
2593 | # Our own compiler remembers the __future__ environment. If we want to | |
2589 | # run code with a separate __future__ environment, use the default |
|
2594 | # run code with a separate __future__ environment, use the default | |
2590 | # compiler |
|
2595 | # compiler |
@@ -168,9 +168,6 b' class InputSplitterTestCase(unittest.TestCase):' | |||||
168 | self.assertEqual(isp.indent_spaces, 0) |
|
168 | self.assertEqual(isp.indent_spaces, 0) | |
169 |
|
169 | |||
170 | def test_indent2(self): |
|
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 | isp = self.isp |
|
171 | isp = self.isp | |
175 | isp.push('if 1:') |
|
172 | isp.push('if 1:') | |
176 | self.assertEqual(isp.indent_spaces, 4) |
|
173 | self.assertEqual(isp.indent_spaces, 4) | |
@@ -181,9 +178,6 b' class InputSplitterTestCase(unittest.TestCase):' | |||||
181 | self.assertEqual(isp.indent_spaces, 4) |
|
178 | self.assertEqual(isp.indent_spaces, 4) | |
182 |
|
179 | |||
183 | def test_indent3(self): |
|
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 | isp = self.isp |
|
181 | isp = self.isp | |
188 | # When a multiline statement contains parens or multiline strings, we |
|
182 | # When a multiline statement contains parens or multiline strings, we | |
189 | # shouldn't get confused. |
|
183 | # shouldn't get confused. | |
@@ -192,9 +186,6 b' class InputSplitterTestCase(unittest.TestCase):' | |||||
192 | self.assertEqual(isp.indent_spaces, 4) |
|
186 | self.assertEqual(isp.indent_spaces, 4) | |
193 |
|
187 | |||
194 | def test_indent4(self): |
|
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 | isp = self.isp |
|
189 | isp = self.isp | |
199 | # whitespace after ':' should not screw up indent level |
|
190 | # whitespace after ':' should not screw up indent level | |
200 | isp.push('if 1: \n x=1') |
|
191 | isp.push('if 1: \n x=1') | |
@@ -279,23 +270,12 b' class InputSplitterTestCase(unittest.TestCase):' | |||||
279 | isp.push(' a = 1') |
|
270 | isp.push(' a = 1') | |
280 | self.assertFalse(isp.push('b = [1,')) |
|
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 | def test_push_accepts_more(self): |
|
273 | def test_push_accepts_more(self): | |
291 | isp = self.isp |
|
274 | isp = self.isp | |
292 | isp.push('x=1') |
|
275 | isp.push('x=1') | |
293 | self.assertFalse(isp.push_accepts_more()) |
|
276 | self.assertFalse(isp.push_accepts_more()) | |
294 |
|
277 | |||
295 | def test_push_accepts_more2(self): |
|
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 | isp = self.isp |
|
279 | isp = self.isp | |
300 | isp.push('if 1:') |
|
280 | isp.push('if 1:') | |
301 | self.assertTrue(isp.push_accepts_more()) |
|
281 | self.assertTrue(isp.push_accepts_more()) | |
@@ -310,9 +290,6 b' class InputSplitterTestCase(unittest.TestCase):' | |||||
310 | self.assertFalse(isp.push_accepts_more()) |
|
290 | self.assertFalse(isp.push_accepts_more()) | |
311 |
|
291 | |||
312 | def test_push_accepts_more4(self): |
|
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 | isp = self.isp |
|
293 | isp = self.isp | |
317 | # When a multiline statement contains parens or multiline strings, we |
|
294 | # When a multiline statement contains parens or multiline strings, we | |
318 | # shouldn't get confused. |
|
295 | # shouldn't get confused. | |
@@ -331,14 +308,13 b' class InputSplitterTestCase(unittest.TestCase):' | |||||
331 | self.assertFalse(isp.push_accepts_more()) |
|
308 | self.assertFalse(isp.push_accepts_more()) | |
332 |
|
309 | |||
333 | def test_push_accepts_more5(self): |
|
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 | isp = self.isp |
|
311 | isp = self.isp | |
338 | isp.push('try:') |
|
312 | isp.push('try:') | |
339 | isp.push(' a = 5') |
|
313 | isp.push(' a = 5') | |
340 | isp.push('except:') |
|
314 | isp.push('except:') | |
341 | isp.push(' raise') |
|
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 | self.assertTrue(isp.push_accepts_more()) |
|
318 | self.assertTrue(isp.push_accepts_more()) | |
343 |
|
319 | |||
344 | def test_continuation(self): |
|
320 | def test_continuation(self): | |
@@ -431,7 +407,7 b' class IPythonInputTestCase(InputSplitterTestCase):' | |||||
431 | """ |
|
407 | """ | |
432 |
|
408 | |||
433 | def setUp(self): |
|
409 | def setUp(self): | |
434 |
self.isp = isp.IPythonInputSplitter( |
|
410 | self.isp = isp.IPythonInputSplitter() | |
435 |
|
411 | |||
436 | def test_syntax(self): |
|
412 | def test_syntax(self): | |
437 | """Call all single-line syntax tests from the main object""" |
|
413 | """Call all single-line syntax tests from the main object""" | |
@@ -467,32 +443,6 b' class IPythonInputTestCase(InputSplitterTestCase):' | |||||
467 | self.assertEqual(out.rstrip(), out_t) |
|
443 | self.assertEqual(out.rstrip(), out_t) | |
468 | self.assertEqual(out_raw.rstrip(), raw) |
|
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 | def test_syntax_multiline_cell(self): |
|
446 | def test_syntax_multiline_cell(self): | |
497 | isp = self.isp |
|
447 | isp = self.isp | |
498 | for example in syntax_ml.itervalues(): |
|
448 | for example in syntax_ml.itervalues(): | |
@@ -588,39 +538,35 b' class CellMagicsCommon(object):' | |||||
588 | out = sp.source_reset() |
|
538 | out = sp.source_reset() | |
589 | 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" | |
590 | 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()) | |||
591 |
|
545 | |||
592 | def tearDown(self): |
|
546 | def tearDown(self): | |
593 | self.sp.reset() |
|
547 | self.sp.reset() | |
594 |
|
548 | |||
595 |
|
549 | |||
596 | class CellModeCellMagics(CellMagicsCommon, unittest.TestCase): |
|
550 | class CellModeCellMagics(CellMagicsCommon, unittest.TestCase): | |
597 |
sp = isp.IPythonInputSplitter(input_ |
|
551 | sp = isp.IPythonInputSplitter(line_input_checker=False) | |
598 |
|
552 | |||
599 | def test_incremental(self): |
|
553 | def test_incremental(self): | |
600 | sp = self.sp |
|
554 | sp = self.sp | |
601 |
s |
|
555 | sp.push('%%cellm firstline\n') | |
602 | sp.push(src) |
|
|||
603 | nt.assert_true(sp.push_accepts_more()) #1 |
|
556 | nt.assert_true(sp.push_accepts_more()) #1 | |
604 | src += '\n' |
|
557 | sp.push('line2\n') | |
605 | sp.push(src) |
|
558 | nt.assert_true(sp.push_accepts_more()) #2 | |
606 | # Note: if we ever change the logic to allow full blank lines (see |
|
559 | sp.push('\n') | |
607 | # _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 | |
608 |
nt.assert_ |
|
561 | nt.assert_true(sp.push_accepts_more()) #3 | |
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 |
|
||||
617 |
|
562 | |||
618 | class LineModeCellMagics(CellMagicsCommon, unittest.TestCase): |
|
563 | class LineModeCellMagics(CellMagicsCommon, unittest.TestCase): | |
619 |
sp = isp.IPythonInputSplitter(input_ |
|
564 | sp = isp.IPythonInputSplitter(line_input_checker=True) | |
620 |
|
565 | |||
621 | def test_incremental(self): |
|
566 | def test_incremental(self): | |
622 | sp = self.sp |
|
567 | sp = self.sp | |
623 | sp.push('%%cellm line2\n') |
|
568 | sp.push('%%cellm line2\n') | |
624 | nt.assert_true(sp.push_accepts_more()) #1 |
|
569 | nt.assert_true(sp.push_accepts_more()) #1 | |
625 | sp.push('\n') |
|
570 | sp.push('\n') | |
|
571 | # In this case, a blank line should end the cell magic | |||
626 | 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 |
( |
|
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), |
@@ -146,7 +146,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||||
146 | self._copy_raw_action = QtGui.QAction('Copy (Raw Text)', None) |
|
146 | self._copy_raw_action = QtGui.QAction('Copy (Raw Text)', None) | |
147 | self._hidden = False |
|
147 | self._hidden = False | |
148 | self._highlighter = FrontendHighlighter(self) |
|
148 | self._highlighter = FrontendHighlighter(self) | |
149 |
self._input_splitter = self._input_splitter_class( |
|
149 | self._input_splitter = self._input_splitter_class() | |
150 | self._kernel_manager = None |
|
150 | self._kernel_manager = None | |
151 | self._request_info = {} |
|
151 | self._request_info = {} | |
152 | self._request_info['execute'] = {}; |
|
152 | self._request_info['execute'] = {}; | |
@@ -204,6 +204,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||||
204 | prompt created. When triggered by an Enter/Return key press, |
|
204 | prompt created. When triggered by an Enter/Return key press, | |
205 | 'interactive' is True; otherwise, it is False. |
|
205 | 'interactive' is True; otherwise, it is False. | |
206 | """ |
|
206 | """ | |
|
207 | self._input_splitter.reset() | |||
207 | complete = self._input_splitter.push(source) |
|
208 | complete = self._input_splitter.push(source) | |
208 | if interactive: |
|
209 | if interactive: | |
209 | complete = not self._input_splitter.push_accepts_more() |
|
210 | complete = not self._input_splitter.push_accepts_more() |
@@ -82,7 +82,7 b' def get_pasted_lines(sentinel, l_input=py3compat.input):' | |||||
82 | class TerminalMagics(Magics): |
|
82 | class TerminalMagics(Magics): | |
83 | def __init__(self, shell): |
|
83 | def __init__(self, shell): | |
84 | super(TerminalMagics, self).__init__(shell) |
|
84 | super(TerminalMagics, self).__init__(shell) | |
85 |
self.input_splitter = IPythonInputSplitter( |
|
85 | self.input_splitter = IPythonInputSplitter() | |
86 |
|
86 | |||
87 | def cleanup_input(self, block): |
|
87 | def cleanup_input(self, block): | |
88 | """Apply all possible IPython cleanups to an input block. |
|
88 | """Apply all possible IPython cleanups to an input block. |
@@ -35,6 +35,14 b' in attributes of :class:`~IPython.core.inputsplitter.IPythonInputSplitter`:' | |||||
35 | passed to these, but note that function and class *definitions* are still a |
|
35 | passed to these, but note that function and class *definitions* are still a | |
36 | series of separate statements. IPython does not use any of these by default. |
|
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 | Stateless transformations |
|
46 | Stateless transformations | |
39 | ------------------------- |
|
47 | ------------------------- | |
40 |
|
48 |
General Comments 0
You need to be logged in to leave comments.
Login now