##// END OF EJS Templates
Remove unused _find_indent method
Thomas Kluyver -
Show More
@@ -1,787 +1,742 b''
1 1 """Input handling and transformation machinery.
2 2
3 3 The first class in this module, :class:`InputSplitter`, is designed to tell when
4 4 input from a line-oriented frontend is complete and should be executed, and when
5 5 the user should be prompted for another line of code instead. The name 'input
6 6 splitter' is largely for historical reasons.
7 7
8 8 A companion, :class:`IPythonInputSplitter`, provides the same functionality but
9 9 with full support for the extended IPython syntax (magics, system calls, etc).
10 10 The code to actually do these transformations is in :mod:`IPython.core.inputtransformer`.
11 11 :class:`IPythonInputSplitter` feeds the raw code to the transformers in order
12 12 and stores the results.
13 13
14 14 For more details, see the class docstrings below.
15 15 """
16 16
17 17 # Copyright (c) IPython Development Team.
18 18 # Distributed under the terms of the Modified BSD License.
19 19 import ast
20 20 import codeop
21 21 import io
22 22 import re
23 23 import sys
24 24 import tokenize
25 25 import warnings
26 26
27 27 from IPython.utils.py3compat import cast_unicode
28 28 from IPython.core.inputtransformer import (leading_indent,
29 29 classic_prompt,
30 30 ipy_prompt,
31 31 cellmagic,
32 32 assemble_logical_lines,
33 33 help_end,
34 34 escaped_commands,
35 35 assign_from_magic,
36 36 assign_from_system,
37 37 assemble_python_lines,
38 38 )
39 39
40 40 # These are available in this module for backwards compatibility.
41 41 from IPython.core.inputtransformer import (ESC_SHELL, ESC_SH_CAP, ESC_HELP,
42 42 ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,
43 43 ESC_QUOTE, ESC_QUOTE2, ESC_PAREN, ESC_SEQUENCES)
44 44
45 45 #-----------------------------------------------------------------------------
46 46 # Utilities
47 47 #-----------------------------------------------------------------------------
48 48
49 49 # FIXME: These are general-purpose utilities that later can be moved to the
50 50 # general ward. Kept here for now because we're being very strict about test
51 51 # coverage with this code, and this lets us ensure that we keep 100% coverage
52 52 # while developing.
53 53
54 54 # compiled regexps for autoindent management
55 55 dedent_re = re.compile('|'.join([
56 56 r'^\s+raise(\s.*)?$', # raise statement (+ space + other stuff, maybe)
57 57 r'^\s+raise\([^\)]*\).*$', # wacky raise with immediate open paren
58 58 r'^\s+return(\s.*)?$', # normal return (+ space + other stuff, maybe)
59 59 r'^\s+return\([^\)]*\).*$', # wacky return with immediate open paren
60 60 r'^\s+pass\s*$', # pass (optionally followed by trailing spaces)
61 61 r'^\s+break\s*$', # break (optionally followed by trailing spaces)
62 62 r'^\s+continue\s*$', # continue (optionally followed by trailing spaces)
63 63 ]))
64 64 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
65 65
66 66 # regexp to match pure comment lines so we don't accidentally insert 'if 1:'
67 67 # before pure comments
68 68 comment_line_re = re.compile('^\s*\#')
69 69
70 70
71 71 def num_ini_spaces(s):
72 72 """Return the number of initial spaces in a string.
73 73
74 74 Note that tabs are counted as a single space. For now, we do *not* support
75 75 mixing of tabs and spaces in the user's input.
76 76
77 77 Parameters
78 78 ----------
79 79 s : string
80 80
81 81 Returns
82 82 -------
83 83 n : int
84 84 """
85 85
86 86 ini_spaces = ini_spaces_re.match(s)
87 87 if ini_spaces:
88 88 return ini_spaces.end()
89 89 else:
90 90 return 0
91 91
92 92 # Fake token types for partial_tokenize:
93 93 INCOMPLETE_STRING = tokenize.N_TOKENS
94 94 IN_MULTILINE_STATEMENT = tokenize.N_TOKENS + 1
95 95
96 96 # The 2 classes below have the same API as TokenInfo, but don't try to look up
97 97 # a token type name that they won't find.
98 98 class IncompleteString:
99 99 type = exact_type = INCOMPLETE_STRING
100 100 def __init__(self, s, start, end, line):
101 101 self.s = s
102 102 self.start = start
103 103 self.end = end
104 104 self.line = line
105 105
106 106 class InMultilineStatement:
107 107 type = exact_type = IN_MULTILINE_STATEMENT
108 108 def __init__(self, pos, line):
109 109 self.s = ''
110 110 self.start = self.end = pos
111 111 self.line = line
112 112
113 113 def partial_tokens(s):
114 114 """Iterate over tokens from a possibly-incomplete string of code.
115 115
116 116 This adds two special token types: INCOMPLETE_STRING and
117 117 IN_MULTILINE_STATEMENT. These can only occur as the last token yielded, and
118 118 represent the two main ways for code to be incomplete.
119 119 """
120 120 readline = io.StringIO(s).readline
121 121 token = tokenize.TokenInfo(tokenize.NEWLINE, '', (1, 0), (1, 0), '')
122 122 try:
123 123 for token in tokenize.generate_tokens(readline):
124 124 yield token
125 125 except tokenize.TokenError as e:
126 126 # catch EOF error
127 127 lines = s.splitlines(keepends=True)
128 128 end = len(lines), len(lines[-1])
129 129 if 'multi-line string' in e.args[0]:
130 130 l, c = start = token.end
131 131 s = lines[l-1][c:] + ''.join(lines[l:])
132 132 yield IncompleteString(s, start, end, lines[-1])
133 133 elif 'multi-line statement' in e.args[0]:
134 134 yield InMultilineStatement(end, lines[-1])
135 135 else:
136 136 raise
137 137
138 138 def find_next_indent(code):
139 139 """Find the number of spaces for the next line of indentation"""
140 140 tokens = list(partial_tokens(code))
141 141 if tokens[-1].type == tokenize.ENDMARKER:
142 142 tokens.pop()
143 143 if not tokens:
144 144 return 0
145 145 if tokens[-1].type in {tokenize.DEDENT, tokenize.NEWLINE, tokenize.COMMENT}:
146 146 tokens.pop()
147 147
148 148 if tokens[-1].type == INCOMPLETE_STRING:
149 149 # Inside a multiline string
150 150 return 0
151 151
152 152 # Find the indents used before
153 153 prev_indents = [0]
154 154 def _add_indent(n):
155 155 if n != prev_indents[-1]:
156 156 prev_indents.append(n)
157 157
158 158 tokiter = iter(tokens)
159 159 for tok in tokiter:
160 160 if tok.type in {tokenize.INDENT, tokenize.DEDENT}:
161 161 _add_indent(tok.end[1])
162 162 elif (tok.type == tokenize.NL):
163 163 try:
164 164 _add_indent(next(tokiter).start[1])
165 165 except StopIteration:
166 166 break
167 167
168 168 last_indent = prev_indents.pop()
169 169
170 170 if tokens[-1].type == IN_MULTILINE_STATEMENT:
171 171 if tokens[-2].exact_type in {tokenize.LPAR, tokenize.LSQB, tokenize.LBRACE}:
172 172 return last_indent + 4
173 173 return last_indent
174 174
175 175 if tokens[-1].exact_type == tokenize.COLON:
176 176 # Line ends with colon - indent
177 177 return last_indent + 4
178 178
179 179 if last_indent:
180 180 # Examine the last line for dedent cues - statements like return or
181 181 # raise which normally end a block of code.
182 182 last_line_starts = 0
183 183 for i, tok in enumerate(tokens):
184 184 if tok.type == tokenize.NEWLINE:
185 185 last_line_starts = i + 1
186 186
187 187 last_line_tokens = tokens[last_line_starts:]
188 188 names = [t.string for t in last_line_tokens if t.type == tokenize.NAME]
189 189 if names and names[0] in {'raise', 'return', 'pass', 'break', 'continue'}:
190 190 # Find the most recent indentation less than the current level
191 191 for indent in reversed(prev_indents):
192 192 if indent < last_indent:
193 193 return indent
194 194
195 195 return last_indent
196 196
197 197
198 198 def last_blank(src):
199 199 """Determine if the input source ends in a blank.
200 200
201 201 A blank is either a newline or a line consisting of whitespace.
202 202
203 203 Parameters
204 204 ----------
205 205 src : string
206 206 A single or multiline string.
207 207 """
208 208 if not src: return False
209 209 ll = src.splitlines()[-1]
210 210 return (ll == '') or ll.isspace()
211 211
212 212
213 213 last_two_blanks_re = re.compile(r'\n\s*\n\s*$', re.MULTILINE)
214 214 last_two_blanks_re2 = re.compile(r'.+\n\s*\n\s+$', re.MULTILINE)
215 215
216 216 def last_two_blanks(src):
217 217 """Determine if the input source ends in two blanks.
218 218
219 219 A blank is either a newline or a line consisting of whitespace.
220 220
221 221 Parameters
222 222 ----------
223 223 src : string
224 224 A single or multiline string.
225 225 """
226 226 if not src: return False
227 227 # The logic here is tricky: I couldn't get a regexp to work and pass all
228 228 # the tests, so I took a different approach: split the source by lines,
229 229 # grab the last two and prepend '###\n' as a stand-in for whatever was in
230 230 # the body before the last two lines. Then, with that structure, it's
231 231 # possible to analyze with two regexps. Not the most elegant solution, but
232 232 # it works. If anyone tries to change this logic, make sure to validate
233 233 # the whole test suite first!
234 234 new_src = '\n'.join(['###\n'] + src.splitlines()[-2:])
235 235 return (bool(last_two_blanks_re.match(new_src)) or
236 236 bool(last_two_blanks_re2.match(new_src)) )
237 237
238 238
239 239 def remove_comments(src):
240 240 """Remove all comments from input source.
241 241
242 242 Note: comments are NOT recognized inside of strings!
243 243
244 244 Parameters
245 245 ----------
246 246 src : string
247 247 A single or multiline input string.
248 248
249 249 Returns
250 250 -------
251 251 String with all Python comments removed.
252 252 """
253 253
254 254 return re.sub('#.*', '', src)
255 255
256 256
257 257 def get_input_encoding():
258 258 """Return the default standard input encoding.
259 259
260 260 If sys.stdin has no encoding, 'ascii' is returned."""
261 261 # There are strange environments for which sys.stdin.encoding is None. We
262 262 # ensure that a valid encoding is returned.
263 263 encoding = getattr(sys.stdin, 'encoding', None)
264 264 if encoding is None:
265 265 encoding = 'ascii'
266 266 return encoding
267 267
268 268 #-----------------------------------------------------------------------------
269 269 # Classes and functions for normal Python syntax handling
270 270 #-----------------------------------------------------------------------------
271 271
272 272 class InputSplitter(object):
273 273 r"""An object that can accumulate lines of Python source before execution.
274 274
275 275 This object is designed to be fed python source line-by-line, using
276 276 :meth:`push`. It will return on each push whether the currently pushed
277 277 code could be executed already. In addition, it provides a method called
278 278 :meth:`push_accepts_more` that can be used to query whether more input
279 279 can be pushed into a single interactive block.
280 280
281 281 This is a simple example of how an interactive terminal-based client can use
282 282 this tool::
283 283
284 284 isp = InputSplitter()
285 285 while isp.push_accepts_more():
286 286 indent = ' '*isp.indent_spaces
287 287 prompt = '>>> ' + indent
288 288 line = indent + raw_input(prompt)
289 289 isp.push(line)
290 290 print 'Input source was:\n', isp.source_reset(),
291 291 """
292 292 # Number of spaces of indentation computed from input that has been pushed
293 293 # so far. This is the attributes callers should query to get the current
294 294 # indentation level, in order to provide auto-indent facilities.
295 295 indent_spaces = 0
296 296 # String, indicating the default input encoding. It is computed by default
297 297 # at initialization time via get_input_encoding(), but it can be reset by a
298 298 # client with specific knowledge of the encoding.
299 299 encoding = ''
300 300 # String where the current full source input is stored, properly encoded.
301 301 # Reading this attribute is the normal way of querying the currently pushed
302 302 # source code, that has been properly encoded.
303 303 source = ''
304 304 # Code object corresponding to the current source. It is automatically
305 305 # synced to the source, so it can be queried at any time to obtain the code
306 306 # object; it will be None if the source doesn't compile to valid Python.
307 307 code = None
308 308
309 309 # Private attributes
310 310
311 311 # List with lines of input accumulated so far
312 312 _buffer = None
313 313 # Command compiler
314 314 _compile = None
315 315 # Mark when input has changed indentation all the way back to flush-left
316 316 _full_dedent = False
317 317 # Boolean indicating whether the current block is complete
318 318 _is_complete = None
319 319 # Boolean indicating whether the current block has an unrecoverable syntax error
320 320 _is_invalid = False
321 321
322 322 def __init__(self):
323 323 """Create a new InputSplitter instance.
324 324 """
325 325 self._buffer = []
326 326 self._compile = codeop.CommandCompiler()
327 327 self.encoding = get_input_encoding()
328 328
329 329 def reset(self):
330 330 """Reset the input buffer and associated state."""
331 331 self.indent_spaces = 0
332 332 self._buffer[:] = []
333 333 self.source = ''
334 334 self.code = None
335 335 self._is_complete = False
336 336 self._is_invalid = False
337 337 self._full_dedent = False
338 338
339 339 def source_reset(self):
340 340 """Return the input source and perform a full reset.
341 341 """
342 342 out = self.source
343 343 self.reset()
344 344 return out
345 345
346 346 def check_complete(self, source):
347 347 """Return whether a block of code is ready to execute, or should be continued
348 348
349 349 This is a non-stateful API, and will reset the state of this InputSplitter.
350 350
351 351 Parameters
352 352 ----------
353 353 source : string
354 354 Python input code, which can be multiline.
355 355
356 356 Returns
357 357 -------
358 358 status : str
359 359 One of 'complete', 'incomplete', or 'invalid' if source is not a
360 360 prefix of valid code.
361 361 indent_spaces : int or None
362 362 The number of spaces by which to indent the next line of code. If
363 363 status is not 'incomplete', this is None.
364 364 """
365 365 self.reset()
366 366 try:
367 367 self.push(source)
368 368 except SyntaxError:
369 369 # Transformers in IPythonInputSplitter can raise SyntaxError,
370 370 # which push() will not catch.
371 371 return 'invalid', None
372 372 else:
373 373 if self._is_invalid:
374 374 return 'invalid', None
375 375 elif self.push_accepts_more():
376 376 return 'incomplete', self.indent_spaces
377 377 else:
378 378 return 'complete', None
379 379 finally:
380 380 self.reset()
381 381
382 382 def push(self, lines):
383 383 """Push one or more lines of input.
384 384
385 385 This stores the given lines and returns a status code indicating
386 386 whether the code forms a complete Python block or not.
387 387
388 388 Any exceptions generated in compilation are swallowed, but if an
389 389 exception was produced, the method returns True.
390 390
391 391 Parameters
392 392 ----------
393 393 lines : string
394 394 One or more lines of Python input.
395 395
396 396 Returns
397 397 -------
398 398 is_complete : boolean
399 399 True if the current input source (the result of the current input
400 400 plus prior inputs) forms a complete Python execution block. Note that
401 401 this value is also stored as a private attribute (``_is_complete``), so it
402 402 can be queried at any time.
403 403 """
404 404 self._store(lines)
405 405 source = self.source
406 406
407 407 # Before calling _compile(), reset the code object to None so that if an
408 408 # exception is raised in compilation, we don't mislead by having
409 409 # inconsistent code/source attributes.
410 410 self.code, self._is_complete = None, None
411 411 self._is_invalid = False
412 412
413 413 # Honor termination lines properly
414 414 if source.endswith('\\\n'):
415 415 return False
416 416
417 417 self._update_indent()
418 418 try:
419 419 with warnings.catch_warnings():
420 420 warnings.simplefilter('error', SyntaxWarning)
421 421 self.code = self._compile(source, symbol="exec")
422 422 # Invalid syntax can produce any of a number of different errors from
423 423 # inside the compiler, so we have to catch them all. Syntax errors
424 424 # immediately produce a 'ready' block, so the invalid Python can be
425 425 # sent to the kernel for evaluation with possible ipython
426 426 # special-syntax conversion.
427 427 except (SyntaxError, OverflowError, ValueError, TypeError,
428 428 MemoryError, SyntaxWarning):
429 429 self._is_complete = True
430 430 self._is_invalid = True
431 431 else:
432 432 # Compilation didn't produce any exceptions (though it may not have
433 433 # given a complete code object)
434 434 self._is_complete = self.code is not None
435 435
436 436 return self._is_complete
437 437
438 438 def push_accepts_more(self):
439 439 """Return whether a block of interactive input can accept more input.
440 440
441 441 This method is meant to be used by line-oriented frontends, who need to
442 442 guess whether a block is complete or not based solely on prior and
443 443 current input lines. The InputSplitter considers it has a complete
444 444 interactive block and will not accept more input when either:
445 445
446 446 * A SyntaxError is raised
447 447
448 448 * The code is complete and consists of a single line or a single
449 449 non-compound statement
450 450
451 451 * The code is complete and has a blank line at the end
452 452
453 453 If the current input produces a syntax error, this method immediately
454 454 returns False but does *not* raise the syntax error exception, as
455 455 typically clients will want to send invalid syntax to an execution
456 456 backend which might convert the invalid syntax into valid Python via
457 457 one of the dynamic IPython mechanisms.
458 458 """
459 459
460 460 # With incomplete input, unconditionally accept more
461 461 # A syntax error also sets _is_complete to True - see push()
462 462 if not self._is_complete:
463 463 #print("Not complete") # debug
464 464 return True
465 465
466 466 # The user can make any (complete) input execute by leaving a blank line
467 467 last_line = self.source.splitlines()[-1]
468 468 if (not last_line) or last_line.isspace():
469 469 #print("Blank line") # debug
470 470 return False
471 471
472 472 # If there's just a single line or AST node, and we're flush left, as is
473 473 # the case after a simple statement such as 'a=1', we want to execute it
474 474 # straight away.
475 475 if self.indent_spaces==0:
476 476 if len(self.source.splitlines()) <= 1:
477 477 return False
478 478
479 479 try:
480 480 code_ast = ast.parse(u''.join(self._buffer))
481 481 except Exception:
482 482 #print("Can't parse AST") # debug
483 483 return False
484 484 else:
485 485 if len(code_ast.body) == 1 and \
486 486 not hasattr(code_ast.body[0], 'body'):
487 487 #print("Simple statement") # debug
488 488 return False
489 489
490 490 # General fallback - accept more code
491 491 return True
492 492
493 #------------------------------------------------------------------------
494 # Private interface
495 #------------------------------------------------------------------------
496
497 def _find_indent(self, line):
498 """Compute the new indentation level for a single line.
499
500 Parameters
501 ----------
502 line : str
503 A single new line of non-whitespace, non-comment Python input.
504
505 Returns
506 -------
507 indent_spaces : int
508 New value for the indent level (it may be equal to self.indent_spaces
509 if indentation doesn't change.
510
511 full_dedent : boolean
512 Whether the new line causes a full flush-left dedent.
513 """
514 indent_spaces = self.indent_spaces
515 full_dedent = self._full_dedent
516
517 inisp = num_ini_spaces(line)
518 if inisp < indent_spaces:
519 indent_spaces = inisp
520 if indent_spaces <= 0:
521 #print 'Full dedent in text',self.source # dbg
522 full_dedent = True
523
524 if line.rstrip()[-1] == ':':
525 indent_spaces += 4
526 elif dedent_re.match(line):
527 indent_spaces -= 4
528 if indent_spaces <= 0:
529 full_dedent = True
530
531 # Safety
532 if indent_spaces < 0:
533 indent_spaces = 0
534 #print 'safety' # dbg
535
536 return indent_spaces, full_dedent
537
538 493 def _update_indent(self):
539 494 # self.source always has a trailing newline
540 495 self.indent_spaces = find_next_indent(self.source[:-1])
541 496 self._full_dedent = (self.indent_spaces == 0)
542 497
543 498 def _store(self, lines, buffer=None, store='source'):
544 499 """Store one or more lines of input.
545 500
546 501 If input lines are not newline-terminated, a newline is automatically
547 502 appended."""
548 503
549 504 if buffer is None:
550 505 buffer = self._buffer
551 506
552 507 if lines.endswith('\n'):
553 508 buffer.append(lines)
554 509 else:
555 510 buffer.append(lines+'\n')
556 511 setattr(self, store, self._set_source(buffer))
557 512
558 513 def _set_source(self, buffer):
559 514 return u''.join(buffer)
560 515
561 516
562 517 class IPythonInputSplitter(InputSplitter):
563 518 """An input splitter that recognizes all of IPython's special syntax."""
564 519
565 520 # String with raw, untransformed input.
566 521 source_raw = ''
567 522
568 523 # Flag to track when a transformer has stored input that it hasn't given
569 524 # back yet.
570 525 transformer_accumulating = False
571 526
572 527 # Flag to track when assemble_python_lines has stored input that it hasn't
573 528 # given back yet.
574 529 within_python_line = False
575 530
576 531 # Private attributes
577 532
578 533 # List with lines of raw input accumulated so far.
579 534 _buffer_raw = None
580 535
581 536 def __init__(self, line_input_checker=True, physical_line_transforms=None,
582 537 logical_line_transforms=None, python_line_transforms=None):
583 538 super(IPythonInputSplitter, self).__init__()
584 539 self._buffer_raw = []
585 540 self._validate = True
586 541
587 542 if physical_line_transforms is not None:
588 543 self.physical_line_transforms = physical_line_transforms
589 544 else:
590 545 self.physical_line_transforms = [
591 546 leading_indent(),
592 547 classic_prompt(),
593 548 ipy_prompt(),
594 549 cellmagic(end_on_blank_line=line_input_checker),
595 550 ]
596 551
597 552 self.assemble_logical_lines = assemble_logical_lines()
598 553 if logical_line_transforms is not None:
599 554 self.logical_line_transforms = logical_line_transforms
600 555 else:
601 556 self.logical_line_transforms = [
602 557 help_end(),
603 558 escaped_commands(),
604 559 assign_from_magic(),
605 560 assign_from_system(),
606 561 ]
607 562
608 563 self.assemble_python_lines = assemble_python_lines()
609 564 if python_line_transforms is not None:
610 565 self.python_line_transforms = python_line_transforms
611 566 else:
612 567 # We don't use any of these at present
613 568 self.python_line_transforms = []
614 569
615 570 @property
616 571 def transforms(self):
617 572 "Quick access to all transformers."
618 573 return self.physical_line_transforms + \
619 574 [self.assemble_logical_lines] + self.logical_line_transforms + \
620 575 [self.assemble_python_lines] + self.python_line_transforms
621 576
622 577 @property
623 578 def transforms_in_use(self):
624 579 """Transformers, excluding logical line transformers if we're in a
625 580 Python line."""
626 581 t = self.physical_line_transforms[:]
627 582 if not self.within_python_line:
628 583 t += [self.assemble_logical_lines] + self.logical_line_transforms
629 584 return t + [self.assemble_python_lines] + self.python_line_transforms
630 585
631 586 def reset(self):
632 587 """Reset the input buffer and associated state."""
633 588 super(IPythonInputSplitter, self).reset()
634 589 self._buffer_raw[:] = []
635 590 self.source_raw = ''
636 591 self.transformer_accumulating = False
637 592 self.within_python_line = False
638 593
639 594 for t in self.transforms:
640 595 try:
641 596 t.reset()
642 597 except SyntaxError:
643 598 # Nothing that calls reset() expects to handle transformer
644 599 # errors
645 600 pass
646 601
647 602 def flush_transformers(self):
648 603 def _flush(transform, outs):
649 604 """yield transformed lines
650 605
651 606 always strings, never None
652 607
653 608 transform: the current transform
654 609 outs: an iterable of previously transformed inputs.
655 610 Each may be multiline, which will be passed
656 611 one line at a time to transform.
657 612 """
658 613 for out in outs:
659 614 for line in out.splitlines():
660 615 # push one line at a time
661 616 tmp = transform.push(line)
662 617 if tmp is not None:
663 618 yield tmp
664 619
665 620 # reset the transform
666 621 tmp = transform.reset()
667 622 if tmp is not None:
668 623 yield tmp
669 624
670 625 out = []
671 626 for t in self.transforms_in_use:
672 627 out = _flush(t, out)
673 628
674 629 out = list(out)
675 630 if out:
676 631 self._store('\n'.join(out))
677 632
678 633 def raw_reset(self):
679 634 """Return raw input only and perform a full reset.
680 635 """
681 636 out = self.source_raw
682 637 self.reset()
683 638 return out
684 639
685 640 def source_reset(self):
686 641 try:
687 642 self.flush_transformers()
688 643 return self.source
689 644 finally:
690 645 self.reset()
691 646
692 647 def push_accepts_more(self):
693 648 if self.transformer_accumulating:
694 649 return True
695 650 else:
696 651 return super(IPythonInputSplitter, self).push_accepts_more()
697 652
698 653 def transform_cell(self, cell):
699 654 """Process and translate a cell of input.
700 655 """
701 656 self.reset()
702 657 try:
703 658 self.push(cell)
704 659 self.flush_transformers()
705 660 return self.source
706 661 finally:
707 662 self.reset()
708 663
709 664 def push(self, lines):
710 665 """Push one or more lines of IPython input.
711 666
712 667 This stores the given lines and returns a status code indicating
713 668 whether the code forms a complete Python block or not, after processing
714 669 all input lines for special IPython syntax.
715 670
716 671 Any exceptions generated in compilation are swallowed, but if an
717 672 exception was produced, the method returns True.
718 673
719 674 Parameters
720 675 ----------
721 676 lines : string
722 677 One or more lines of Python input.
723 678
724 679 Returns
725 680 -------
726 681 is_complete : boolean
727 682 True if the current input source (the result of the current input
728 683 plus prior inputs) forms a complete Python execution block. Note that
729 684 this value is also stored as a private attribute (_is_complete), so it
730 685 can be queried at any time.
731 686 """
732 687
733 688 # We must ensure all input is pure unicode
734 689 lines = cast_unicode(lines, self.encoding)
735 690 # ''.splitlines() --> [], but we need to push the empty line to transformers
736 691 lines_list = lines.splitlines()
737 692 if not lines_list:
738 693 lines_list = ['']
739 694
740 695 # Store raw source before applying any transformations to it. Note
741 696 # that this must be done *after* the reset() call that would otherwise
742 697 # flush the buffer.
743 698 self._store(lines, self._buffer_raw, 'source_raw')
744 699
745 700 for line in lines_list:
746 701 out = self.push_line(line)
747 702
748 703 return out
749 704
750 705 def push_line(self, line):
751 706 buf = self._buffer
752 707
753 708 def _accumulating(dbg):
754 709 #print(dbg)
755 710 self.transformer_accumulating = True
756 711 return False
757 712
758 713 for transformer in self.physical_line_transforms:
759 714 line = transformer.push(line)
760 715 if line is None:
761 716 return _accumulating(transformer)
762 717
763 718 if not self.within_python_line:
764 719 line = self.assemble_logical_lines.push(line)
765 720 if line is None:
766 721 return _accumulating('acc logical line')
767 722
768 723 for transformer in self.logical_line_transforms:
769 724 line = transformer.push(line)
770 725 if line is None:
771 726 return _accumulating(transformer)
772 727
773 728 line = self.assemble_python_lines.push(line)
774 729 if line is None:
775 730 self.within_python_line = True
776 731 return _accumulating('acc python line')
777 732 else:
778 733 self.within_python_line = False
779 734
780 735 for transformer in self.python_line_transforms:
781 736 line = transformer.push(line)
782 737 if line is None:
783 738 return _accumulating(transformer)
784 739
785 740 #print("transformers clear") #debug
786 741 self.transformer_accumulating = False
787 742 return super(IPythonInputSplitter, self).push(line)
General Comments 0
You need to be logged in to leave comments. Login now