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