##// END OF EJS Templates
Avoid trying to compile the code after each line
Thomas Kluyver -
Show More
@@ -1,744 +1,759 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 while (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 we've just opened a multiline statement (e.g. 'a = ['), indent more
171 171 if tokens[-1].type == IN_MULTILINE_STATEMENT:
172 172 if tokens[-2].exact_type in {tokenize.LPAR, tokenize.LSQB, tokenize.LBRACE}:
173 173 return last_indent + 4
174 174 return last_indent
175 175
176 176 if tokens[-1].exact_type == tokenize.COLON:
177 177 # Line ends with colon - indent
178 178 return last_indent + 4
179 179
180 180 if last_indent:
181 181 # Examine the last line for dedent cues - statements like return or
182 182 # raise which normally end a block of code.
183 183 last_line_starts = 0
184 184 for i, tok in enumerate(tokens):
185 185 if tok.type == tokenize.NEWLINE:
186 186 last_line_starts = i + 1
187 187
188 188 last_line_tokens = tokens[last_line_starts:]
189 189 names = [t.string for t in last_line_tokens if t.type == tokenize.NAME]
190 190 if names and names[0] in {'raise', 'return', 'pass', 'break', 'continue'}:
191 191 # Find the most recent indentation less than the current level
192 192 for indent in reversed(prev_indents):
193 193 if indent < last_indent:
194 194 return indent
195 195
196 196 return last_indent
197 197
198 198
199 199 def last_blank(src):
200 200 """Determine if the input source ends in a blank.
201 201
202 202 A blank is either a newline or a line consisting of whitespace.
203 203
204 204 Parameters
205 205 ----------
206 206 src : string
207 207 A single or multiline string.
208 208 """
209 209 if not src: return False
210 210 ll = src.splitlines()[-1]
211 211 return (ll == '') or ll.isspace()
212 212
213 213
214 214 last_two_blanks_re = re.compile(r'\n\s*\n\s*$', re.MULTILINE)
215 215 last_two_blanks_re2 = re.compile(r'.+\n\s*\n\s+$', re.MULTILINE)
216 216
217 217 def last_two_blanks(src):
218 218 """Determine if the input source ends in two blanks.
219 219
220 220 A blank is either a newline or a line consisting of whitespace.
221 221
222 222 Parameters
223 223 ----------
224 224 src : string
225 225 A single or multiline string.
226 226 """
227 227 if not src: return False
228 228 # The logic here is tricky: I couldn't get a regexp to work and pass all
229 229 # the tests, so I took a different approach: split the source by lines,
230 230 # grab the last two and prepend '###\n' as a stand-in for whatever was in
231 231 # the body before the last two lines. Then, with that structure, it's
232 232 # possible to analyze with two regexps. Not the most elegant solution, but
233 233 # it works. If anyone tries to change this logic, make sure to validate
234 234 # the whole test suite first!
235 235 new_src = '\n'.join(['###\n'] + src.splitlines()[-2:])
236 236 return (bool(last_two_blanks_re.match(new_src)) or
237 237 bool(last_two_blanks_re2.match(new_src)) )
238 238
239 239
240 240 def remove_comments(src):
241 241 """Remove all comments from input source.
242 242
243 243 Note: comments are NOT recognized inside of strings!
244 244
245 245 Parameters
246 246 ----------
247 247 src : string
248 248 A single or multiline input string.
249 249
250 250 Returns
251 251 -------
252 252 String with all Python comments removed.
253 253 """
254 254
255 255 return re.sub('#.*', '', src)
256 256
257 257
258 258 def get_input_encoding():
259 259 """Return the default standard input encoding.
260 260
261 261 If sys.stdin has no encoding, 'ascii' is returned."""
262 262 # There are strange environments for which sys.stdin.encoding is None. We
263 263 # ensure that a valid encoding is returned.
264 264 encoding = getattr(sys.stdin, 'encoding', None)
265 265 if encoding is None:
266 266 encoding = 'ascii'
267 267 return encoding
268 268
269 269 #-----------------------------------------------------------------------------
270 270 # Classes and functions for normal Python syntax handling
271 271 #-----------------------------------------------------------------------------
272 272
273 273 class InputSplitter(object):
274 274 r"""An object that can accumulate lines of Python source before execution.
275 275
276 276 This object is designed to be fed python source line-by-line, using
277 277 :meth:`push`. It will return on each push whether the currently pushed
278 278 code could be executed already. In addition, it provides a method called
279 279 :meth:`push_accepts_more` that can be used to query whether more input
280 280 can be pushed into a single interactive block.
281 281
282 282 This is a simple example of how an interactive terminal-based client can use
283 283 this tool::
284 284
285 285 isp = InputSplitter()
286 286 while isp.push_accepts_more():
287 287 indent = ' '*isp.indent_spaces
288 288 prompt = '>>> ' + indent
289 289 line = indent + raw_input(prompt)
290 290 isp.push(line)
291 291 print 'Input source was:\n', isp.source_reset(),
292 292 """
293 293 # A cache for calculating the current indentation.
294 294 # If the first value matches self.source, the second value is an integer
295 295 # number of spaces for the current indentation. If the first value does not
296 296 # match, self.source has changed, and the indentation must be recalculated.
297 297 _indent_spaces_cache = None, None
298 298 # String, indicating the default input encoding. It is computed by default
299 299 # at initialization time via get_input_encoding(), but it can be reset by a
300 300 # client with specific knowledge of the encoding.
301 301 encoding = ''
302 302 # String where the current full source input is stored, properly encoded.
303 303 # Reading this attribute is the normal way of querying the currently pushed
304 304 # source code, that has been properly encoded.
305 305 source = ''
306 306 # Code object corresponding to the current source. It is automatically
307 307 # synced to the source, so it can be queried at any time to obtain the code
308 308 # object; it will be None if the source doesn't compile to valid Python.
309 309 code = None
310 310
311 311 # Private attributes
312 312
313 313 # List with lines of input accumulated so far
314 314 _buffer = None
315 315 # Command compiler
316 316 _compile = None
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._buffer[:] = []
332 332 self.source = ''
333 333 self.code = None
334 334 self._is_complete = False
335 335 self._is_invalid = False
336 336
337 337 def source_reset(self):
338 338 """Return the input source and perform a full reset.
339 339 """
340 340 out = self.source
341 341 self.reset()
342 342 return out
343 343
344 344 def check_complete(self, source):
345 345 """Return whether a block of code is ready to execute, or should be continued
346 346
347 347 This is a non-stateful API, and will reset the state of this InputSplitter.
348 348
349 349 Parameters
350 350 ----------
351 351 source : string
352 352 Python input code, which can be multiline.
353 353
354 354 Returns
355 355 -------
356 356 status : str
357 357 One of 'complete', 'incomplete', or 'invalid' if source is not a
358 358 prefix of valid code.
359 359 indent_spaces : int or None
360 360 The number of spaces by which to indent the next line of code. If
361 361 status is not 'incomplete', this is None.
362 362 """
363 363 self.reset()
364 364 try:
365 365 self.push(source)
366 366 except SyntaxError:
367 367 # Transformers in IPythonInputSplitter can raise SyntaxError,
368 368 # which push() will not catch.
369 369 return 'invalid', None
370 370 else:
371 371 if self._is_invalid:
372 372 return 'invalid', None
373 373 elif self.push_accepts_more():
374 374 return 'incomplete', self.get_indent_spaces()
375 375 else:
376 376 return 'complete', None
377 377 finally:
378 378 self.reset()
379 379
380 380 def push(self, lines):
381 381 """Push one or more lines of input.
382 382
383 383 This stores the given lines and returns a status code indicating
384 384 whether the code forms a complete Python block or not.
385 385
386 386 Any exceptions generated in compilation are swallowed, but if an
387 387 exception was produced, the method returns True.
388 388
389 389 Parameters
390 390 ----------
391 391 lines : string
392 392 One or more lines of Python input.
393 393
394 394 Returns
395 395 -------
396 396 is_complete : boolean
397 397 True if the current input source (the result of the current input
398 398 plus prior inputs) forms a complete Python execution block. Note that
399 399 this value is also stored as a private attribute (``_is_complete``), so it
400 400 can be queried at any time.
401 401 """
402 402 self._store(lines)
403 403 source = self.source
404 404
405 405 # Before calling _compile(), reset the code object to None so that if an
406 406 # exception is raised in compilation, we don't mislead by having
407 407 # inconsistent code/source attributes.
408 408 self.code, self._is_complete = None, None
409 409 self._is_invalid = False
410 410
411 411 # Honor termination lines properly
412 412 if source.endswith('\\\n'):
413 413 return False
414 414
415 415 try:
416 416 with warnings.catch_warnings():
417 417 warnings.simplefilter('error', SyntaxWarning)
418 418 self.code = self._compile(source, symbol="exec")
419 419 # Invalid syntax can produce any of a number of different errors from
420 420 # inside the compiler, so we have to catch them all. Syntax errors
421 421 # immediately produce a 'ready' block, so the invalid Python can be
422 422 # sent to the kernel for evaluation with possible ipython
423 423 # special-syntax conversion.
424 424 except (SyntaxError, OverflowError, ValueError, TypeError,
425 425 MemoryError, SyntaxWarning):
426 426 self._is_complete = True
427 427 self._is_invalid = True
428 428 else:
429 429 # Compilation didn't produce any exceptions (though it may not have
430 430 # given a complete code object)
431 431 self._is_complete = self.code is not None
432 432
433 433 return self._is_complete
434 434
435 435 def push_accepts_more(self):
436 436 """Return whether a block of interactive input can accept more input.
437 437
438 438 This method is meant to be used by line-oriented frontends, who need to
439 439 guess whether a block is complete or not based solely on prior and
440 440 current input lines. The InputSplitter considers it has a complete
441 441 interactive block and will not accept more input when either:
442 442
443 443 * A SyntaxError is raised
444 444
445 445 * The code is complete and consists of a single line or a single
446 446 non-compound statement
447 447
448 448 * The code is complete and has a blank line at the end
449 449
450 450 If the current input produces a syntax error, this method immediately
451 451 returns False but does *not* raise the syntax error exception, as
452 452 typically clients will want to send invalid syntax to an execution
453 453 backend which might convert the invalid syntax into valid Python via
454 454 one of the dynamic IPython mechanisms.
455 455 """
456 456
457 457 # With incomplete input, unconditionally accept more
458 458 # A syntax error also sets _is_complete to True - see push()
459 459 if not self._is_complete:
460 460 #print("Not complete") # debug
461 461 return True
462 462
463 463 # The user can make any (complete) input execute by leaving a blank line
464 464 last_line = self.source.splitlines()[-1]
465 465 if (not last_line) or last_line.isspace():
466 466 #print("Blank line") # debug
467 467 return False
468 468
469 469 # If there's just a single line or AST node, and we're flush left, as is
470 470 # the case after a simple statement such as 'a=1', we want to execute it
471 471 # straight away.
472 472 if self.get_indent_spaces() == 0:
473 473 if len(self.source.splitlines()) <= 1:
474 474 return False
475 475
476 476 try:
477 477 code_ast = ast.parse(u''.join(self._buffer))
478 478 except Exception:
479 479 #print("Can't parse AST") # debug
480 480 return False
481 481 else:
482 482 if len(code_ast.body) == 1 and \
483 483 not hasattr(code_ast.body[0], 'body'):
484 484 #print("Simple statement") # debug
485 485 return False
486 486
487 487 # General fallback - accept more code
488 488 return True
489 489
490 490 def get_indent_spaces(self):
491 491 sourcefor, n = self._indent_spaces_cache
492 492 if sourcefor == self.source:
493 493 return n
494 494
495 495 # self.source always has a trailing newline
496 496 n = find_next_indent(self.source[:-1])
497 497 self._indent_spaces_cache = (self.source, n)
498 498 return n
499 499
500 500 def _store(self, lines, buffer=None, store='source'):
501 501 """Store one or more lines of input.
502 502
503 503 If input lines are not newline-terminated, a newline is automatically
504 504 appended."""
505 505
506 506 if buffer is None:
507 507 buffer = self._buffer
508 508
509 509 if lines.endswith('\n'):
510 510 buffer.append(lines)
511 511 else:
512 512 buffer.append(lines+'\n')
513 513 setattr(self, store, self._set_source(buffer))
514 514
515 515 def _set_source(self, buffer):
516 516 return u''.join(buffer)
517 517
518 518
519 519 class IPythonInputSplitter(InputSplitter):
520 520 """An input splitter that recognizes all of IPython's special syntax."""
521 521
522 522 # String with raw, untransformed input.
523 523 source_raw = ''
524 524
525 525 # Flag to track when a transformer has stored input that it hasn't given
526 526 # back yet.
527 527 transformer_accumulating = False
528 528
529 529 # Flag to track when assemble_python_lines has stored input that it hasn't
530 530 # given back yet.
531 531 within_python_line = False
532 532
533 533 # Private attributes
534 534
535 535 # List with lines of raw input accumulated so far.
536 536 _buffer_raw = None
537 537
538 538 def __init__(self, line_input_checker=True, physical_line_transforms=None,
539 539 logical_line_transforms=None, python_line_transforms=None):
540 540 super(IPythonInputSplitter, self).__init__()
541 541 self._buffer_raw = []
542 542 self._validate = True
543 543
544 544 if physical_line_transforms is not None:
545 545 self.physical_line_transforms = physical_line_transforms
546 546 else:
547 547 self.physical_line_transforms = [
548 548 leading_indent(),
549 549 classic_prompt(),
550 550 ipy_prompt(),
551 551 cellmagic(end_on_blank_line=line_input_checker),
552 552 ]
553 553
554 554 self.assemble_logical_lines = assemble_logical_lines()
555 555 if logical_line_transforms is not None:
556 556 self.logical_line_transforms = logical_line_transforms
557 557 else:
558 558 self.logical_line_transforms = [
559 559 help_end(),
560 560 escaped_commands(),
561 561 assign_from_magic(),
562 562 assign_from_system(),
563 563 ]
564 564
565 565 self.assemble_python_lines = assemble_python_lines()
566 566 if python_line_transforms is not None:
567 567 self.python_line_transforms = python_line_transforms
568 568 else:
569 569 # We don't use any of these at present
570 570 self.python_line_transforms = []
571 571
572 572 @property
573 573 def transforms(self):
574 574 "Quick access to all transformers."
575 575 return self.physical_line_transforms + \
576 576 [self.assemble_logical_lines] + self.logical_line_transforms + \
577 577 [self.assemble_python_lines] + self.python_line_transforms
578 578
579 579 @property
580 580 def transforms_in_use(self):
581 581 """Transformers, excluding logical line transformers if we're in a
582 582 Python line."""
583 583 t = self.physical_line_transforms[:]
584 584 if not self.within_python_line:
585 585 t += [self.assemble_logical_lines] + self.logical_line_transforms
586 586 return t + [self.assemble_python_lines] + self.python_line_transforms
587 587
588 588 def reset(self):
589 589 """Reset the input buffer and associated state."""
590 590 super(IPythonInputSplitter, self).reset()
591 591 self._buffer_raw[:] = []
592 592 self.source_raw = ''
593 593 self.transformer_accumulating = False
594 594 self.within_python_line = False
595 595
596 596 for t in self.transforms:
597 597 try:
598 598 t.reset()
599 599 except SyntaxError:
600 600 # Nothing that calls reset() expects to handle transformer
601 601 # errors
602 602 pass
603 603
604 604 def flush_transformers(self):
605 605 def _flush(transform, outs):
606 606 """yield transformed lines
607 607
608 608 always strings, never None
609 609
610 610 transform: the current transform
611 611 outs: an iterable of previously transformed inputs.
612 612 Each may be multiline, which will be passed
613 613 one line at a time to transform.
614 614 """
615 615 for out in outs:
616 616 for line in out.splitlines():
617 617 # push one line at a time
618 618 tmp = transform.push(line)
619 619 if tmp is not None:
620 620 yield tmp
621 621
622 622 # reset the transform
623 623 tmp = transform.reset()
624 624 if tmp is not None:
625 625 yield tmp
626 626
627 627 out = []
628 628 for t in self.transforms_in_use:
629 629 out = _flush(t, out)
630 630
631 631 out = list(out)
632 632 if out:
633 633 self._store('\n'.join(out))
634 634
635 635 def raw_reset(self):
636 636 """Return raw input only and perform a full reset.
637 637 """
638 638 out = self.source_raw
639 639 self.reset()
640 640 return out
641 641
642 642 def source_reset(self):
643 643 try:
644 644 self.flush_transformers()
645 645 return self.source
646 646 finally:
647 647 self.reset()
648 648
649 649 def push_accepts_more(self):
650 650 if self.transformer_accumulating:
651 651 return True
652 652 else:
653 653 return super(IPythonInputSplitter, self).push_accepts_more()
654 654
655 655 def transform_cell(self, cell):
656 656 """Process and translate a cell of input.
657 657 """
658 658 self.reset()
659 659 try:
660 660 self.push(cell)
661 661 self.flush_transformers()
662 662 return self.source
663 663 finally:
664 664 self.reset()
665 665
666 666 def push(self, lines):
667 667 """Push one or more lines of IPython input.
668 668
669 669 This stores the given lines and returns a status code indicating
670 670 whether the code forms a complete Python block or not, after processing
671 671 all input lines for special IPython syntax.
672 672
673 673 Any exceptions generated in compilation are swallowed, but if an
674 674 exception was produced, the method returns True.
675 675
676 676 Parameters
677 677 ----------
678 678 lines : string
679 679 One or more lines of Python input.
680 680
681 681 Returns
682 682 -------
683 683 is_complete : boolean
684 684 True if the current input source (the result of the current input
685 685 plus prior inputs) forms a complete Python execution block. Note that
686 686 this value is also stored as a private attribute (_is_complete), so it
687 687 can be queried at any time.
688 688 """
689 689
690 690 # We must ensure all input is pure unicode
691 691 lines = cast_unicode(lines, self.encoding)
692 692 # ''.splitlines() --> [], but we need to push the empty line to transformers
693 693 lines_list = lines.splitlines()
694 694 if not lines_list:
695 695 lines_list = ['']
696 696
697 697 # Store raw source before applying any transformations to it. Note
698 698 # that this must be done *after* the reset() call that would otherwise
699 699 # flush the buffer.
700 700 self._store(lines, self._buffer_raw, 'source_raw')
701 701
702 transformed_lines_list = []
702 703 for line in lines_list:
703 out = self.push_line(line)
704 transformed = self._transform_line(line)
705 if transformed is not None:
706 transformed_lines_list.append(transformed)
704 707
705 return out
706
707 def push_line(self, line):
708 buf = self._buffer
708 if transformed_lines_list:
709 transformed_lines = '\n'.join(transformed_lines_list)
710 return super(IPythonInputSplitter, self).push(transformed_lines)
711 else:
712 # Got nothing back from transformers - they must be waiting for
713 # more input.
714 return False
715
716 def _transform_line(self, line):
717 """Push a line of input code through the various transformers.
709 718
719 Returns any output from the transformers, or None if a transformer
720 is accumulating lines.
721
722 Sets self.transformer_accumulating as a side effect.
723 """
710 724 def _accumulating(dbg):
711 725 #print(dbg)
712 726 self.transformer_accumulating = True
713 return False
714
727 return None
728
715 729 for transformer in self.physical_line_transforms:
716 730 line = transformer.push(line)
717 731 if line is None:
718 732 return _accumulating(transformer)
719
733
720 734 if not self.within_python_line:
721 735 line = self.assemble_logical_lines.push(line)
722 736 if line is None:
723 return _accumulating('acc logical line')
724
737 return _accumulating('acc logical line')
738
725 739 for transformer in self.logical_line_transforms:
726 740 line = transformer.push(line)
727 741 if line is None:
728 742 return _accumulating(transformer)
729
743
730 744 line = self.assemble_python_lines.push(line)
731 745 if line is None:
732 746 self.within_python_line = True
733 747 return _accumulating('acc python line')
734 748 else:
735 749 self.within_python_line = False
736
750
737 751 for transformer in self.python_line_transforms:
738 752 line = transformer.push(line)
739 753 if line is None:
740 754 return _accumulating(transformer)
741 755
742 756 #print("transformers clear") #debug
743 757 self.transformer_accumulating = False
744 return super(IPythonInputSplitter, self).push(line)
758 return line
759
General Comments 0
You need to be logged in to leave comments. Login now