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