##// END OF EJS Templates
Remove unused _full_dedent attribute
Thomas Kluyver -
Show More
@@ -1,743 +1,739 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 # Number of spaces of indentation computed from input that has been pushed
294 294 # so far. This is the attributes callers should query to get the current
295 295 # indentation level, in order to provide auto-indent facilities.
296 296 indent_spaces = 0
297 297 # String, indicating the default input encoding. It is computed by default
298 298 # at initialization time via get_input_encoding(), but it can be reset by a
299 299 # client with specific knowledge of the encoding.
300 300 encoding = ''
301 301 # String where the current full source input is stored, properly encoded.
302 302 # Reading this attribute is the normal way of querying the currently pushed
303 303 # source code, that has been properly encoded.
304 304 source = ''
305 305 # Code object corresponding to the current source. It is automatically
306 306 # synced to the source, so it can be queried at any time to obtain the code
307 307 # object; it will be None if the source doesn't compile to valid Python.
308 308 code = None
309 309
310 310 # Private attributes
311 311
312 312 # List with lines of input accumulated so far
313 313 _buffer = None
314 314 # Command compiler
315 315 _compile = None
316 # Mark when input has changed indentation all the way back to flush-left
317 _full_dedent = False
318 316 # Boolean indicating whether the current block is complete
319 317 _is_complete = None
320 318 # Boolean indicating whether the current block has an unrecoverable syntax error
321 319 _is_invalid = False
322 320
323 321 def __init__(self):
324 322 """Create a new InputSplitter instance.
325 323 """
326 324 self._buffer = []
327 325 self._compile = codeop.CommandCompiler()
328 326 self.encoding = get_input_encoding()
329 327
330 328 def reset(self):
331 329 """Reset the input buffer and associated state."""
332 330 self.indent_spaces = 0
333 331 self._buffer[:] = []
334 332 self.source = ''
335 333 self.code = None
336 334 self._is_complete = False
337 335 self._is_invalid = False
338 self._full_dedent = False
339 336
340 337 def source_reset(self):
341 338 """Return the input source and perform a full reset.
342 339 """
343 340 out = self.source
344 341 self.reset()
345 342 return out
346 343
347 344 def check_complete(self, source):
348 345 """Return whether a block of code is ready to execute, or should be continued
349 346
350 347 This is a non-stateful API, and will reset the state of this InputSplitter.
351 348
352 349 Parameters
353 350 ----------
354 351 source : string
355 352 Python input code, which can be multiline.
356 353
357 354 Returns
358 355 -------
359 356 status : str
360 357 One of 'complete', 'incomplete', or 'invalid' if source is not a
361 358 prefix of valid code.
362 359 indent_spaces : int or None
363 360 The number of spaces by which to indent the next line of code. If
364 361 status is not 'incomplete', this is None.
365 362 """
366 363 self.reset()
367 364 try:
368 365 self.push(source)
369 366 except SyntaxError:
370 367 # Transformers in IPythonInputSplitter can raise SyntaxError,
371 368 # which push() will not catch.
372 369 return 'invalid', None
373 370 else:
374 371 if self._is_invalid:
375 372 return 'invalid', None
376 373 elif self.push_accepts_more():
377 374 return 'incomplete', self.indent_spaces
378 375 else:
379 376 return 'complete', None
380 377 finally:
381 378 self.reset()
382 379
383 380 def push(self, lines):
384 381 """Push one or more lines of input.
385 382
386 383 This stores the given lines and returns a status code indicating
387 384 whether the code forms a complete Python block or not.
388 385
389 386 Any exceptions generated in compilation are swallowed, but if an
390 387 exception was produced, the method returns True.
391 388
392 389 Parameters
393 390 ----------
394 391 lines : string
395 392 One or more lines of Python input.
396 393
397 394 Returns
398 395 -------
399 396 is_complete : boolean
400 397 True if the current input source (the result of the current input
401 398 plus prior inputs) forms a complete Python execution block. Note that
402 399 this value is also stored as a private attribute (``_is_complete``), so it
403 400 can be queried at any time.
404 401 """
405 402 self._store(lines)
406 403 source = self.source
407 404
408 405 # Before calling _compile(), reset the code object to None so that if an
409 406 # exception is raised in compilation, we don't mislead by having
410 407 # inconsistent code/source attributes.
411 408 self.code, self._is_complete = None, None
412 409 self._is_invalid = False
413 410
414 411 # Honor termination lines properly
415 412 if source.endswith('\\\n'):
416 413 return False
417 414
418 415 self._update_indent()
419 416 try:
420 417 with warnings.catch_warnings():
421 418 warnings.simplefilter('error', SyntaxWarning)
422 419 self.code = self._compile(source, symbol="exec")
423 420 # Invalid syntax can produce any of a number of different errors from
424 421 # inside the compiler, so we have to catch them all. Syntax errors
425 422 # immediately produce a 'ready' block, so the invalid Python can be
426 423 # sent to the kernel for evaluation with possible ipython
427 424 # special-syntax conversion.
428 425 except (SyntaxError, OverflowError, ValueError, TypeError,
429 426 MemoryError, SyntaxWarning):
430 427 self._is_complete = True
431 428 self._is_invalid = True
432 429 else:
433 430 # Compilation didn't produce any exceptions (though it may not have
434 431 # given a complete code object)
435 432 self._is_complete = self.code is not None
436 433
437 434 return self._is_complete
438 435
439 436 def push_accepts_more(self):
440 437 """Return whether a block of interactive input can accept more input.
441 438
442 439 This method is meant to be used by line-oriented frontends, who need to
443 440 guess whether a block is complete or not based solely on prior and
444 441 current input lines. The InputSplitter considers it has a complete
445 442 interactive block and will not accept more input when either:
446 443
447 444 * A SyntaxError is raised
448 445
449 446 * The code is complete and consists of a single line or a single
450 447 non-compound statement
451 448
452 449 * The code is complete and has a blank line at the end
453 450
454 451 If the current input produces a syntax error, this method immediately
455 452 returns False but does *not* raise the syntax error exception, as
456 453 typically clients will want to send invalid syntax to an execution
457 454 backend which might convert the invalid syntax into valid Python via
458 455 one of the dynamic IPython mechanisms.
459 456 """
460 457
461 458 # With incomplete input, unconditionally accept more
462 459 # A syntax error also sets _is_complete to True - see push()
463 460 if not self._is_complete:
464 461 #print("Not complete") # debug
465 462 return True
466 463
467 464 # The user can make any (complete) input execute by leaving a blank line
468 465 last_line = self.source.splitlines()[-1]
469 466 if (not last_line) or last_line.isspace():
470 467 #print("Blank line") # debug
471 468 return False
472 469
473 470 # If there's just a single line or AST node, and we're flush left, as is
474 471 # the case after a simple statement such as 'a=1', we want to execute it
475 472 # straight away.
476 473 if self.indent_spaces==0:
477 474 if len(self.source.splitlines()) <= 1:
478 475 return False
479 476
480 477 try:
481 478 code_ast = ast.parse(u''.join(self._buffer))
482 479 except Exception:
483 480 #print("Can't parse AST") # debug
484 481 return False
485 482 else:
486 483 if len(code_ast.body) == 1 and \
487 484 not hasattr(code_ast.body[0], 'body'):
488 485 #print("Simple statement") # debug
489 486 return False
490 487
491 488 # General fallback - accept more code
492 489 return True
493 490
494 491 def _update_indent(self):
495 492 # self.source always has a trailing newline
496 493 self.indent_spaces = find_next_indent(self.source[:-1])
497 self._full_dedent = (self.indent_spaces == 0)
498 494
499 495 def _store(self, lines, buffer=None, store='source'):
500 496 """Store one or more lines of input.
501 497
502 498 If input lines are not newline-terminated, a newline is automatically
503 499 appended."""
504 500
505 501 if buffer is None:
506 502 buffer = self._buffer
507 503
508 504 if lines.endswith('\n'):
509 505 buffer.append(lines)
510 506 else:
511 507 buffer.append(lines+'\n')
512 508 setattr(self, store, self._set_source(buffer))
513 509
514 510 def _set_source(self, buffer):
515 511 return u''.join(buffer)
516 512
517 513
518 514 class IPythonInputSplitter(InputSplitter):
519 515 """An input splitter that recognizes all of IPython's special syntax."""
520 516
521 517 # String with raw, untransformed input.
522 518 source_raw = ''
523 519
524 520 # Flag to track when a transformer has stored input that it hasn't given
525 521 # back yet.
526 522 transformer_accumulating = False
527 523
528 524 # Flag to track when assemble_python_lines has stored input that it hasn't
529 525 # given back yet.
530 526 within_python_line = False
531 527
532 528 # Private attributes
533 529
534 530 # List with lines of raw input accumulated so far.
535 531 _buffer_raw = None
536 532
537 533 def __init__(self, line_input_checker=True, physical_line_transforms=None,
538 534 logical_line_transforms=None, python_line_transforms=None):
539 535 super(IPythonInputSplitter, self).__init__()
540 536 self._buffer_raw = []
541 537 self._validate = True
542 538
543 539 if physical_line_transforms is not None:
544 540 self.physical_line_transforms = physical_line_transforms
545 541 else:
546 542 self.physical_line_transforms = [
547 543 leading_indent(),
548 544 classic_prompt(),
549 545 ipy_prompt(),
550 546 cellmagic(end_on_blank_line=line_input_checker),
551 547 ]
552 548
553 549 self.assemble_logical_lines = assemble_logical_lines()
554 550 if logical_line_transforms is not None:
555 551 self.logical_line_transforms = logical_line_transforms
556 552 else:
557 553 self.logical_line_transforms = [
558 554 help_end(),
559 555 escaped_commands(),
560 556 assign_from_magic(),
561 557 assign_from_system(),
562 558 ]
563 559
564 560 self.assemble_python_lines = assemble_python_lines()
565 561 if python_line_transforms is not None:
566 562 self.python_line_transforms = python_line_transforms
567 563 else:
568 564 # We don't use any of these at present
569 565 self.python_line_transforms = []
570 566
571 567 @property
572 568 def transforms(self):
573 569 "Quick access to all transformers."
574 570 return self.physical_line_transforms + \
575 571 [self.assemble_logical_lines] + self.logical_line_transforms + \
576 572 [self.assemble_python_lines] + self.python_line_transforms
577 573
578 574 @property
579 575 def transforms_in_use(self):
580 576 """Transformers, excluding logical line transformers if we're in a
581 577 Python line."""
582 578 t = self.physical_line_transforms[:]
583 579 if not self.within_python_line:
584 580 t += [self.assemble_logical_lines] + self.logical_line_transforms
585 581 return t + [self.assemble_python_lines] + self.python_line_transforms
586 582
587 583 def reset(self):
588 584 """Reset the input buffer and associated state."""
589 585 super(IPythonInputSplitter, self).reset()
590 586 self._buffer_raw[:] = []
591 587 self.source_raw = ''
592 588 self.transformer_accumulating = False
593 589 self.within_python_line = False
594 590
595 591 for t in self.transforms:
596 592 try:
597 593 t.reset()
598 594 except SyntaxError:
599 595 # Nothing that calls reset() expects to handle transformer
600 596 # errors
601 597 pass
602 598
603 599 def flush_transformers(self):
604 600 def _flush(transform, outs):
605 601 """yield transformed lines
606 602
607 603 always strings, never None
608 604
609 605 transform: the current transform
610 606 outs: an iterable of previously transformed inputs.
611 607 Each may be multiline, which will be passed
612 608 one line at a time to transform.
613 609 """
614 610 for out in outs:
615 611 for line in out.splitlines():
616 612 # push one line at a time
617 613 tmp = transform.push(line)
618 614 if tmp is not None:
619 615 yield tmp
620 616
621 617 # reset the transform
622 618 tmp = transform.reset()
623 619 if tmp is not None:
624 620 yield tmp
625 621
626 622 out = []
627 623 for t in self.transforms_in_use:
628 624 out = _flush(t, out)
629 625
630 626 out = list(out)
631 627 if out:
632 628 self._store('\n'.join(out))
633 629
634 630 def raw_reset(self):
635 631 """Return raw input only and perform a full reset.
636 632 """
637 633 out = self.source_raw
638 634 self.reset()
639 635 return out
640 636
641 637 def source_reset(self):
642 638 try:
643 639 self.flush_transformers()
644 640 return self.source
645 641 finally:
646 642 self.reset()
647 643
648 644 def push_accepts_more(self):
649 645 if self.transformer_accumulating:
650 646 return True
651 647 else:
652 648 return super(IPythonInputSplitter, self).push_accepts_more()
653 649
654 650 def transform_cell(self, cell):
655 651 """Process and translate a cell of input.
656 652 """
657 653 self.reset()
658 654 try:
659 655 self.push(cell)
660 656 self.flush_transformers()
661 657 return self.source
662 658 finally:
663 659 self.reset()
664 660
665 661 def push(self, lines):
666 662 """Push one or more lines of IPython input.
667 663
668 664 This stores the given lines and returns a status code indicating
669 665 whether the code forms a complete Python block or not, after processing
670 666 all input lines for special IPython syntax.
671 667
672 668 Any exceptions generated in compilation are swallowed, but if an
673 669 exception was produced, the method returns True.
674 670
675 671 Parameters
676 672 ----------
677 673 lines : string
678 674 One or more lines of Python input.
679 675
680 676 Returns
681 677 -------
682 678 is_complete : boolean
683 679 True if the current input source (the result of the current input
684 680 plus prior inputs) forms a complete Python execution block. Note that
685 681 this value is also stored as a private attribute (_is_complete), so it
686 682 can be queried at any time.
687 683 """
688 684
689 685 # We must ensure all input is pure unicode
690 686 lines = cast_unicode(lines, self.encoding)
691 687 # ''.splitlines() --> [], but we need to push the empty line to transformers
692 688 lines_list = lines.splitlines()
693 689 if not lines_list:
694 690 lines_list = ['']
695 691
696 692 # Store raw source before applying any transformations to it. Note
697 693 # that this must be done *after* the reset() call that would otherwise
698 694 # flush the buffer.
699 695 self._store(lines, self._buffer_raw, 'source_raw')
700 696
701 697 for line in lines_list:
702 698 out = self.push_line(line)
703 699
704 700 return out
705 701
706 702 def push_line(self, line):
707 703 buf = self._buffer
708 704
709 705 def _accumulating(dbg):
710 706 #print(dbg)
711 707 self.transformer_accumulating = True
712 708 return False
713 709
714 710 for transformer in self.physical_line_transforms:
715 711 line = transformer.push(line)
716 712 if line is None:
717 713 return _accumulating(transformer)
718 714
719 715 if not self.within_python_line:
720 716 line = self.assemble_logical_lines.push(line)
721 717 if line is None:
722 718 return _accumulating('acc logical line')
723 719
724 720 for transformer in self.logical_line_transforms:
725 721 line = transformer.push(line)
726 722 if line is None:
727 723 return _accumulating(transformer)
728 724
729 725 line = self.assemble_python_lines.push(line)
730 726 if line is None:
731 727 self.within_python_line = True
732 728 return _accumulating('acc python line')
733 729 else:
734 730 self.within_python_line = False
735 731
736 732 for transformer in self.python_line_transforms:
737 733 line = transformer.push(line)
738 734 if line is None:
739 735 return _accumulating(transformer)
740 736
741 737 #print("transformers clear") #debug
742 738 self.transformer_accumulating = False
743 739 return super(IPythonInputSplitter, self).push(line)
General Comments 0
You need to be logged in to leave comments. Login now