##// END OF EJS Templates
Fix bug with lines ending in continuation markers (\)....
Fernando Perez -
Show More
@@ -1,977 +1,981 b''
1 1 """Analysis of text input into executable blocks.
2 2
3 3 The main class in this module, :class:`InputSplitter`, is designed to break
4 4 input from either interactive, line-by-line environments or block-based ones,
5 5 into standalone blocks that can be executed by Python as 'single' statements
6 6 (thus triggering sys.displayhook).
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
11 11 For more details, see the class docstring below.
12 12
13 13 Syntax Transformations
14 14 ----------------------
15 15
16 16 One of the main jobs of the code in this file is to apply all syntax
17 17 transformations that make up 'the IPython language', i.e. magics, shell
18 18 escapes, etc. All transformations should be implemented as *fully stateless*
19 19 entities, that simply take one line as their input and return a line.
20 20 Internally for implementation purposes they may be a normal function or a
21 21 callable object, but the only input they receive will be a single line and they
22 22 should only return a line, without holding any data-dependent state between
23 23 calls.
24 24
25 25 As an example, the EscapedTransformer is a class so we can more clearly group
26 26 together the functionality of dispatching to individual functions based on the
27 27 starting escape character, but the only method for public use is its call
28 28 method.
29 29
30 30
31 31 ToDo
32 32 ----
33 33
34 34 - Should we make push() actually raise an exception once push_accepts_more()
35 35 returns False?
36 36
37 37 - Naming cleanups. The tr_* names aren't the most elegant, though now they are
38 38 at least just attributes of a class so not really very exposed.
39 39
40 40 - Think about the best way to support dynamic things: automagic, autocall,
41 41 macros, etc.
42 42
43 43 - Think of a better heuristic for the application of the transforms in
44 44 IPythonInputSplitter.push() than looking at the buffer ending in ':'. Idea:
45 45 track indentation change events (indent, dedent, nothing) and apply them only
46 46 if the indentation went up, but not otherwise.
47 47
48 48 - Think of the cleanest way for supporting user-specified transformations (the
49 49 user prefilters we had before).
50 50
51 51 Authors
52 52 -------
53 53
54 54 * Fernando Perez
55 55 * Brian Granger
56 56 """
57 57 #-----------------------------------------------------------------------------
58 58 # Copyright (C) 2010 The IPython Development Team
59 59 #
60 60 # Distributed under the terms of the BSD License. The full license is in
61 61 # the file COPYING, distributed as part of this software.
62 62 #-----------------------------------------------------------------------------
63 63 from __future__ import print_function
64 64
65 65 #-----------------------------------------------------------------------------
66 66 # Imports
67 67 #-----------------------------------------------------------------------------
68 68 # stdlib
69 69 import codeop
70 70 import re
71 71 import sys
72 72
73 73 # IPython modules
74 74 from IPython.utils.text import make_quoted_expr
75 75
76 76 #-----------------------------------------------------------------------------
77 77 # Globals
78 78 #-----------------------------------------------------------------------------
79 79
80 80 # The escape sequences that define the syntax transformations IPython will
81 81 # apply to user input. These can NOT be just changed here: many regular
82 82 # expressions and other parts of the code may use their hardcoded values, and
83 83 # for all intents and purposes they constitute the 'IPython syntax', so they
84 84 # should be considered fixed.
85 85
86 86 ESC_SHELL = '!' # Send line to underlying system shell
87 87 ESC_SH_CAP = '!!' # Send line to system shell and capture output
88 88 ESC_HELP = '?' # Find information about object
89 89 ESC_HELP2 = '??' # Find extra-detailed information about object
90 90 ESC_MAGIC = '%' # Call magic function
91 91 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
92 92 ESC_QUOTE2 = ';' # Quote all args as a single string, call
93 93 ESC_PAREN = '/' # Call first argument with rest of line as arguments
94 94
95 95 #-----------------------------------------------------------------------------
96 96 # Utilities
97 97 #-----------------------------------------------------------------------------
98 98
99 99 # FIXME: These are general-purpose utilities that later can be moved to the
100 100 # general ward. Kept here for now because we're being very strict about test
101 101 # coverage with this code, and this lets us ensure that we keep 100% coverage
102 102 # while developing.
103 103
104 104 # compiled regexps for autoindent management
105 105 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
106 106 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
107 107
108 108 # regexp to match pure comment lines so we don't accidentally insert 'if 1:'
109 109 # before pure comments
110 110 comment_line_re = re.compile('^\s*\#')
111 111
112 112
113 113 def num_ini_spaces(s):
114 114 """Return the number of initial spaces in a string.
115 115
116 116 Note that tabs are counted as a single space. For now, we do *not* support
117 117 mixing of tabs and spaces in the user's input.
118 118
119 119 Parameters
120 120 ----------
121 121 s : string
122 122
123 123 Returns
124 124 -------
125 125 n : int
126 126 """
127 127
128 128 ini_spaces = ini_spaces_re.match(s)
129 129 if ini_spaces:
130 130 return ini_spaces.end()
131 131 else:
132 132 return 0
133 133
134 134
135 135 def remove_comments(src):
136 136 """Remove all comments from input source.
137 137
138 138 Note: comments are NOT recognized inside of strings!
139 139
140 140 Parameters
141 141 ----------
142 142 src : string
143 143 A single or multiline input string.
144 144
145 145 Returns
146 146 -------
147 147 String with all Python comments removed.
148 148 """
149 149
150 150 return re.sub('#.*', '', src)
151 151
152 152
153 153 def get_input_encoding():
154 154 """Return the default standard input encoding.
155 155
156 156 If sys.stdin has no encoding, 'ascii' is returned."""
157 157 # There are strange environments for which sys.stdin.encoding is None. We
158 158 # ensure that a valid encoding is returned.
159 159 encoding = getattr(sys.stdin, 'encoding', None)
160 160 if encoding is None:
161 161 encoding = 'ascii'
162 162 return encoding
163 163
164 164 #-----------------------------------------------------------------------------
165 165 # Classes and functions for normal Python syntax handling
166 166 #-----------------------------------------------------------------------------
167 167
168 168 # HACK! This implementation, written by Robert K a while ago using the
169 169 # compiler module, is more robust than the other one below, but it expects its
170 170 # input to be pure python (no ipython syntax). For now we're using it as a
171 171 # second-pass splitter after the first pass transforms the input to pure
172 172 # python.
173 173
174 174 def split_blocks(python):
175 175 """ Split multiple lines of code into discrete commands that can be
176 176 executed singly.
177 177
178 178 Parameters
179 179 ----------
180 180 python : str
181 181 Pure, exec'able Python code.
182 182
183 183 Returns
184 184 -------
185 185 commands : list of str
186 186 Separate commands that can be exec'ed independently.
187 187 """
188 188
189 189 import compiler
190 190
191 191 # compiler.parse treats trailing spaces after a newline as a
192 192 # SyntaxError. This is different than codeop.CommandCompiler, which
193 193 # will compile the trailng spaces just fine. We simply strip any
194 194 # trailing whitespace off. Passing a string with trailing whitespace
195 195 # to exec will fail however. There seems to be some inconsistency in
196 196 # how trailing whitespace is handled, but this seems to work.
197 197 python_ori = python # save original in case we bail on error
198 198 python = python.strip()
199 199
200 200 # The compiler module does not like unicode. We need to convert
201 201 # it encode it:
202 202 if isinstance(python, unicode):
203 203 # Use the utf-8-sig BOM so the compiler detects this a UTF-8
204 204 # encode string.
205 205 python = '\xef\xbb\xbf' + python.encode('utf-8')
206 206
207 207 # The compiler module will parse the code into an abstract syntax tree.
208 208 # This has a bug with str("a\nb"), but not str("""a\nb""")!!!
209 209 try:
210 210 ast = compiler.parse(python)
211 211 except:
212 212 return [python_ori]
213 213
214 214 # Uncomment to help debug the ast tree
215 215 # for n in ast.node:
216 216 # print n.lineno,'->',n
217 217
218 218 # Each separate command is available by iterating over ast.node. The
219 219 # lineno attribute is the line number (1-indexed) beginning the commands
220 220 # suite.
221 221 # lines ending with ";" yield a Discard Node that doesn't have a lineno
222 222 # attribute. These nodes can and should be discarded. But there are
223 223 # other situations that cause Discard nodes that shouldn't be discarded.
224 224 # We might eventually discover other cases where lineno is None and have
225 225 # to put in a more sophisticated test.
226 226 linenos = [x.lineno-1 for x in ast.node if x.lineno is not None]
227 227
228 228 # When we finally get the slices, we will need to slice all the way to
229 229 # the end even though we don't have a line number for it. Fortunately,
230 230 # None does the job nicely.
231 231 linenos.append(None)
232 232
233 233 # Same problem at the other end: sometimes the ast tree has its
234 234 # first complete statement not starting on line 0. In this case
235 235 # we might miss part of it. This fixes ticket 266993. Thanks Gael!
236 236 linenos[0] = 0
237 237
238 238 lines = python.splitlines()
239 239
240 240 # Create a list of atomic commands.
241 241 cmds = []
242 242 for i, j in zip(linenos[:-1], linenos[1:]):
243 243 cmd = lines[i:j]
244 244 if cmd:
245 245 cmds.append('\n'.join(cmd)+'\n')
246 246
247 247 return cmds
248 248
249 249
250 250 class InputSplitter(object):
251 251 """An object that can split Python source input in executable blocks.
252 252
253 253 This object is designed to be used in one of two basic modes:
254 254
255 255 1. By feeding it python source line-by-line, using :meth:`push`. In this
256 256 mode, it will return on each push whether the currently pushed code
257 257 could be executed already. In addition, it provides a method called
258 258 :meth:`push_accepts_more` that can be used to query whether more input
259 259 can be pushed into a single interactive block.
260 260
261 261 2. By calling :meth:`split_blocks` with a single, multiline Python string,
262 262 that is then split into blocks each of which can be executed
263 263 interactively as a single statement.
264 264
265 265 This is a simple example of how an interactive terminal-based client can use
266 266 this tool::
267 267
268 268 isp = InputSplitter()
269 269 while isp.push_accepts_more():
270 270 indent = ' '*isp.indent_spaces
271 271 prompt = '>>> ' + indent
272 272 line = indent + raw_input(prompt)
273 273 isp.push(line)
274 274 print 'Input source was:\n', isp.source_reset(),
275 275 """
276 276 # Number of spaces of indentation computed from input that has been pushed
277 277 # so far. This is the attributes callers should query to get the current
278 278 # indentation level, in order to provide auto-indent facilities.
279 279 indent_spaces = 0
280 280 # String, indicating the default input encoding. It is computed by default
281 281 # at initialization time via get_input_encoding(), but it can be reset by a
282 282 # client with specific knowledge of the encoding.
283 283 encoding = ''
284 284 # String where the current full source input is stored, properly encoded.
285 285 # Reading this attribute is the normal way of querying the currently pushed
286 286 # source code, that has been properly encoded.
287 287 source = ''
288 288 # Code object corresponding to the current source. It is automatically
289 289 # synced to the source, so it can be queried at any time to obtain the code
290 290 # object; it will be None if the source doesn't compile to valid Python.
291 291 code = None
292 292 # Input mode
293 293 input_mode = 'line'
294 294
295 295 # Private attributes
296 296
297 297 # List with lines of input accumulated so far
298 298 _buffer = None
299 299 # Command compiler
300 300 _compile = None
301 301 # Mark when input has changed indentation all the way back to flush-left
302 302 _full_dedent = False
303 303 # Boolean indicating whether the current block is complete
304 304 _is_complete = None
305 305
306 306 def __init__(self, input_mode=None):
307 307 """Create a new InputSplitter instance.
308 308
309 309 Parameters
310 310 ----------
311 311 input_mode : str
312 312
313 313 One of ['line', 'cell']; default is 'line'.
314 314
315 315 The input_mode parameter controls how new inputs are used when fed via
316 316 the :meth:`push` method:
317 317
318 318 - 'line': meant for line-oriented clients, inputs are appended one at a
319 319 time to the internal buffer and the whole buffer is compiled.
320 320
321 321 - 'cell': meant for clients that can edit multi-line 'cells' of text at
322 322 a time. A cell can contain one or more blocks that can be compile in
323 323 'single' mode by Python. In this mode, each new input new input
324 324 completely replaces all prior inputs. Cell mode is thus equivalent
325 325 to prepending a full reset() to every push() call.
326 326 """
327 327 self._buffer = []
328 328 self._compile = codeop.CommandCompiler()
329 329 self.encoding = get_input_encoding()
330 330 self.input_mode = InputSplitter.input_mode if input_mode is None \
331 331 else input_mode
332 332
333 333 def reset(self):
334 334 """Reset the input buffer and associated state."""
335 335 self.indent_spaces = 0
336 336 self._buffer[:] = []
337 337 self.source = ''
338 338 self.code = None
339 339 self._is_complete = False
340 340 self._full_dedent = False
341 341
342 342 def source_reset(self):
343 343 """Return the input source and perform a full reset.
344 344 """
345 345 out = self.source
346 346 self.reset()
347 347 return out
348 348
349 349 def push(self, lines):
350 350 """Push one ore more lines of input.
351 351
352 352 This stores the given lines and returns a status code indicating
353 353 whether the code forms a complete Python block or not.
354 354
355 355 Any exceptions generated in compilation are swallowed, but if an
356 356 exception was produced, the method returns True.
357 357
358 358 Parameters
359 359 ----------
360 360 lines : string
361 361 One or more lines of Python input.
362 362
363 363 Returns
364 364 -------
365 365 is_complete : boolean
366 366 True if the current input source (the result of the current input
367 367 plus prior inputs) forms a complete Python execution block. Note that
368 368 this value is also stored as a private attribute (_is_complete), so it
369 369 can be queried at any time.
370 370 """
371 371 if self.input_mode == 'cell':
372 372 self.reset()
373 373
374 374 # If the source code has leading blanks, add 'if 1:\n' to it
375 375 # this allows execution of indented pasted code. It is tempting
376 376 # to add '\n' at the end of source to run commands like ' a=1'
377 377 # directly, but this fails for more complicated scenarios
378 378
379 379 if not self._buffer and lines[:1] in [' ', '\t'] and \
380 380 not comment_line_re.match(lines):
381 381 lines = 'if 1:\n%s' % lines
382 382
383 383 self._store(lines)
384 384 source = self.source
385 385
386 386 # Before calling _compile(), reset the code object to None so that if an
387 387 # exception is raised in compilation, we don't mislead by having
388 388 # inconsistent code/source attributes.
389 389 self.code, self._is_complete = None, None
390 390
391 # Honor termination lines properly
392 if source.rstrip().endswith('\\'):
393 return False
394
391 395 self._update_indent(lines)
392 396 try:
393 397 self.code = self._compile(source)
394 398 # Invalid syntax can produce any of a number of different errors from
395 399 # inside the compiler, so we have to catch them all. Syntax errors
396 400 # immediately produce a 'ready' block, so the invalid Python can be
397 401 # sent to the kernel for evaluation with possible ipython
398 402 # special-syntax conversion.
399 403 except (SyntaxError, OverflowError, ValueError, TypeError,
400 404 MemoryError):
401 405 self._is_complete = True
402 406 else:
403 407 # Compilation didn't produce any exceptions (though it may not have
404 408 # given a complete code object)
405 409 self._is_complete = self.code is not None
406 410
407 411 return self._is_complete
408 412
409 413 def push_accepts_more(self):
410 414 """Return whether a block of interactive input can accept more input.
411 415
412 416 This method is meant to be used by line-oriented frontends, who need to
413 417 guess whether a block is complete or not based solely on prior and
414 418 current input lines. The InputSplitter considers it has a complete
415 419 interactive block and will not accept more input only when either a
416 420 SyntaxError is raised, or *all* of the following are true:
417 421
418 422 1. The input compiles to a complete statement.
419 423
420 424 2. The indentation level is flush-left (because if we are indented,
421 425 like inside a function definition or for loop, we need to keep
422 426 reading new input).
423 427
424 428 3. There is one extra line consisting only of whitespace.
425 429
426 430 Because of condition #3, this method should be used only by
427 431 *line-oriented* frontends, since it means that intermediate blank lines
428 432 are not allowed in function definitions (or any other indented block).
429 433
430 434 Block-oriented frontends that have a separate keyboard event to
431 435 indicate execution should use the :meth:`split_blocks` method instead.
432 436
433 437 If the current input produces a syntax error, this method immediately
434 438 returns False but does *not* raise the syntax error exception, as
435 439 typically clients will want to send invalid syntax to an execution
436 440 backend which might convert the invalid syntax into valid Python via
437 441 one of the dynamic IPython mechanisms.
438 442 """
439 443
440 444 # With incomplete input, unconditionally accept more
441 445 if not self._is_complete:
442 446 return True
443 447
444 448 # If we already have complete input and we're flush left, the answer
445 449 # depends. In line mode, we're done. But in cell mode, we need to
446 450 # check how many blocks the input so far compiles into, because if
447 451 # there's already more than one full independent block of input, then
448 452 # the client has entered full 'cell' mode and is feeding lines that
449 453 # each is complete. In this case we should then keep accepting.
450 454 # The Qt terminal-like console does precisely this, to provide the
451 455 # convenience of terminal-like input of single expressions, but
452 456 # allowing the user (with a separate keystroke) to switch to 'cell'
453 457 # mode and type multiple expressions in one shot.
454 458 if self.indent_spaces==0:
455 459 if self.input_mode=='line':
456 460 return False
457 461 else:
458 462 nblocks = len(split_blocks(''.join(self._buffer)))
459 463 if nblocks==1:
460 464 return False
461 465
462 466 # When input is complete, then termination is marked by an extra blank
463 467 # line at the end.
464 468 last_line = self.source.splitlines()[-1]
465 469 return bool(last_line and not last_line.isspace())
466 470
467 471 def split_blocks(self, lines):
468 472 """Split a multiline string into multiple input blocks.
469 473
470 474 Note: this method starts by performing a full reset().
471 475
472 476 Parameters
473 477 ----------
474 478 lines : str
475 479 A possibly multiline string.
476 480
477 481 Returns
478 482 -------
479 483 blocks : list
480 484 A list of strings, each possibly multiline. Each string corresponds
481 485 to a single block that can be compiled in 'single' mode (unless it
482 486 has a syntax error)."""
483 487
484 488 # This code is fairly delicate. If you make any changes here, make
485 489 # absolutely sure that you do run the full test suite and ALL tests
486 490 # pass.
487 491
488 492 self.reset()
489 493 blocks = []
490 494
491 495 # Reversed copy so we can use pop() efficiently and consume the input
492 496 # as a stack
493 497 lines = lines.splitlines()[::-1]
494 498 # Outer loop over all input
495 499 while lines:
496 500 #print 'Current lines:', lines # dbg
497 501 # Inner loop to build each block
498 502 while True:
499 503 # Safety exit from inner loop
500 504 if not lines:
501 505 break
502 506 # Grab next line but don't push it yet
503 507 next_line = lines.pop()
504 508 # Blank/empty lines are pushed as-is
505 509 if not next_line or next_line.isspace():
506 510 self.push(next_line)
507 511 continue
508 512
509 513 # Check indentation changes caused by the *next* line
510 514 indent_spaces, _full_dedent = self._find_indent(next_line)
511 515
512 516 # If the next line causes a dedent, it can be for two differnt
513 517 # reasons: either an explicit de-dent by the user or a
514 518 # return/raise/pass statement. These MUST be handled
515 519 # separately:
516 520 #
517 521 # 1. the first case is only detected when the actual explicit
518 522 # dedent happens, and that would be the *first* line of a *new*
519 523 # block. Thus, we must put the line back into the input buffer
520 524 # so that it starts a new block on the next pass.
521 525 #
522 526 # 2. the second case is detected in the line before the actual
523 527 # dedent happens, so , we consume the line and we can break out
524 528 # to start a new block.
525 529
526 530 # Case 1, explicit dedent causes a break.
527 531 # Note: check that we weren't on the very last line, else we'll
528 532 # enter an infinite loop adding/removing the last line.
529 533 if _full_dedent and lines and not next_line.startswith(' '):
530 534 lines.append(next_line)
531 535 break
532 536
533 537 # Otherwise any line is pushed
534 538 self.push(next_line)
535 539
536 540 # Case 2, full dedent with full block ready:
537 541 if _full_dedent or \
538 542 self.indent_spaces==0 and not self.push_accepts_more():
539 543 break
540 544 # Form the new block with the current source input
541 545 blocks.append(self.source_reset())
542 546
543 547 #return blocks
544 548 # HACK!!! Now that our input is in blocks but guaranteed to be pure
545 549 # python syntax, feed it back a second time through the AST-based
546 550 # splitter, which is more accurate than ours.
547 551 return split_blocks(''.join(blocks))
548 552
549 553 #------------------------------------------------------------------------
550 554 # Private interface
551 555 #------------------------------------------------------------------------
552 556
553 557 def _find_indent(self, line):
554 558 """Compute the new indentation level for a single line.
555 559
556 560 Parameters
557 561 ----------
558 562 line : str
559 563 A single new line of non-whitespace, non-comment Python input.
560 564
561 565 Returns
562 566 -------
563 567 indent_spaces : int
564 568 New value for the indent level (it may be equal to self.indent_spaces
565 569 if indentation doesn't change.
566 570
567 571 full_dedent : boolean
568 572 Whether the new line causes a full flush-left dedent.
569 573 """
570 574 indent_spaces = self.indent_spaces
571 575 full_dedent = self._full_dedent
572 576
573 577 inisp = num_ini_spaces(line)
574 578 if inisp < indent_spaces:
575 579 indent_spaces = inisp
576 580 if indent_spaces <= 0:
577 581 #print 'Full dedent in text',self.source # dbg
578 582 full_dedent = True
579 583
580 584 if line[-1] == ':':
581 585 indent_spaces += 4
582 586 elif dedent_re.match(line):
583 587 indent_spaces -= 4
584 588 if indent_spaces <= 0:
585 589 full_dedent = True
586 590
587 591 # Safety
588 592 if indent_spaces < 0:
589 593 indent_spaces = 0
590 594 #print 'safety' # dbg
591 595
592 596 return indent_spaces, full_dedent
593 597
594 598 def _update_indent(self, lines):
595 599 for line in remove_comments(lines).splitlines():
596 600 if line and not line.isspace():
597 601 self.indent_spaces, self._full_dedent = self._find_indent(line)
598 602
599 603 def _store(self, lines):
600 604 """Store one or more lines of input.
601 605
602 606 If input lines are not newline-terminated, a newline is automatically
603 607 appended."""
604 608
605 609 if lines.endswith('\n'):
606 610 self._buffer.append(lines)
607 611 else:
608 612 self._buffer.append(lines+'\n')
609 613 self._set_source()
610 614
611 615 def _set_source(self):
612 616 self.source = ''.join(self._buffer).encode(self.encoding)
613 617
614 618
615 619 #-----------------------------------------------------------------------------
616 620 # Functions and classes for IPython-specific syntactic support
617 621 #-----------------------------------------------------------------------------
618 622
619 623 # RegExp for splitting line contents into pre-char//first word-method//rest.
620 624 # For clarity, each group in on one line.
621 625
622 626 line_split = re.compile("""
623 627 ^(\s*) # any leading space
624 628 ([,;/%]|!!?|\?\??) # escape character or characters
625 629 \s*(%?[\w\.]*) # function/method, possibly with leading %
626 630 # to correctly treat things like '?%magic'
627 631 (\s+.*$|$) # rest of line
628 632 """, re.VERBOSE)
629 633
630 634
631 635 def split_user_input(line):
632 636 """Split user input into early whitespace, esc-char, function part and rest.
633 637
634 638 This is currently handles lines with '=' in them in a very inconsistent
635 639 manner.
636 640
637 641 Examples
638 642 ========
639 643 >>> split_user_input('x=1')
640 644 ('', '', 'x=1', '')
641 645 >>> split_user_input('?')
642 646 ('', '?', '', '')
643 647 >>> split_user_input('??')
644 648 ('', '??', '', '')
645 649 >>> split_user_input(' ?')
646 650 (' ', '?', '', '')
647 651 >>> split_user_input(' ??')
648 652 (' ', '??', '', '')
649 653 >>> split_user_input('??x')
650 654 ('', '??', 'x', '')
651 655 >>> split_user_input('?x=1')
652 656 ('', '', '?x=1', '')
653 657 >>> split_user_input('!ls')
654 658 ('', '!', 'ls', '')
655 659 >>> split_user_input(' !ls')
656 660 (' ', '!', 'ls', '')
657 661 >>> split_user_input('!!ls')
658 662 ('', '!!', 'ls', '')
659 663 >>> split_user_input(' !!ls')
660 664 (' ', '!!', 'ls', '')
661 665 >>> split_user_input(',ls')
662 666 ('', ',', 'ls', '')
663 667 >>> split_user_input(';ls')
664 668 ('', ';', 'ls', '')
665 669 >>> split_user_input(' ;ls')
666 670 (' ', ';', 'ls', '')
667 671 >>> split_user_input('f.g(x)')
668 672 ('', '', 'f.g(x)', '')
669 673 >>> split_user_input('f.g (x)')
670 674 ('', '', 'f.g', '(x)')
671 675 >>> split_user_input('?%hist')
672 676 ('', '?', '%hist', '')
673 677 """
674 678 match = line_split.match(line)
675 679 if match:
676 680 lspace, esc, fpart, rest = match.groups()
677 681 else:
678 682 # print "match failed for line '%s'" % line
679 683 try:
680 684 fpart, rest = line.split(None, 1)
681 685 except ValueError:
682 686 # print "split failed for line '%s'" % line
683 687 fpart, rest = line,''
684 688 lspace = re.match('^(\s*)(.*)', line).groups()[0]
685 689 esc = ''
686 690
687 691 # fpart has to be a valid python identifier, so it better be only pure
688 692 # ascii, no unicode:
689 693 try:
690 694 fpart = fpart.encode('ascii')
691 695 except UnicodeEncodeError:
692 696 lspace = unicode(lspace)
693 697 rest = fpart + u' ' + rest
694 698 fpart = u''
695 699
696 700 #print 'line:<%s>' % line # dbg
697 701 #print 'esc <%s> fpart <%s> rest <%s>' % (esc,fpart.strip(),rest) # dbg
698 702 return lspace, esc, fpart.strip(), rest.lstrip()
699 703
700 704
701 705 # The escaped translators ALL receive a line where their own escape has been
702 706 # stripped. Only '?' is valid at the end of the line, all others can only be
703 707 # placed at the start.
704 708
705 709 class LineInfo(object):
706 710 """A single line of input and associated info.
707 711
708 712 This is a utility class that mostly wraps the output of
709 713 :func:`split_user_input` into a convenient object to be passed around
710 714 during input transformations.
711 715
712 716 Includes the following as properties:
713 717
714 718 line
715 719 The original, raw line
716 720
717 721 lspace
718 722 Any early whitespace before actual text starts.
719 723
720 724 esc
721 725 The initial esc character (or characters, for double-char escapes like
722 726 '??' or '!!').
723 727
724 728 fpart
725 729 The 'function part', which is basically the maximal initial sequence
726 730 of valid python identifiers and the '.' character. This is what is
727 731 checked for alias and magic transformations, used for auto-calling,
728 732 etc.
729 733
730 734 rest
731 735 Everything else on the line.
732 736 """
733 737 def __init__(self, line):
734 738 self.line = line
735 739 self.lspace, self.esc, self.fpart, self.rest = \
736 740 split_user_input(line)
737 741
738 742 def __str__(self):
739 743 return "LineInfo [%s|%s|%s|%s]" % (self.lspace, self.esc,
740 744 self.fpart, self.rest)
741 745
742 746
743 747 # Transformations of the special syntaxes that don't rely on an explicit escape
744 748 # character but instead on patterns on the input line
745 749
746 750 # The core transformations are implemented as standalone functions that can be
747 751 # tested and validated in isolation. Each of these uses a regexp, we
748 752 # pre-compile these and keep them close to each function definition for clarity
749 753
750 754 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
751 755 r'\s*=\s*!\s*(?P<cmd>.*)')
752 756
753 757 def transform_assign_system(line):
754 758 """Handle the `files = !ls` syntax."""
755 759 m = _assign_system_re.match(line)
756 760 if m is not None:
757 761 cmd = m.group('cmd')
758 762 lhs = m.group('lhs')
759 763 expr = make_quoted_expr(cmd)
760 764 new_line = '%s = get_ipython().getoutput(%s)' % (lhs, expr)
761 765 return new_line
762 766 return line
763 767
764 768
765 769 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
766 770 r'\s*=\s*%\s*(?P<cmd>.*)')
767 771
768 772 def transform_assign_magic(line):
769 773 """Handle the `a = %who` syntax."""
770 774 m = _assign_magic_re.match(line)
771 775 if m is not None:
772 776 cmd = m.group('cmd')
773 777 lhs = m.group('lhs')
774 778 expr = make_quoted_expr(cmd)
775 779 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
776 780 return new_line
777 781 return line
778 782
779 783
780 784 _classic_prompt_re = re.compile(r'^([ \t]*>>> |^[ \t]*\.\.\. )')
781 785
782 786 def transform_classic_prompt(line):
783 787 """Handle inputs that start with '>>> ' syntax."""
784 788
785 789 if not line or line.isspace():
786 790 return line
787 791 m = _classic_prompt_re.match(line)
788 792 if m:
789 793 return line[len(m.group(0)):]
790 794 else:
791 795 return line
792 796
793 797
794 798 _ipy_prompt_re = re.compile(r'^([ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
795 799
796 800 def transform_ipy_prompt(line):
797 801 """Handle inputs that start classic IPython prompt syntax."""
798 802
799 803 if not line or line.isspace():
800 804 return line
801 805 #print 'LINE: %r' % line # dbg
802 806 m = _ipy_prompt_re.match(line)
803 807 if m:
804 808 #print 'MATCH! %r -> %r' % (line, line[len(m.group(0)):]) # dbg
805 809 return line[len(m.group(0)):]
806 810 else:
807 811 return line
808 812
809 813
810 814 class EscapedTransformer(object):
811 815 """Class to transform lines that are explicitly escaped out."""
812 816
813 817 def __init__(self):
814 818 tr = { ESC_SHELL : self._tr_system,
815 819 ESC_SH_CAP : self._tr_system2,
816 820 ESC_HELP : self._tr_help,
817 821 ESC_HELP2 : self._tr_help,
818 822 ESC_MAGIC : self._tr_magic,
819 823 ESC_QUOTE : self._tr_quote,
820 824 ESC_QUOTE2 : self._tr_quote2,
821 825 ESC_PAREN : self._tr_paren }
822 826 self.tr = tr
823 827
824 828 # Support for syntax transformations that use explicit escapes typed by the
825 829 # user at the beginning of a line
826 830 @staticmethod
827 831 def _tr_system(line_info):
828 832 "Translate lines escaped with: !"
829 833 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
830 834 return '%sget_ipython().system(%s)' % (line_info.lspace,
831 835 make_quoted_expr(cmd))
832 836
833 837 @staticmethod
834 838 def _tr_system2(line_info):
835 839 "Translate lines escaped with: !!"
836 840 cmd = line_info.line.lstrip()[2:]
837 841 return '%sget_ipython().getoutput(%s)' % (line_info.lspace,
838 842 make_quoted_expr(cmd))
839 843
840 844 @staticmethod
841 845 def _tr_help(line_info):
842 846 "Translate lines escaped with: ?/??"
843 847 # A naked help line should just fire the intro help screen
844 848 if not line_info.line[1:]:
845 849 return 'get_ipython().show_usage()'
846 850
847 851 # There may be one or two '?' at the end, move them to the front so that
848 852 # the rest of the logic can assume escapes are at the start
849 853 line = line_info.line
850 854 if line.endswith('?'):
851 855 line = line[-1] + line[:-1]
852 856 if line.endswith('?'):
853 857 line = line[-1] + line[:-1]
854 858 line_info = LineInfo(line)
855 859
856 860 # From here on, simply choose which level of detail to get.
857 861 if line_info.esc == '?':
858 862 pinfo = 'pinfo'
859 863 elif line_info.esc == '??':
860 864 pinfo = 'pinfo2'
861 865
862 866 tpl = '%sget_ipython().magic("%s %s")'
863 867 return tpl % (line_info.lspace, pinfo,
864 868 ' '.join([line_info.fpart, line_info.rest]).strip())
865 869
866 870 @staticmethod
867 871 def _tr_magic(line_info):
868 872 "Translate lines escaped with: %"
869 873 tpl = '%sget_ipython().magic(%s)'
870 874 cmd = make_quoted_expr(' '.join([line_info.fpart,
871 875 line_info.rest]).strip())
872 876 return tpl % (line_info.lspace, cmd)
873 877
874 878 @staticmethod
875 879 def _tr_quote(line_info):
876 880 "Translate lines escaped with: ,"
877 881 return '%s%s("%s")' % (line_info.lspace, line_info.fpart,
878 882 '", "'.join(line_info.rest.split()) )
879 883
880 884 @staticmethod
881 885 def _tr_quote2(line_info):
882 886 "Translate lines escaped with: ;"
883 887 return '%s%s("%s")' % (line_info.lspace, line_info.fpart,
884 888 line_info.rest)
885 889
886 890 @staticmethod
887 891 def _tr_paren(line_info):
888 892 "Translate lines escaped with: /"
889 893 return '%s%s(%s)' % (line_info.lspace, line_info.fpart,
890 894 ", ".join(line_info.rest.split()))
891 895
892 896 def __call__(self, line):
893 897 """Class to transform lines that are explicitly escaped out.
894 898
895 899 This calls the above _tr_* static methods for the actual line
896 900 translations."""
897 901
898 902 # Empty lines just get returned unmodified
899 903 if not line or line.isspace():
900 904 return line
901 905
902 906 # Get line endpoints, where the escapes can be
903 907 line_info = LineInfo(line)
904 908
905 909 # If the escape is not at the start, only '?' needs to be special-cased.
906 910 # All other escapes are only valid at the start
907 911 if not line_info.esc in self.tr:
908 912 if line.endswith(ESC_HELP):
909 913 return self._tr_help(line_info)
910 914 else:
911 915 # If we don't recognize the escape, don't modify the line
912 916 return line
913 917
914 918 return self.tr[line_info.esc](line_info)
915 919
916 920
917 921 # A function-looking object to be used by the rest of the code. The purpose of
918 922 # the class in this case is to organize related functionality, more than to
919 923 # manage state.
920 924 transform_escaped = EscapedTransformer()
921 925
922 926
923 927 class IPythonInputSplitter(InputSplitter):
924 928 """An input splitter that recognizes all of IPython's special syntax."""
925 929
926 930 def push(self, lines):
927 931 """Push one or more lines of IPython input.
928 932 """
929 933 if not lines:
930 934 return super(IPythonInputSplitter, self).push(lines)
931 935
932 936 lines_list = lines.splitlines()
933 937
934 938 transforms = [transform_escaped, transform_assign_system,
935 939 transform_assign_magic, transform_ipy_prompt,
936 940 transform_classic_prompt]
937 941
938 942 # Transform logic
939 943 #
940 944 # We only apply the line transformers to the input if we have either no
941 945 # input yet, or complete input, or if the last line of the buffer ends
942 946 # with ':' (opening an indented block). This prevents the accidental
943 947 # transformation of escapes inside multiline expressions like
944 948 # triple-quoted strings or parenthesized expressions.
945 949 #
946 950 # The last heuristic, while ugly, ensures that the first line of an
947 951 # indented block is correctly transformed.
948 952 #
949 953 # FIXME: try to find a cleaner approach for this last bit.
950 954
951 955 # If we were in 'block' mode, since we're going to pump the parent
952 956 # class by hand line by line, we need to temporarily switch out to
953 957 # 'line' mode, do a single manual reset and then feed the lines one
954 958 # by one. Note that this only matters if the input has more than one
955 959 # line.
956 960 changed_input_mode = False
957 961
958 962 if len(lines_list)>1 and self.input_mode == 'cell':
959 963 self.reset()
960 964 changed_input_mode = True
961 965 saved_input_mode = 'cell'
962 966 self.input_mode = 'line'
963 967
964 968 try:
965 969 push = super(IPythonInputSplitter, self).push
966 970 for line in lines_list:
967 971 if self._is_complete or not self._buffer or \
968 972 (self._buffer and self._buffer[-1].rstrip().endswith(':')):
969 973 for f in transforms:
970 974 line = f(line)
971 975
972 976 out = push(line)
973 977 finally:
974 978 if changed_input_mode:
975 979 self.input_mode = saved_input_mode
976 980
977 981 return out
@@ -1,649 +1,656 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for the inputsplitter module.
3 3 """
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (C) 2010 The IPython Development Team
6 6 #
7 7 # Distributed under the terms of the BSD License. The full license is in
8 8 # the file COPYING, distributed as part of this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14 # stdlib
15 15 import unittest
16 16 import sys
17 17
18 18 # Third party
19 19 import nose.tools as nt
20 20
21 21 # Our own
22 22 from IPython.core import inputsplitter as isp
23 23
24 24 #-----------------------------------------------------------------------------
25 25 # Semi-complete examples (also used as tests)
26 26 #-----------------------------------------------------------------------------
27 27
28 28 # Note: at the bottom, there's a slightly more complete version of this that
29 29 # can be useful during development of code here.
30 30
31 31 def mini_interactive_loop(raw_input):
32 32 """Minimal example of the logic of an interactive interpreter loop.
33 33
34 34 This serves as an example, and it is used by the test system with a fake
35 35 raw_input that simulates interactive input."""
36 36
37 37 from IPython.core.inputsplitter import InputSplitter
38 38
39 39 isp = InputSplitter()
40 40 # In practice, this input loop would be wrapped in an outside loop to read
41 41 # input indefinitely, until some exit/quit command was issued. Here we
42 42 # only illustrate the basic inner loop.
43 43 while isp.push_accepts_more():
44 44 indent = ' '*isp.indent_spaces
45 45 prompt = '>>> ' + indent
46 46 line = indent + raw_input(prompt)
47 47 isp.push(line)
48 48
49 49 # Here we just return input so we can use it in a test suite, but a real
50 50 # interpreter would instead send it for execution somewhere.
51 51 src = isp.source_reset()
52 52 #print 'Input source was:\n', src # dbg
53 53 return src
54 54
55 55 #-----------------------------------------------------------------------------
56 56 # Test utilities, just for local use
57 57 #-----------------------------------------------------------------------------
58 58
59 59 def assemble(block):
60 60 """Assemble a block into multi-line sub-blocks."""
61 61 return ['\n'.join(sub_block)+'\n' for sub_block in block]
62 62
63 63
64 64 def pseudo_input(lines):
65 65 """Return a function that acts like raw_input but feeds the input list."""
66 66 ilines = iter(lines)
67 67 def raw_in(prompt):
68 68 try:
69 69 return next(ilines)
70 70 except StopIteration:
71 71 return ''
72 72 return raw_in
73 73
74 74 #-----------------------------------------------------------------------------
75 75 # Tests
76 76 #-----------------------------------------------------------------------------
77 77 def test_spaces():
78 78 tests = [('', 0),
79 79 (' ', 1),
80 80 ('\n', 0),
81 81 (' \n', 1),
82 82 ('x', 0),
83 83 (' x', 1),
84 84 (' x',2),
85 85 (' x',4),
86 86 # Note: tabs are counted as a single whitespace!
87 87 ('\tx', 1),
88 88 ('\t x', 2),
89 89 ]
90 90
91 91 for s, nsp in tests:
92 92 nt.assert_equal(isp.num_ini_spaces(s), nsp)
93 93
94 94
95 95 def test_remove_comments():
96 96 tests = [('text', 'text'),
97 97 ('text # comment', 'text '),
98 98 ('text # comment\n', 'text \n'),
99 99 ('text # comment \n', 'text \n'),
100 100 ('line # c \nline\n','line \nline\n'),
101 101 ('line # c \nline#c2 \nline\nline #c\n\n',
102 102 'line \nline\nline\nline \n\n'),
103 103 ]
104 104
105 105 for inp, out in tests:
106 106 nt.assert_equal(isp.remove_comments(inp), out)
107 107
108 108
109 109 def test_get_input_encoding():
110 110 encoding = isp.get_input_encoding()
111 111 nt.assert_true(isinstance(encoding, basestring))
112 112 # simple-minded check that at least encoding a simple string works with the
113 113 # encoding we got.
114 114 nt.assert_equal('test'.encode(encoding), 'test')
115 115
116 116
117 117 class NoInputEncodingTestCase(unittest.TestCase):
118 118 def setUp(self):
119 119 self.old_stdin = sys.stdin
120 120 class X: pass
121 121 fake_stdin = X()
122 122 sys.stdin = fake_stdin
123 123
124 124 def test(self):
125 125 # Verify that if sys.stdin has no 'encoding' attribute we do the right
126 126 # thing
127 127 enc = isp.get_input_encoding()
128 128 self.assertEqual(enc, 'ascii')
129 129
130 130 def tearDown(self):
131 131 sys.stdin = self.old_stdin
132 132
133 133
134 134 class InputSplitterTestCase(unittest.TestCase):
135 135 def setUp(self):
136 136 self.isp = isp.InputSplitter()
137 137
138 138 def test_reset(self):
139 139 isp = self.isp
140 140 isp.push('x=1')
141 141 isp.reset()
142 142 self.assertEqual(isp._buffer, [])
143 143 self.assertEqual(isp.indent_spaces, 0)
144 144 self.assertEqual(isp.source, '')
145 145 self.assertEqual(isp.code, None)
146 146 self.assertEqual(isp._is_complete, False)
147 147
148 148 def test_source(self):
149 149 self.isp._store('1')
150 150 self.isp._store('2')
151 151 self.assertEqual(self.isp.source, '1\n2\n')
152 152 self.assertTrue(len(self.isp._buffer)>0)
153 153 self.assertEqual(self.isp.source_reset(), '1\n2\n')
154 154 self.assertEqual(self.isp._buffer, [])
155 155 self.assertEqual(self.isp.source, '')
156 156
157 157 def test_indent(self):
158 158 isp = self.isp # shorthand
159 159 isp.push('x=1')
160 160 self.assertEqual(isp.indent_spaces, 0)
161 161 isp.push('if 1:\n x=1')
162 162 self.assertEqual(isp.indent_spaces, 4)
163 163 isp.push('y=2\n')
164 164 self.assertEqual(isp.indent_spaces, 0)
165 165 isp.push('if 1:')
166 166 self.assertEqual(isp.indent_spaces, 4)
167 167 isp.push(' x=1')
168 168 self.assertEqual(isp.indent_spaces, 4)
169 169 # Blank lines shouldn't change the indent level
170 170 isp.push(' '*2)
171 171 self.assertEqual(isp.indent_spaces, 4)
172 172
173 173 def test_indent2(self):
174 174 isp = self.isp
175 175 # When a multiline statement contains parens or multiline strings, we
176 176 # shouldn't get confused.
177 177 isp.push("if 1:")
178 178 isp.push(" x = (1+\n 2)")
179 179 self.assertEqual(isp.indent_spaces, 4)
180 180
181 181 def test_dedent(self):
182 182 isp = self.isp # shorthand
183 183 isp.push('if 1:')
184 184 self.assertEqual(isp.indent_spaces, 4)
185 185 isp.push(' pass')
186 186 self.assertEqual(isp.indent_spaces, 0)
187 187
188 188 def test_push(self):
189 189 isp = self.isp
190 190 self.assertTrue(isp.push('x=1'))
191 191
192 192 def test_push2(self):
193 193 isp = self.isp
194 194 self.assertFalse(isp.push('if 1:'))
195 195 for line in [' x=1', '# a comment', ' y=2']:
196 196 self.assertTrue(isp.push(line))
197 197
198 198 def test_push3(self):
199 199 """Test input with leading whitespace"""
200 200 isp = self.isp
201 201 isp.push(' x=1')
202 202 isp.push(' y=2')
203 203 self.assertEqual(isp.source, 'if 1:\n x=1\n y=2\n')
204 204
205 205 def test_replace_mode(self):
206 206 isp = self.isp
207 207 isp.input_mode = 'cell'
208 208 isp.push('x=1')
209 209 self.assertEqual(isp.source, 'x=1\n')
210 210 isp.push('x=2')
211 211 self.assertEqual(isp.source, 'x=2\n')
212 212
213 213 def test_push_accepts_more(self):
214 214 isp = self.isp
215 215 isp.push('x=1')
216 216 self.assertFalse(isp.push_accepts_more())
217 217
218 218 def test_push_accepts_more2(self):
219 219 isp = self.isp
220 220 isp.push('if 1:')
221 221 self.assertTrue(isp.push_accepts_more())
222 222 isp.push(' x=1')
223 223 self.assertTrue(isp.push_accepts_more())
224 224 isp.push('')
225 225 self.assertFalse(isp.push_accepts_more())
226 226
227 227 def test_push_accepts_more3(self):
228 228 isp = self.isp
229 229 isp.push("x = (2+\n3)")
230 230 self.assertFalse(isp.push_accepts_more())
231 231
232 232 def test_push_accepts_more4(self):
233 233 isp = self.isp
234 234 # When a multiline statement contains parens or multiline strings, we
235 235 # shouldn't get confused.
236 236 # FIXME: we should be able to better handle de-dents in statements like
237 237 # multiline strings and multiline expressions (continued with \ or
238 238 # parens). Right now we aren't handling the indentation tracking quite
239 239 # correctly with this, though in practice it may not be too much of a
240 240 # problem. We'll need to see.
241 241 isp.push("if 1:")
242 242 isp.push(" x = (2+")
243 243 isp.push(" 3)")
244 244 self.assertTrue(isp.push_accepts_more())
245 245 isp.push(" y = 3")
246 246 self.assertTrue(isp.push_accepts_more())
247 247 isp.push('')
248 248 self.assertFalse(isp.push_accepts_more())
249 249
250 def test_continuation(self):
251 isp = self.isp
252 isp.push("import os, \\")
253 self.assertTrue(isp.push_accepts_more())
254 isp.push("sys")
255 self.assertFalse(isp.push_accepts_more())
256
250 257 def test_syntax_error(self):
251 258 isp = self.isp
252 259 # Syntax errors immediately produce a 'ready' block, so the invalid
253 260 # Python can be sent to the kernel for evaluation with possible ipython
254 261 # special-syntax conversion.
255 262 isp.push('run foo')
256 263 self.assertFalse(isp.push_accepts_more())
257 264
258 265 def check_split(self, block_lines, compile=True):
259 266 blocks = assemble(block_lines)
260 267 lines = ''.join(blocks)
261 268 oblock = self.isp.split_blocks(lines)
262 269 self.assertEqual(oblock, blocks)
263 270 if compile:
264 271 for block in blocks:
265 272 self.isp._compile(block)
266 273
267 274 def test_split(self):
268 275 # All blocks of input we want to test in a list. The format for each
269 276 # block is a list of lists, with each inner lists consisting of all the
270 277 # lines (as single-lines) that should make up a sub-block.
271 278
272 279 # Note: do NOT put here sub-blocks that don't compile, as the
273 280 # check_split() routine makes a final verification pass to check that
274 281 # each sub_block, as returned by split_blocks(), does compile
275 282 # correctly.
276 283 all_blocks = [ [['x=1']],
277 284
278 285 [['x=1'],
279 286 ['y=2']],
280 287
281 288 [['x=1',
282 289 '# a comment'],
283 290 ['y=11']],
284 291
285 292 [['if 1:',
286 293 ' x=1'],
287 294 ['y=3']],
288 295
289 296 [['def f(x):',
290 297 ' return x'],
291 298 ['x=1']],
292 299
293 300 [['def f(x):',
294 301 ' x+=1',
295 302 ' ',
296 303 ' return x'],
297 304 ['x=1']],
298 305
299 306 [['def f(x):',
300 307 ' if x>0:',
301 308 ' y=1',
302 309 ' # a comment',
303 310 ' else:',
304 311 ' y=4',
305 312 ' ',
306 313 ' return y'],
307 314 ['x=1'],
308 315 ['if 1:',
309 316 ' y=11'] ],
310 317
311 318 [['for i in range(10):'
312 319 ' x=i**2']],
313 320
314 321 [['for i in range(10):'
315 322 ' x=i**2'],
316 323 ['z = 1']],
317 324 ]
318 325 for block_lines in all_blocks:
319 326 self.check_split(block_lines)
320 327
321 328 def test_split_syntax_errors(self):
322 329 # Block splitting with invalid syntax
323 330 all_blocks = [ [['a syntax error']],
324 331
325 332 [['x=1',
326 333 'another syntax error']],
327 334
328 335 [['for i in range(10):'
329 336 ' yet another error']],
330 337
331 338 ]
332 339 for block_lines in all_blocks:
333 340 self.check_split(block_lines, compile=False)
334 341
335 342
336 343 class InteractiveLoopTestCase(unittest.TestCase):
337 344 """Tests for an interactive loop like a python shell.
338 345 """
339 346 def check_ns(self, lines, ns):
340 347 """Validate that the given input lines produce the resulting namespace.
341 348
342 349 Note: the input lines are given exactly as they would be typed in an
343 350 auto-indenting environment, as mini_interactive_loop above already does
344 351 auto-indenting and prepends spaces to the input.
345 352 """
346 353 src = mini_interactive_loop(pseudo_input(lines))
347 354 test_ns = {}
348 355 exec src in test_ns
349 356 # We can't check that the provided ns is identical to the test_ns,
350 357 # because Python fills test_ns with extra keys (copyright, etc). But
351 358 # we can check that the given dict is *contained* in test_ns
352 359 for k,v in ns.items():
353 360 self.assertEqual(test_ns[k], v)
354 361
355 362 def test_simple(self):
356 363 self.check_ns(['x=1'], dict(x=1))
357 364
358 365 def test_simple2(self):
359 366 self.check_ns(['if 1:', 'x=2'], dict(x=2))
360 367
361 368 def test_xy(self):
362 369 self.check_ns(['x=1; y=2'], dict(x=1, y=2))
363 370
364 371 def test_abc(self):
365 372 self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3))
366 373
367 374 def test_multi(self):
368 375 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
369 376
370 377
371 378 def test_LineInfo():
372 379 """Simple test for LineInfo construction and str()"""
373 380 linfo = isp.LineInfo(' %cd /home')
374 381 nt.assert_equals(str(linfo), 'LineInfo [ |%|cd|/home]')
375 382
376 383
377 384 def test_split_user_input():
378 385 """Unicode test - split_user_input already has good doctests"""
379 386 line = u"PΓ©rez Fernando"
380 387 parts = isp.split_user_input(line)
381 388 parts_expected = (u'', u'', u'', line)
382 389 nt.assert_equal(parts, parts_expected)
383 390
384 391
385 392 # Transformer tests
386 393 def transform_checker(tests, func):
387 394 """Utility to loop over test inputs"""
388 395 for inp, tr in tests:
389 396 nt.assert_equals(func(inp), tr)
390 397
391 398 # Data for all the syntax tests in the form of lists of pairs of
392 399 # raw/transformed input. We store it here as a global dict so that we can use
393 400 # it both within single-function tests and also to validate the behavior of the
394 401 # larger objects
395 402
396 403 syntax = \
397 404 dict(assign_system =
398 405 [('a =! ls', 'a = get_ipython().getoutput("ls")'),
399 406 ('b = !ls', 'b = get_ipython().getoutput("ls")'),
400 407 ('x=1', 'x=1'), # normal input is unmodified
401 408 (' ',' '), # blank lines are kept intact
402 409 ],
403 410
404 411 assign_magic =
405 412 [('a =% who', 'a = get_ipython().magic("who")'),
406 413 ('b = %who', 'b = get_ipython().magic("who")'),
407 414 ('x=1', 'x=1'), # normal input is unmodified
408 415 (' ',' '), # blank lines are kept intact
409 416 ],
410 417
411 418 classic_prompt =
412 419 [('>>> x=1', 'x=1'),
413 420 ('x=1', 'x=1'), # normal input is unmodified
414 421 (' ', ' '), # blank lines are kept intact
415 422 ('... ', ''), # continuation prompts
416 423 ],
417 424
418 425 ipy_prompt =
419 426 [('In [1]: x=1', 'x=1'),
420 427 ('x=1', 'x=1'), # normal input is unmodified
421 428 (' ',' '), # blank lines are kept intact
422 429 (' ....: ', ''), # continuation prompts
423 430 ],
424 431
425 432 # Tests for the escape transformer to leave normal code alone
426 433 escaped_noesc =
427 434 [ (' ', ' '),
428 435 ('x=1', 'x=1'),
429 436 ],
430 437
431 438 # System calls
432 439 escaped_shell =
433 440 [ ('!ls', 'get_ipython().system("ls")'),
434 441 # Double-escape shell, this means to capture the output of the
435 442 # subprocess and return it
436 443 ('!!ls', 'get_ipython().getoutput("ls")'),
437 444 ],
438 445
439 446 # Help/object info
440 447 escaped_help =
441 448 [ ('?', 'get_ipython().show_usage()'),
442 449 ('?x1', 'get_ipython().magic("pinfo x1")'),
443 450 ('??x2', 'get_ipython().magic("pinfo2 x2")'),
444 451 ('x3?', 'get_ipython().magic("pinfo x3")'),
445 452 ('x4??', 'get_ipython().magic("pinfo2 x4")'),
446 453 ('%hist?', 'get_ipython().magic("pinfo %hist")'),
447 454 ],
448 455
449 456 # Explicit magic calls
450 457 escaped_magic =
451 458 [ ('%cd', 'get_ipython().magic("cd")'),
452 459 ('%cd /home', 'get_ipython().magic("cd /home")'),
453 460 (' %magic', ' get_ipython().magic("magic")'),
454 461 ],
455 462
456 463 # Quoting with separate arguments
457 464 escaped_quote =
458 465 [ (',f', 'f("")'),
459 466 (',f x', 'f("x")'),
460 467 (' ,f y', ' f("y")'),
461 468 (',f a b', 'f("a", "b")'),
462 469 ],
463 470
464 471 # Quoting with single argument
465 472 escaped_quote2 =
466 473 [ (';f', 'f("")'),
467 474 (';f x', 'f("x")'),
468 475 (' ;f y', ' f("y")'),
469 476 (';f a b', 'f("a b")'),
470 477 ],
471 478
472 479 # Simply apply parens
473 480 escaped_paren =
474 481 [ ('/f', 'f()'),
475 482 ('/f x', 'f(x)'),
476 483 (' /f y', ' f(y)'),
477 484 ('/f a b', 'f(a, b)'),
478 485 ],
479 486
480 487 )
481 488
482 489 # multiline syntax examples. Each of these should be a list of lists, with
483 490 # each entry itself having pairs of raw/transformed input. The union (with
484 491 # '\n'.join() of the transformed inputs is what the splitter should produce
485 492 # when fed the raw lines one at a time via push.
486 493 syntax_ml = \
487 494 dict(classic_prompt =
488 495 [ [('>>> for i in range(10):','for i in range(10):'),
489 496 ('... print i',' print i'),
490 497 ('... ', ''),
491 498 ],
492 499 ],
493 500
494 501 ipy_prompt =
495 502 [ [('In [24]: for i in range(10):','for i in range(10):'),
496 503 (' ....: print i',' print i'),
497 504 (' ....: ', ''),
498 505 ],
499 506 ],
500 507 )
501 508
502 509
503 510 def test_assign_system():
504 511 transform_checker(syntax['assign_system'], isp.transform_assign_system)
505 512
506 513
507 514 def test_assign_magic():
508 515 transform_checker(syntax['assign_magic'], isp.transform_assign_magic)
509 516
510 517
511 518 def test_classic_prompt():
512 519 transform_checker(syntax['classic_prompt'], isp.transform_classic_prompt)
513 520 for example in syntax_ml['classic_prompt']:
514 521 transform_checker(example, isp.transform_classic_prompt)
515 522
516 523
517 524 def test_ipy_prompt():
518 525 transform_checker(syntax['ipy_prompt'], isp.transform_ipy_prompt)
519 526 for example in syntax_ml['ipy_prompt']:
520 527 transform_checker(example, isp.transform_ipy_prompt)
521 528
522 529
523 530 def test_escaped_noesc():
524 531 transform_checker(syntax['escaped_noesc'], isp.transform_escaped)
525 532
526 533
527 534 def test_escaped_shell():
528 535 transform_checker(syntax['escaped_shell'], isp.transform_escaped)
529 536
530 537
531 538 def test_escaped_help():
532 539 transform_checker(syntax['escaped_help'], isp.transform_escaped)
533 540
534 541
535 542 def test_escaped_magic():
536 543 transform_checker(syntax['escaped_magic'], isp.transform_escaped)
537 544
538 545
539 546 def test_escaped_quote():
540 547 transform_checker(syntax['escaped_quote'], isp.transform_escaped)
541 548
542 549
543 550 def test_escaped_quote2():
544 551 transform_checker(syntax['escaped_quote2'], isp.transform_escaped)
545 552
546 553
547 554 def test_escaped_paren():
548 555 transform_checker(syntax['escaped_paren'], isp.transform_escaped)
549 556
550 557
551 558 class IPythonInputTestCase(InputSplitterTestCase):
552 559 """By just creating a new class whose .isp is a different instance, we
553 560 re-run the same test battery on the new input splitter.
554 561
555 562 In addition, this runs the tests over the syntax and syntax_ml dicts that
556 563 were tested by individual functions, as part of the OO interface.
557 564 """
558 565
559 566 def setUp(self):
560 567 self.isp = isp.IPythonInputSplitter(input_mode='line')
561 568
562 569 def test_syntax(self):
563 570 """Call all single-line syntax tests from the main object"""
564 571 isp = self.isp
565 572 for example in syntax.itervalues():
566 573 for raw, out_t in example:
567 574 if raw.startswith(' '):
568 575 continue
569 576
570 577 isp.push(raw)
571 578 out = isp.source_reset().rstrip()
572 579 self.assertEqual(out, out_t)
573 580
574 581 def test_syntax_multiline(self):
575 582 isp = self.isp
576 583 for example in syntax_ml.itervalues():
577 584 out_t_parts = []
578 585 for line_pairs in example:
579 586 for raw, out_t_part in line_pairs:
580 587 isp.push(raw)
581 588 out_t_parts.append(out_t_part)
582 589
583 590 out = isp.source_reset().rstrip()
584 591 out_t = '\n'.join(out_t_parts).rstrip()
585 592 self.assertEqual(out, out_t)
586 593
587 594
588 595 class BlockIPythonInputTestCase(IPythonInputTestCase):
589 596
590 597 # Deactivate tests that don't make sense for the block mode
591 598 test_push3 = test_split = lambda s: None
592 599
593 600 def setUp(self):
594 601 self.isp = isp.IPythonInputSplitter(input_mode='cell')
595 602
596 603 def test_syntax_multiline(self):
597 604 isp = self.isp
598 605 for example in syntax_ml.itervalues():
599 606 raw_parts = []
600 607 out_t_parts = []
601 608 for line_pairs in example:
602 609 for raw, out_t_part in line_pairs:
603 610 raw_parts.append(raw)
604 611 out_t_parts.append(out_t_part)
605 612
606 613 raw = '\n'.join(raw_parts)
607 614 out_t = '\n'.join(out_t_parts)
608 615
609 616 isp.push(raw)
610 617 out = isp.source_reset()
611 618 # Match ignoring trailing whitespace
612 619 self.assertEqual(out.rstrip(), out_t.rstrip())
613 620
614 621
615 622 #-----------------------------------------------------------------------------
616 623 # Main - use as a script, mostly for developer experiments
617 624 #-----------------------------------------------------------------------------
618 625
619 626 if __name__ == '__main__':
620 627 # A simple demo for interactive experimentation. This code will not get
621 628 # picked up by any test suite.
622 629 from IPython.core.inputsplitter import InputSplitter, IPythonInputSplitter
623 630
624 631 # configure here the syntax to use, prompt and whether to autoindent
625 632 #isp, start_prompt = InputSplitter(), '>>> '
626 633 isp, start_prompt = IPythonInputSplitter(), 'In> '
627 634
628 635 autoindent = True
629 636 #autoindent = False
630 637
631 638 try:
632 639 while True:
633 640 prompt = start_prompt
634 641 while isp.push_accepts_more():
635 642 indent = ' '*isp.indent_spaces
636 643 if autoindent:
637 644 line = indent + raw_input(prompt+indent)
638 645 else:
639 646 line = raw_input(prompt)
640 647 isp.push(line)
641 648 prompt = '... '
642 649
643 650 # Here we just return input so we can use it in a test suite, but a
644 651 # real interpreter would instead send it for execution somewhere.
645 652 #src = isp.source; raise EOFError # dbg
646 653 src = isp.source_reset()
647 654 print 'Input source was:\n', src
648 655 except EOFError:
649 656 print 'Bye'
General Comments 0
You need to be logged in to leave comments. Login now