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