##// END OF EJS Templates
Fix bug for x.*a*? syntax, added tests for it.
Fernando Perez -
Show More
@@ -1,981 +1,987 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 391 # Honor termination lines properly
392 392 if source.rstrip().endswith('\\'):
393 393 return False
394 394
395 395 self._update_indent(lines)
396 396 try:
397 397 self.code = self._compile(source)
398 398 # Invalid syntax can produce any of a number of different errors from
399 399 # inside the compiler, so we have to catch them all. Syntax errors
400 400 # immediately produce a 'ready' block, so the invalid Python can be
401 401 # sent to the kernel for evaluation with possible ipython
402 402 # special-syntax conversion.
403 403 except (SyntaxError, OverflowError, ValueError, TypeError,
404 404 MemoryError):
405 405 self._is_complete = True
406 406 else:
407 407 # Compilation didn't produce any exceptions (though it may not have
408 408 # given a complete code object)
409 409 self._is_complete = self.code is not None
410 410
411 411 return self._is_complete
412 412
413 413 def push_accepts_more(self):
414 414 """Return whether a block of interactive input can accept more input.
415 415
416 416 This method is meant to be used by line-oriented frontends, who need to
417 417 guess whether a block is complete or not based solely on prior and
418 418 current input lines. The InputSplitter considers it has a complete
419 419 interactive block and will not accept more input only when either a
420 420 SyntaxError is raised, or *all* of the following are true:
421 421
422 422 1. The input compiles to a complete statement.
423 423
424 424 2. The indentation level is flush-left (because if we are indented,
425 425 like inside a function definition or for loop, we need to keep
426 426 reading new input).
427 427
428 428 3. There is one extra line consisting only of whitespace.
429 429
430 430 Because of condition #3, this method should be used only by
431 431 *line-oriented* frontends, since it means that intermediate blank lines
432 432 are not allowed in function definitions (or any other indented block).
433 433
434 434 Block-oriented frontends that have a separate keyboard event to
435 435 indicate execution should use the :meth:`split_blocks` method instead.
436 436
437 437 If the current input produces a syntax error, this method immediately
438 438 returns False but does *not* raise the syntax error exception, as
439 439 typically clients will want to send invalid syntax to an execution
440 440 backend which might convert the invalid syntax into valid Python via
441 441 one of the dynamic IPython mechanisms.
442 442 """
443 443
444 444 # With incomplete input, unconditionally accept more
445 445 if not self._is_complete:
446 446 return True
447 447
448 448 # If we already have complete input and we're flush left, the answer
449 449 # depends. In line mode, we're done. But in cell mode, we need to
450 450 # check how many blocks the input so far compiles into, because if
451 451 # there's already more than one full independent block of input, then
452 452 # the client has entered full 'cell' mode and is feeding lines that
453 453 # each is complete. In this case we should then keep accepting.
454 454 # The Qt terminal-like console does precisely this, to provide the
455 455 # convenience of terminal-like input of single expressions, but
456 456 # allowing the user (with a separate keystroke) to switch to 'cell'
457 457 # mode and type multiple expressions in one shot.
458 458 if self.indent_spaces==0:
459 459 if self.input_mode=='line':
460 460 return False
461 461 else:
462 462 nblocks = len(split_blocks(''.join(self._buffer)))
463 463 if nblocks==1:
464 464 return False
465 465
466 466 # When input is complete, then termination is marked by an extra blank
467 467 # line at the end.
468 468 last_line = self.source.splitlines()[-1]
469 469 return bool(last_line and not last_line.isspace())
470 470
471 471 def split_blocks(self, lines):
472 472 """Split a multiline string into multiple input blocks.
473 473
474 474 Note: this method starts by performing a full reset().
475 475
476 476 Parameters
477 477 ----------
478 478 lines : str
479 479 A possibly multiline string.
480 480
481 481 Returns
482 482 -------
483 483 blocks : list
484 484 A list of strings, each possibly multiline. Each string corresponds
485 485 to a single block that can be compiled in 'single' mode (unless it
486 486 has a syntax error)."""
487 487
488 488 # This code is fairly delicate. If you make any changes here, make
489 489 # absolutely sure that you do run the full test suite and ALL tests
490 490 # pass.
491 491
492 492 self.reset()
493 493 blocks = []
494 494
495 495 # Reversed copy so we can use pop() efficiently and consume the input
496 496 # as a stack
497 497 lines = lines.splitlines()[::-1]
498 498 # Outer loop over all input
499 499 while lines:
500 500 #print 'Current lines:', lines # dbg
501 501 # Inner loop to build each block
502 502 while True:
503 503 # Safety exit from inner loop
504 504 if not lines:
505 505 break
506 506 # Grab next line but don't push it yet
507 507 next_line = lines.pop()
508 508 # Blank/empty lines are pushed as-is
509 509 if not next_line or next_line.isspace():
510 510 self.push(next_line)
511 511 continue
512 512
513 513 # Check indentation changes caused by the *next* line
514 514 indent_spaces, _full_dedent = self._find_indent(next_line)
515 515
516 516 # If the next line causes a dedent, it can be for two differnt
517 517 # reasons: either an explicit de-dent by the user or a
518 518 # return/raise/pass statement. These MUST be handled
519 519 # separately:
520 520 #
521 521 # 1. the first case is only detected when the actual explicit
522 522 # dedent happens, and that would be the *first* line of a *new*
523 523 # block. Thus, we must put the line back into the input buffer
524 524 # so that it starts a new block on the next pass.
525 525 #
526 526 # 2. the second case is detected in the line before the actual
527 527 # dedent happens, so , we consume the line and we can break out
528 528 # to start a new block.
529 529
530 530 # Case 1, explicit dedent causes a break.
531 531 # Note: check that we weren't on the very last line, else we'll
532 532 # enter an infinite loop adding/removing the last line.
533 533 if _full_dedent and lines and not next_line.startswith(' '):
534 534 lines.append(next_line)
535 535 break
536 536
537 537 # Otherwise any line is pushed
538 538 self.push(next_line)
539 539
540 540 # Case 2, full dedent with full block ready:
541 541 if _full_dedent or \
542 542 self.indent_spaces==0 and not self.push_accepts_more():
543 543 break
544 544 # Form the new block with the current source input
545 545 blocks.append(self.source_reset())
546 546
547 547 #return blocks
548 548 # HACK!!! Now that our input is in blocks but guaranteed to be pure
549 549 # python syntax, feed it back a second time through the AST-based
550 550 # splitter, which is more accurate than ours.
551 551 return split_blocks(''.join(blocks))
552 552
553 553 #------------------------------------------------------------------------
554 554 # Private interface
555 555 #------------------------------------------------------------------------
556 556
557 557 def _find_indent(self, line):
558 558 """Compute the new indentation level for a single line.
559 559
560 560 Parameters
561 561 ----------
562 562 line : str
563 563 A single new line of non-whitespace, non-comment Python input.
564 564
565 565 Returns
566 566 -------
567 567 indent_spaces : int
568 568 New value for the indent level (it may be equal to self.indent_spaces
569 569 if indentation doesn't change.
570 570
571 571 full_dedent : boolean
572 572 Whether the new line causes a full flush-left dedent.
573 573 """
574 574 indent_spaces = self.indent_spaces
575 575 full_dedent = self._full_dedent
576 576
577 577 inisp = num_ini_spaces(line)
578 578 if inisp < indent_spaces:
579 579 indent_spaces = inisp
580 580 if indent_spaces <= 0:
581 581 #print 'Full dedent in text',self.source # dbg
582 582 full_dedent = True
583 583
584 584 if line[-1] == ':':
585 585 indent_spaces += 4
586 586 elif dedent_re.match(line):
587 587 indent_spaces -= 4
588 588 if indent_spaces <= 0:
589 589 full_dedent = True
590 590
591 591 # Safety
592 592 if indent_spaces < 0:
593 593 indent_spaces = 0
594 594 #print 'safety' # dbg
595 595
596 596 return indent_spaces, full_dedent
597 597
598 598 def _update_indent(self, lines):
599 599 for line in remove_comments(lines).splitlines():
600 600 if line and not line.isspace():
601 601 self.indent_spaces, self._full_dedent = self._find_indent(line)
602 602
603 603 def _store(self, lines):
604 604 """Store one or more lines of input.
605 605
606 606 If input lines are not newline-terminated, a newline is automatically
607 607 appended."""
608 608
609 609 if lines.endswith('\n'):
610 610 self._buffer.append(lines)
611 611 else:
612 612 self._buffer.append(lines+'\n')
613 613 self._set_source()
614 614
615 615 def _set_source(self):
616 616 self.source = ''.join(self._buffer).encode(self.encoding)
617 617
618 618
619 619 #-----------------------------------------------------------------------------
620 620 # Functions and classes for IPython-specific syntactic support
621 621 #-----------------------------------------------------------------------------
622 622
623 623 # RegExp for splitting line contents into pre-char//first word-method//rest.
624 624 # For clarity, each group in on one line.
625 625
626 626 line_split = re.compile("""
627 627 ^(\s*) # any leading space
628 628 ([,;/%]|!!?|\?\??) # escape character or characters
629 \s*(%?[\w\.]*) # function/method, possibly with leading %
629 \s*(%?[\w\.\*]*) # function/method, possibly with leading %
630 630 # to correctly treat things like '?%magic'
631 631 (\s+.*$|$) # rest of line
632 632 """, re.VERBOSE)
633 633
634 634
635 635 def split_user_input(line):
636 636 """Split user input into early whitespace, esc-char, function part and rest.
637 637
638 638 This is currently handles lines with '=' in them in a very inconsistent
639 639 manner.
640 640
641 641 Examples
642 642 ========
643 643 >>> split_user_input('x=1')
644 644 ('', '', 'x=1', '')
645 645 >>> split_user_input('?')
646 646 ('', '?', '', '')
647 647 >>> split_user_input('??')
648 648 ('', '??', '', '')
649 649 >>> split_user_input(' ?')
650 650 (' ', '?', '', '')
651 651 >>> split_user_input(' ??')
652 652 (' ', '??', '', '')
653 653 >>> split_user_input('??x')
654 654 ('', '??', 'x', '')
655 655 >>> split_user_input('?x=1')
656 656 ('', '', '?x=1', '')
657 657 >>> split_user_input('!ls')
658 658 ('', '!', 'ls', '')
659 659 >>> split_user_input(' !ls')
660 660 (' ', '!', 'ls', '')
661 661 >>> split_user_input('!!ls')
662 662 ('', '!!', 'ls', '')
663 663 >>> split_user_input(' !!ls')
664 664 (' ', '!!', 'ls', '')
665 665 >>> split_user_input(',ls')
666 666 ('', ',', 'ls', '')
667 667 >>> split_user_input(';ls')
668 668 ('', ';', 'ls', '')
669 669 >>> split_user_input(' ;ls')
670 670 (' ', ';', 'ls', '')
671 671 >>> split_user_input('f.g(x)')
672 672 ('', '', 'f.g(x)', '')
673 673 >>> split_user_input('f.g (x)')
674 674 ('', '', 'f.g', '(x)')
675 675 >>> split_user_input('?%hist')
676 676 ('', '?', '%hist', '')
677 >>> split_user_input('?x*')
678 ('', '?', 'x*', '')
677 679 """
678 680 match = line_split.match(line)
679 681 if match:
680 682 lspace, esc, fpart, rest = match.groups()
681 683 else:
682 684 # print "match failed for line '%s'" % line
683 685 try:
684 686 fpart, rest = line.split(None, 1)
685 687 except ValueError:
686 688 # print "split failed for line '%s'" % line
687 689 fpart, rest = line,''
688 690 lspace = re.match('^(\s*)(.*)', line).groups()[0]
689 691 esc = ''
690 692
691 693 # fpart has to be a valid python identifier, so it better be only pure
692 694 # ascii, no unicode:
693 695 try:
694 696 fpart = fpart.encode('ascii')
695 697 except UnicodeEncodeError:
696 698 lspace = unicode(lspace)
697 699 rest = fpart + u' ' + rest
698 700 fpart = u''
699 701
700 702 #print 'line:<%s>' % line # dbg
701 703 #print 'esc <%s> fpart <%s> rest <%s>' % (esc,fpart.strip(),rest) # dbg
702 704 return lspace, esc, fpart.strip(), rest.lstrip()
703 705
704 706
705 707 # The escaped translators ALL receive a line where their own escape has been
706 708 # stripped. Only '?' is valid at the end of the line, all others can only be
707 709 # placed at the start.
708 710
709 711 class LineInfo(object):
710 712 """A single line of input and associated info.
711 713
712 714 This is a utility class that mostly wraps the output of
713 715 :func:`split_user_input` into a convenient object to be passed around
714 716 during input transformations.
715 717
716 718 Includes the following as properties:
717 719
718 720 line
719 721 The original, raw line
720 722
721 723 lspace
722 724 Any early whitespace before actual text starts.
723 725
724 726 esc
725 727 The initial esc character (or characters, for double-char escapes like
726 728 '??' or '!!').
727 729
728 730 fpart
729 731 The 'function part', which is basically the maximal initial sequence
730 732 of valid python identifiers and the '.' character. This is what is
731 733 checked for alias and magic transformations, used for auto-calling,
732 734 etc.
733 735
734 736 rest
735 737 Everything else on the line.
736 738 """
737 739 def __init__(self, line):
738 740 self.line = line
739 741 self.lspace, self.esc, self.fpart, self.rest = \
740 742 split_user_input(line)
741 743
742 744 def __str__(self):
743 745 return "LineInfo [%s|%s|%s|%s]" % (self.lspace, self.esc,
744 746 self.fpart, self.rest)
745 747
746 748
747 749 # Transformations of the special syntaxes that don't rely on an explicit escape
748 750 # character but instead on patterns on the input line
749 751
750 752 # The core transformations are implemented as standalone functions that can be
751 753 # tested and validated in isolation. Each of these uses a regexp, we
752 754 # pre-compile these and keep them close to each function definition for clarity
753 755
754 756 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
755 757 r'\s*=\s*!\s*(?P<cmd>.*)')
756 758
757 759 def transform_assign_system(line):
758 760 """Handle the `files = !ls` syntax."""
759 761 m = _assign_system_re.match(line)
760 762 if m is not None:
761 763 cmd = m.group('cmd')
762 764 lhs = m.group('lhs')
763 765 expr = make_quoted_expr(cmd)
764 766 new_line = '%s = get_ipython().getoutput(%s)' % (lhs, expr)
765 767 return new_line
766 768 return line
767 769
768 770
769 771 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
770 772 r'\s*=\s*%\s*(?P<cmd>.*)')
771 773
772 774 def transform_assign_magic(line):
773 775 """Handle the `a = %who` syntax."""
774 776 m = _assign_magic_re.match(line)
775 777 if m is not None:
776 778 cmd = m.group('cmd')
777 779 lhs = m.group('lhs')
778 780 expr = make_quoted_expr(cmd)
779 781 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
780 782 return new_line
781 783 return line
782 784
783 785
784 786 _classic_prompt_re = re.compile(r'^([ \t]*>>> |^[ \t]*\.\.\. )')
785 787
786 788 def transform_classic_prompt(line):
787 789 """Handle inputs that start with '>>> ' syntax."""
788 790
789 791 if not line or line.isspace():
790 792 return line
791 793 m = _classic_prompt_re.match(line)
792 794 if m:
793 795 return line[len(m.group(0)):]
794 796 else:
795 797 return line
796 798
797 799
798 800 _ipy_prompt_re = re.compile(r'^([ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
799 801
800 802 def transform_ipy_prompt(line):
801 803 """Handle inputs that start classic IPython prompt syntax."""
802 804
803 805 if not line or line.isspace():
804 806 return line
805 807 #print 'LINE: %r' % line # dbg
806 808 m = _ipy_prompt_re.match(line)
807 809 if m:
808 810 #print 'MATCH! %r -> %r' % (line, line[len(m.group(0)):]) # dbg
809 811 return line[len(m.group(0)):]
810 812 else:
811 813 return line
812 814
813 815
814 816 class EscapedTransformer(object):
815 817 """Class to transform lines that are explicitly escaped out."""
816 818
817 819 def __init__(self):
818 820 tr = { ESC_SHELL : self._tr_system,
819 821 ESC_SH_CAP : self._tr_system2,
820 822 ESC_HELP : self._tr_help,
821 823 ESC_HELP2 : self._tr_help,
822 824 ESC_MAGIC : self._tr_magic,
823 825 ESC_QUOTE : self._tr_quote,
824 826 ESC_QUOTE2 : self._tr_quote2,
825 827 ESC_PAREN : self._tr_paren }
826 828 self.tr = tr
827 829
828 830 # Support for syntax transformations that use explicit escapes typed by the
829 831 # user at the beginning of a line
830 832 @staticmethod
831 833 def _tr_system(line_info):
832 834 "Translate lines escaped with: !"
833 835 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
834 836 return '%sget_ipython().system(%s)' % (line_info.lspace,
835 837 make_quoted_expr(cmd))
836 838
837 839 @staticmethod
838 840 def _tr_system2(line_info):
839 841 "Translate lines escaped with: !!"
840 842 cmd = line_info.line.lstrip()[2:]
841 843 return '%sget_ipython().getoutput(%s)' % (line_info.lspace,
842 844 make_quoted_expr(cmd))
843 845
844 846 @staticmethod
845 847 def _tr_help(line_info):
846 848 "Translate lines escaped with: ?/??"
847 849 # A naked help line should just fire the intro help screen
848 850 if not line_info.line[1:]:
849 851 return 'get_ipython().show_usage()'
850 852
851 853 # There may be one or two '?' at the end, move them to the front so that
852 854 # the rest of the logic can assume escapes are at the start
855 l_ori = line_info
853 856 line = line_info.line
854 857 if line.endswith('?'):
855 858 line = line[-1] + line[:-1]
856 859 if line.endswith('?'):
857 860 line = line[-1] + line[:-1]
858 861 line_info = LineInfo(line)
859 862
860 # From here on, simply choose which level of detail to get.
861 if line_info.esc == '?':
863 # From here on, simply choose which level of detail to get, and
864 # special-case the psearch syntax
865 if '*' in line_info.line:
866 pinfo = 'psearch'
867 elif line_info.esc == '?':
862 868 pinfo = 'pinfo'
863 869 elif line_info.esc == '??':
864 870 pinfo = 'pinfo2'
865 871
866 872 tpl = '%sget_ipython().magic("%s %s")'
867 873 return tpl % (line_info.lspace, pinfo,
868 874 ' '.join([line_info.fpart, line_info.rest]).strip())
869 875
870 876 @staticmethod
871 877 def _tr_magic(line_info):
872 878 "Translate lines escaped with: %"
873 879 tpl = '%sget_ipython().magic(%s)'
874 880 cmd = make_quoted_expr(' '.join([line_info.fpart,
875 881 line_info.rest]).strip())
876 882 return tpl % (line_info.lspace, cmd)
877 883
878 884 @staticmethod
879 885 def _tr_quote(line_info):
880 886 "Translate lines escaped with: ,"
881 887 return '%s%s("%s")' % (line_info.lspace, line_info.fpart,
882 888 '", "'.join(line_info.rest.split()) )
883 889
884 890 @staticmethod
885 891 def _tr_quote2(line_info):
886 892 "Translate lines escaped with: ;"
887 893 return '%s%s("%s")' % (line_info.lspace, line_info.fpart,
888 894 line_info.rest)
889 895
890 896 @staticmethod
891 897 def _tr_paren(line_info):
892 898 "Translate lines escaped with: /"
893 899 return '%s%s(%s)' % (line_info.lspace, line_info.fpart,
894 900 ", ".join(line_info.rest.split()))
895 901
896 902 def __call__(self, line):
897 903 """Class to transform lines that are explicitly escaped out.
898 904
899 905 This calls the above _tr_* static methods for the actual line
900 906 translations."""
901 907
902 908 # Empty lines just get returned unmodified
903 909 if not line or line.isspace():
904 910 return line
905 911
906 912 # Get line endpoints, where the escapes can be
907 913 line_info = LineInfo(line)
908 914
909 915 # If the escape is not at the start, only '?' needs to be special-cased.
910 916 # All other escapes are only valid at the start
911 917 if not line_info.esc in self.tr:
912 918 if line.endswith(ESC_HELP):
913 919 return self._tr_help(line_info)
914 920 else:
915 921 # If we don't recognize the escape, don't modify the line
916 922 return line
917 923
918 924 return self.tr[line_info.esc](line_info)
919 925
920 926
921 927 # A function-looking object to be used by the rest of the code. The purpose of
922 928 # the class in this case is to organize related functionality, more than to
923 929 # manage state.
924 930 transform_escaped = EscapedTransformer()
925 931
926 932
927 933 class IPythonInputSplitter(InputSplitter):
928 934 """An input splitter that recognizes all of IPython's special syntax."""
929 935
930 936 def push(self, lines):
931 937 """Push one or more lines of IPython input.
932 938 """
933 939 if not lines:
934 940 return super(IPythonInputSplitter, self).push(lines)
935 941
936 942 lines_list = lines.splitlines()
937 943
938 944 transforms = [transform_escaped, transform_assign_system,
939 945 transform_assign_magic, transform_ipy_prompt,
940 946 transform_classic_prompt]
941 947
942 948 # Transform logic
943 949 #
944 950 # We only apply the line transformers to the input if we have either no
945 951 # input yet, or complete input, or if the last line of the buffer ends
946 952 # with ':' (opening an indented block). This prevents the accidental
947 953 # transformation of escapes inside multiline expressions like
948 954 # triple-quoted strings or parenthesized expressions.
949 955 #
950 956 # The last heuristic, while ugly, ensures that the first line of an
951 957 # indented block is correctly transformed.
952 958 #
953 959 # FIXME: try to find a cleaner approach for this last bit.
954 960
955 961 # If we were in 'block' mode, since we're going to pump the parent
956 962 # class by hand line by line, we need to temporarily switch out to
957 963 # 'line' mode, do a single manual reset and then feed the lines one
958 964 # by one. Note that this only matters if the input has more than one
959 965 # line.
960 966 changed_input_mode = False
961 967
962 968 if len(lines_list)>1 and self.input_mode == 'cell':
963 969 self.reset()
964 970 changed_input_mode = True
965 971 saved_input_mode = 'cell'
966 972 self.input_mode = 'line'
967 973
968 974 try:
969 975 push = super(IPythonInputSplitter, self).push
970 976 for line in lines_list:
971 977 if self._is_complete or not self._buffer or \
972 978 (self._buffer and self._buffer[-1].rstrip().endswith(':')):
973 979 for f in transforms:
974 980 line = f(line)
975 981
976 982 out = push(line)
977 983 finally:
978 984 if changed_input_mode:
979 985 self.input_mode = saved_input_mode
980 986
981 987 return out
@@ -1,656 +1,658 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 250 def test_continuation(self):
251 251 isp = self.isp
252 252 isp.push("import os, \\")
253 253 self.assertTrue(isp.push_accepts_more())
254 254 isp.push("sys")
255 255 self.assertFalse(isp.push_accepts_more())
256 256
257 257 def test_syntax_error(self):
258 258 isp = self.isp
259 259 # Syntax errors immediately produce a 'ready' block, so the invalid
260 260 # Python can be sent to the kernel for evaluation with possible ipython
261 261 # special-syntax conversion.
262 262 isp.push('run foo')
263 263 self.assertFalse(isp.push_accepts_more())
264 264
265 265 def check_split(self, block_lines, compile=True):
266 266 blocks = assemble(block_lines)
267 267 lines = ''.join(blocks)
268 268 oblock = self.isp.split_blocks(lines)
269 269 self.assertEqual(oblock, blocks)
270 270 if compile:
271 271 for block in blocks:
272 272 self.isp._compile(block)
273 273
274 274 def test_split(self):
275 275 # All blocks of input we want to test in a list. The format for each
276 276 # block is a list of lists, with each inner lists consisting of all the
277 277 # lines (as single-lines) that should make up a sub-block.
278 278
279 279 # Note: do NOT put here sub-blocks that don't compile, as the
280 280 # check_split() routine makes a final verification pass to check that
281 281 # each sub_block, as returned by split_blocks(), does compile
282 282 # correctly.
283 283 all_blocks = [ [['x=1']],
284 284
285 285 [['x=1'],
286 286 ['y=2']],
287 287
288 288 [['x=1',
289 289 '# a comment'],
290 290 ['y=11']],
291 291
292 292 [['if 1:',
293 293 ' x=1'],
294 294 ['y=3']],
295 295
296 296 [['def f(x):',
297 297 ' return x'],
298 298 ['x=1']],
299 299
300 300 [['def f(x):',
301 301 ' x+=1',
302 302 ' ',
303 303 ' return x'],
304 304 ['x=1']],
305 305
306 306 [['def f(x):',
307 307 ' if x>0:',
308 308 ' y=1',
309 309 ' # a comment',
310 310 ' else:',
311 311 ' y=4',
312 312 ' ',
313 313 ' return y'],
314 314 ['x=1'],
315 315 ['if 1:',
316 316 ' y=11'] ],
317 317
318 318 [['for i in range(10):'
319 319 ' x=i**2']],
320 320
321 321 [['for i in range(10):'
322 322 ' x=i**2'],
323 323 ['z = 1']],
324 324 ]
325 325 for block_lines in all_blocks:
326 326 self.check_split(block_lines)
327 327
328 328 def test_split_syntax_errors(self):
329 329 # Block splitting with invalid syntax
330 330 all_blocks = [ [['a syntax error']],
331 331
332 332 [['x=1',
333 333 'another syntax error']],
334 334
335 335 [['for i in range(10):'
336 336 ' yet another error']],
337 337
338 338 ]
339 339 for block_lines in all_blocks:
340 340 self.check_split(block_lines, compile=False)
341 341
342 342
343 343 class InteractiveLoopTestCase(unittest.TestCase):
344 344 """Tests for an interactive loop like a python shell.
345 345 """
346 346 def check_ns(self, lines, ns):
347 347 """Validate that the given input lines produce the resulting namespace.
348 348
349 349 Note: the input lines are given exactly as they would be typed in an
350 350 auto-indenting environment, as mini_interactive_loop above already does
351 351 auto-indenting and prepends spaces to the input.
352 352 """
353 353 src = mini_interactive_loop(pseudo_input(lines))
354 354 test_ns = {}
355 355 exec src in test_ns
356 356 # We can't check that the provided ns is identical to the test_ns,
357 357 # because Python fills test_ns with extra keys (copyright, etc). But
358 358 # we can check that the given dict is *contained* in test_ns
359 359 for k,v in ns.items():
360 360 self.assertEqual(test_ns[k], v)
361 361
362 362 def test_simple(self):
363 363 self.check_ns(['x=1'], dict(x=1))
364 364
365 365 def test_simple2(self):
366 366 self.check_ns(['if 1:', 'x=2'], dict(x=2))
367 367
368 368 def test_xy(self):
369 369 self.check_ns(['x=1; y=2'], dict(x=1, y=2))
370 370
371 371 def test_abc(self):
372 372 self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3))
373 373
374 374 def test_multi(self):
375 375 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
376 376
377 377
378 378 def test_LineInfo():
379 379 """Simple test for LineInfo construction and str()"""
380 380 linfo = isp.LineInfo(' %cd /home')
381 381 nt.assert_equals(str(linfo), 'LineInfo [ |%|cd|/home]')
382 382
383 383
384 384 def test_split_user_input():
385 385 """Unicode test - split_user_input already has good doctests"""
386 386 line = u"PΓ©rez Fernando"
387 387 parts = isp.split_user_input(line)
388 388 parts_expected = (u'', u'', u'', line)
389 389 nt.assert_equal(parts, parts_expected)
390 390
391 391
392 392 # Transformer tests
393 393 def transform_checker(tests, func):
394 394 """Utility to loop over test inputs"""
395 395 for inp, tr in tests:
396 396 nt.assert_equals(func(inp), tr)
397 397
398 398 # Data for all the syntax tests in the form of lists of pairs of
399 399 # raw/transformed input. We store it here as a global dict so that we can use
400 400 # it both within single-function tests and also to validate the behavior of the
401 401 # larger objects
402 402
403 403 syntax = \
404 404 dict(assign_system =
405 405 [('a =! ls', 'a = get_ipython().getoutput("ls")'),
406 406 ('b = !ls', 'b = get_ipython().getoutput("ls")'),
407 407 ('x=1', 'x=1'), # normal input is unmodified
408 408 (' ',' '), # blank lines are kept intact
409 409 ],
410 410
411 411 assign_magic =
412 412 [('a =% who', 'a = get_ipython().magic("who")'),
413 413 ('b = %who', 'b = get_ipython().magic("who")'),
414 414 ('x=1', 'x=1'), # normal input is unmodified
415 415 (' ',' '), # blank lines are kept intact
416 416 ],
417 417
418 418 classic_prompt =
419 419 [('>>> x=1', 'x=1'),
420 420 ('x=1', 'x=1'), # normal input is unmodified
421 421 (' ', ' '), # blank lines are kept intact
422 422 ('... ', ''), # continuation prompts
423 423 ],
424 424
425 425 ipy_prompt =
426 426 [('In [1]: x=1', 'x=1'),
427 427 ('x=1', 'x=1'), # normal input is unmodified
428 428 (' ',' '), # blank lines are kept intact
429 429 (' ....: ', ''), # continuation prompts
430 430 ],
431 431
432 432 # Tests for the escape transformer to leave normal code alone
433 433 escaped_noesc =
434 434 [ (' ', ' '),
435 435 ('x=1', 'x=1'),
436 436 ],
437 437
438 438 # System calls
439 439 escaped_shell =
440 440 [ ('!ls', 'get_ipython().system("ls")'),
441 441 # Double-escape shell, this means to capture the output of the
442 442 # subprocess and return it
443 443 ('!!ls', 'get_ipython().getoutput("ls")'),
444 444 ],
445 445
446 446 # Help/object info
447 447 escaped_help =
448 448 [ ('?', 'get_ipython().show_usage()'),
449 449 ('?x1', 'get_ipython().magic("pinfo x1")'),
450 450 ('??x2', 'get_ipython().magic("pinfo2 x2")'),
451 451 ('x3?', 'get_ipython().magic("pinfo x3")'),
452 452 ('x4??', 'get_ipython().magic("pinfo2 x4")'),
453 453 ('%hist?', 'get_ipython().magic("pinfo %hist")'),
454 ('f*?', 'get_ipython().magic("psearch f*")'),
455 ('ax.*aspe*?', 'get_ipython().magic("psearch ax.*aspe*")'),
454 456 ],
455 457
456 458 # Explicit magic calls
457 459 escaped_magic =
458 460 [ ('%cd', 'get_ipython().magic("cd")'),
459 461 ('%cd /home', 'get_ipython().magic("cd /home")'),
460 462 (' %magic', ' get_ipython().magic("magic")'),
461 463 ],
462 464
463 465 # Quoting with separate arguments
464 466 escaped_quote =
465 467 [ (',f', 'f("")'),
466 468 (',f x', 'f("x")'),
467 469 (' ,f y', ' f("y")'),
468 470 (',f a b', 'f("a", "b")'),
469 471 ],
470 472
471 473 # Quoting with single argument
472 474 escaped_quote2 =
473 475 [ (';f', 'f("")'),
474 476 (';f x', 'f("x")'),
475 477 (' ;f y', ' f("y")'),
476 478 (';f a b', 'f("a b")'),
477 479 ],
478 480
479 481 # Simply apply parens
480 482 escaped_paren =
481 483 [ ('/f', 'f()'),
482 484 ('/f x', 'f(x)'),
483 485 (' /f y', ' f(y)'),
484 486 ('/f a b', 'f(a, b)'),
485 487 ],
486 488
487 489 )
488 490
489 491 # multiline syntax examples. Each of these should be a list of lists, with
490 492 # each entry itself having pairs of raw/transformed input. The union (with
491 493 # '\n'.join() of the transformed inputs is what the splitter should produce
492 494 # when fed the raw lines one at a time via push.
493 495 syntax_ml = \
494 496 dict(classic_prompt =
495 497 [ [('>>> for i in range(10):','for i in range(10):'),
496 498 ('... print i',' print i'),
497 499 ('... ', ''),
498 500 ],
499 501 ],
500 502
501 503 ipy_prompt =
502 504 [ [('In [24]: for i in range(10):','for i in range(10):'),
503 505 (' ....: print i',' print i'),
504 506 (' ....: ', ''),
505 507 ],
506 508 ],
507 509 )
508 510
509 511
510 512 def test_assign_system():
511 513 transform_checker(syntax['assign_system'], isp.transform_assign_system)
512 514
513 515
514 516 def test_assign_magic():
515 517 transform_checker(syntax['assign_magic'], isp.transform_assign_magic)
516 518
517 519
518 520 def test_classic_prompt():
519 521 transform_checker(syntax['classic_prompt'], isp.transform_classic_prompt)
520 522 for example in syntax_ml['classic_prompt']:
521 523 transform_checker(example, isp.transform_classic_prompt)
522 524
523 525
524 526 def test_ipy_prompt():
525 527 transform_checker(syntax['ipy_prompt'], isp.transform_ipy_prompt)
526 528 for example in syntax_ml['ipy_prompt']:
527 529 transform_checker(example, isp.transform_ipy_prompt)
528 530
529 531
530 532 def test_escaped_noesc():
531 533 transform_checker(syntax['escaped_noesc'], isp.transform_escaped)
532 534
533 535
534 536 def test_escaped_shell():
535 537 transform_checker(syntax['escaped_shell'], isp.transform_escaped)
536 538
537 539
538 540 def test_escaped_help():
539 541 transform_checker(syntax['escaped_help'], isp.transform_escaped)
540 542
541 543
542 544 def test_escaped_magic():
543 545 transform_checker(syntax['escaped_magic'], isp.transform_escaped)
544 546
545 547
546 548 def test_escaped_quote():
547 549 transform_checker(syntax['escaped_quote'], isp.transform_escaped)
548 550
549 551
550 552 def test_escaped_quote2():
551 553 transform_checker(syntax['escaped_quote2'], isp.transform_escaped)
552 554
553 555
554 556 def test_escaped_paren():
555 557 transform_checker(syntax['escaped_paren'], isp.transform_escaped)
556 558
557 559
558 560 class IPythonInputTestCase(InputSplitterTestCase):
559 561 """By just creating a new class whose .isp is a different instance, we
560 562 re-run the same test battery on the new input splitter.
561 563
562 564 In addition, this runs the tests over the syntax and syntax_ml dicts that
563 565 were tested by individual functions, as part of the OO interface.
564 566 """
565 567
566 568 def setUp(self):
567 569 self.isp = isp.IPythonInputSplitter(input_mode='line')
568 570
569 571 def test_syntax(self):
570 572 """Call all single-line syntax tests from the main object"""
571 573 isp = self.isp
572 574 for example in syntax.itervalues():
573 575 for raw, out_t in example:
574 576 if raw.startswith(' '):
575 577 continue
576 578
577 579 isp.push(raw)
578 580 out = isp.source_reset().rstrip()
579 581 self.assertEqual(out, out_t)
580 582
581 583 def test_syntax_multiline(self):
582 584 isp = self.isp
583 585 for example in syntax_ml.itervalues():
584 586 out_t_parts = []
585 587 for line_pairs in example:
586 588 for raw, out_t_part in line_pairs:
587 589 isp.push(raw)
588 590 out_t_parts.append(out_t_part)
589 591
590 592 out = isp.source_reset().rstrip()
591 593 out_t = '\n'.join(out_t_parts).rstrip()
592 594 self.assertEqual(out, out_t)
593 595
594 596
595 597 class BlockIPythonInputTestCase(IPythonInputTestCase):
596 598
597 599 # Deactivate tests that don't make sense for the block mode
598 600 test_push3 = test_split = lambda s: None
599 601
600 602 def setUp(self):
601 603 self.isp = isp.IPythonInputSplitter(input_mode='cell')
602 604
603 605 def test_syntax_multiline(self):
604 606 isp = self.isp
605 607 for example in syntax_ml.itervalues():
606 608 raw_parts = []
607 609 out_t_parts = []
608 610 for line_pairs in example:
609 611 for raw, out_t_part in line_pairs:
610 612 raw_parts.append(raw)
611 613 out_t_parts.append(out_t_part)
612 614
613 615 raw = '\n'.join(raw_parts)
614 616 out_t = '\n'.join(out_t_parts)
615 617
616 618 isp.push(raw)
617 619 out = isp.source_reset()
618 620 # Match ignoring trailing whitespace
619 621 self.assertEqual(out.rstrip(), out_t.rstrip())
620 622
621 623
622 624 #-----------------------------------------------------------------------------
623 625 # Main - use as a script, mostly for developer experiments
624 626 #-----------------------------------------------------------------------------
625 627
626 628 if __name__ == '__main__':
627 629 # A simple demo for interactive experimentation. This code will not get
628 630 # picked up by any test suite.
629 631 from IPython.core.inputsplitter import InputSplitter, IPythonInputSplitter
630 632
631 633 # configure here the syntax to use, prompt and whether to autoindent
632 634 #isp, start_prompt = InputSplitter(), '>>> '
633 635 isp, start_prompt = IPythonInputSplitter(), 'In> '
634 636
635 637 autoindent = True
636 638 #autoindent = False
637 639
638 640 try:
639 641 while True:
640 642 prompt = start_prompt
641 643 while isp.push_accepts_more():
642 644 indent = ' '*isp.indent_spaces
643 645 if autoindent:
644 646 line = indent + raw_input(prompt+indent)
645 647 else:
646 648 line = raw_input(prompt)
647 649 isp.push(line)
648 650 prompt = '... '
649 651
650 652 # Here we just return input so we can use it in a test suite, but a
651 653 # real interpreter would instead send it for execution somewhere.
652 654 #src = isp.source; raise EOFError # dbg
653 655 src = isp.source_reset()
654 656 print 'Input source was:\n', src
655 657 except EOFError:
656 658 print 'Bye'
General Comments 0
You need to be logged in to leave comments. Login now