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