##// END OF EJS Templates
Merge branch 'blockbreaker' of git://github.com/fperez/ipython into qtfrontend
epatters -
r2788:45fee7db merge
parent child Browse files
Show More
@@ -5,7 +5,33 b' input from either interactive, line-by-line environments or block-based ones,'
5 into standalone blocks that can be executed by Python as 'single' statements
5 into standalone blocks that can be executed by Python as 'single' statements
6 (thus triggering sys.displayhook).
6 (thus triggering sys.displayhook).
7
7
8 A companion, :class:`IPythonInputSplitter`, provides the same functionality but
9 with full support for the extended IPython syntax (magics, system calls, etc).
10
8 For more details, see the class docstring below.
11 For more details, see the class docstring below.
12
13 ToDo
14 ----
15
16 - Naming cleanups. The tr_* names aren't the most elegant, though now they are
17 at least just attributes of a class so not really very exposed.
18
19 - Think about the best way to support dynamic things: automagic, autocall,
20 macros, etc.
21
22 - Think of a better heuristic for the application of the transforms in
23 IPythonInputSplitter.push() than looking at the buffer ending in ':'. Idea:
24 track indentation change events (indent, dedent, nothing) and apply them only
25 if the indentation went up, but not otherwise.
26
27 - Think of the cleanest way for supporting user-specified transformations (the
28 user prefilters we had before).
29
30 Authors
31 -------
32
33 * Fernando Perez
34 * Brian Granger
9 """
35 """
10 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
11 # Copyright (C) 2010 The IPython Development Team
37 # Copyright (C) 2010 The IPython Development Team
@@ -22,11 +48,36 b' import codeop'
22 import re
48 import re
23 import sys
49 import sys
24
50
51 # IPython modules
52 from IPython.utils.text import make_quoted_expr
53
54 #-----------------------------------------------------------------------------
55 # Globals
56 #-----------------------------------------------------------------------------
57
58 # The escape sequences that define the syntax transformations IPython will
59 # apply to user input. These can NOT be just changed here: many regular
60 # expressions and other parts of the code may use their hardcoded values, and
61 # for all intents and purposes they constitute the 'IPython syntax', so they
62 # should be considered fixed.
63
64 ESC_SHELL = '!'
65 ESC_SH_CAP = '!!'
66 ESC_HELP = '?'
67 ESC_HELP2 = '??'
68 ESC_MAGIC = '%'
69 ESC_QUOTE = ','
70 ESC_QUOTE2 = ';'
71 ESC_PAREN = '/'
72
25 #-----------------------------------------------------------------------------
73 #-----------------------------------------------------------------------------
26 # Utilities
74 # Utilities
27 #-----------------------------------------------------------------------------
75 #-----------------------------------------------------------------------------
28
76
29 # FIXME: move these utilities to the general ward...
77 # FIXME: These are general-purpose utilities that later can be moved to the
78 # general ward. Kept here for now because we're being very strict about test
79 # coverage with this code, and this lets us ensure that we keep 100% coverage
80 # while developing.
30
81
31 # compiled regexps for autoindent management
82 # compiled regexps for autoindent management
32 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
83 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
@@ -74,7 +125,9 b' def remove_comments(src):'
74
125
75
126
76 def get_input_encoding():
127 def get_input_encoding():
77 """Return the default standard input encoding."""
128 """Return the default standard input encoding.
129
130 If sys.stdin has no encoding, 'ascii' is returned."""
78 # There are strange environments for which sys.stdin.encoding is None. We
131 # There are strange environments for which sys.stdin.encoding is None. We
79 # ensure that a valid encoding is returned.
132 # ensure that a valid encoding is returned.
80 encoding = getattr(sys.stdin, 'encoding', None)
133 encoding = getattr(sys.stdin, 'encoding', None)
@@ -83,7 +136,7 b' def get_input_encoding():'
83 return encoding
136 return encoding
84
137
85 #-----------------------------------------------------------------------------
138 #-----------------------------------------------------------------------------
86 # Classes and functions
139 # Classes and functions for normal Python syntax handling
87 #-----------------------------------------------------------------------------
140 #-----------------------------------------------------------------------------
88
141
89 class InputSplitter(object):
142 class InputSplitter(object):
@@ -417,3 +470,348 b' class InputSplitter(object):'
417
470
418 def _set_source(self):
471 def _set_source(self):
419 self.source = ''.join(self._buffer).encode(self.encoding)
472 self.source = ''.join(self._buffer).encode(self.encoding)
473
474
475 #-----------------------------------------------------------------------------
476 # Functions and classes for IPython-specific syntactic support
477 #-----------------------------------------------------------------------------
478
479 # RegExp for splitting line contents into pre-char//first word-method//rest.
480 # For clarity, each group in on one line.
481
482 line_split = re.compile("""
483 ^(\s*) # any leading space
484 ([,;/%]|!!?|\?\??) # escape character or characters
485 \s*([\w\.]*) # function/method part (mix of \w and '.')
486 (\s+.*$|$) # rest of line
487 """, re.VERBOSE)
488
489
490 def split_user_input(line):
491 """Split user input into early whitespace, esc-char, function part and rest.
492
493 This is currently handles lines with '=' in them in a very inconsistent
494 manner.
495
496 Examples
497 ========
498 >>> split_user_input('x=1')
499 ('', '', 'x=1', '')
500 >>> split_user_input('?')
501 ('', '?', '', '')
502 >>> split_user_input('??')
503 ('', '??', '', '')
504 >>> split_user_input(' ?')
505 (' ', '?', '', '')
506 >>> split_user_input(' ??')
507 (' ', '??', '', '')
508 >>> split_user_input('??x')
509 ('', '??', 'x', '')
510 >>> split_user_input('?x=1')
511 ('', '', '?x=1', '')
512 >>> split_user_input('!ls')
513 ('', '!', 'ls', '')
514 >>> split_user_input(' !ls')
515 (' ', '!', 'ls', '')
516 >>> split_user_input('!!ls')
517 ('', '!!', 'ls', '')
518 >>> split_user_input(' !!ls')
519 (' ', '!!', 'ls', '')
520 >>> split_user_input(',ls')
521 ('', ',', 'ls', '')
522 >>> split_user_input(';ls')
523 ('', ';', 'ls', '')
524 >>> split_user_input(' ;ls')
525 (' ', ';', 'ls', '')
526 >>> split_user_input('f.g(x)')
527 ('', '', 'f.g(x)', '')
528 >>> split_user_input('f.g (x)')
529 ('', '', 'f.g', '(x)')
530 """
531 match = line_split.match(line)
532 if match:
533 lspace, esc, fpart, rest = match.groups()
534 else:
535 # print "match failed for line '%s'" % line
536 try:
537 fpart, rest = line.split(None, 1)
538 except ValueError:
539 # print "split failed for line '%s'" % line
540 fpart, rest = line,''
541 lspace = re.match('^(\s*)(.*)', line).groups()[0]
542 esc = ''
543
544 # fpart has to be a valid python identifier, so it better be only pure
545 # ascii, no unicode:
546 try:
547 fpart = fpart.encode('ascii')
548 except UnicodeEncodeError:
549 lspace = unicode(lspace)
550 rest = fpart + u' ' + rest
551 fpart = u''
552
553 #print 'line:<%s>' % line # dbg
554 #print 'esc <%s> fpart <%s> rest <%s>' % (esc,fpart.strip(),rest) # dbg
555 return lspace, esc, fpart.strip(), rest.lstrip()
556
557
558 # The escaped translators ALL receive a line where their own escape has been
559 # stripped. Only '?' is valid at the end of the line, all others can only be
560 # placed at the start.
561
562 class LineInfo(object):
563 """A single line of input and associated info.
564
565 This is a utility class that mostly wraps the output of
566 :func:`split_user_input` into a convenient object to be passed around
567 during input transformations.
568
569 Includes the following as properties:
570
571 line
572 The original, raw line
573
574 lspace
575 Any early whitespace before actual text starts.
576
577 esc
578 The initial esc character (or characters, for double-char escapes like
579 '??' or '!!').
580
581 fpart
582 The 'function part', which is basically the maximal initial sequence
583 of valid python identifiers and the '.' character. This is what is
584 checked for alias and magic transformations, used for auto-calling,
585 etc.
586
587 rest
588 Everything else on the line.
589 """
590 def __init__(self, line):
591 self.line = line
592 self.lspace, self.esc, self.fpart, self.rest = \
593 split_user_input(line)
594
595 def __str__(self):
596 return "LineInfo [%s|%s|%s|%s]" % (self.lspace, self.esc,
597 self.fpart, self.rest)
598
599
600 # Transformations of the special syntaxes that don't rely on an explicit escape
601 # character but instead on patterns on the input line
602
603 # The core transformations are implemented as standalone functions that can be
604 # tested and validated in isolation. Each of these uses a regexp, we
605 # pre-compile these and keep them close to each function definition for clarity
606
607 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
608 r'\s*=\s*!\s*(?P<cmd>.*)')
609
610 def transform_assign_system(line):
611 """Handle the `files = !ls` syntax."""
612 # FIXME: This transforms the line to use %sc, but we've listed that magic
613 # as deprecated. We should then implement this functionality in a
614 # standalone api that we can transform to, without going through a
615 # deprecated magic.
616 m = _assign_system_re.match(line)
617 if m is not None:
618 cmd = m.group('cmd')
619 lhs = m.group('lhs')
620 expr = make_quoted_expr("sc -l = %s" % cmd)
621 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
622 return new_line
623 return line
624
625
626 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
627 r'\s*=\s*%\s*(?P<cmd>.*)')
628
629 def transform_assign_magic(line):
630 """Handle the `a = %who` syntax."""
631 m = _assign_magic_re.match(line)
632 if m is not None:
633 cmd = m.group('cmd')
634 lhs = m.group('lhs')
635 expr = make_quoted_expr(cmd)
636 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
637 return new_line
638 return line
639
640
641 _classic_prompt_re = re.compile(r'^([ \t]*>>> |^[ \t]*\.\.\. )')
642
643 def transform_classic_prompt(line):
644 """Handle inputs that start with '>>> ' syntax."""
645
646 if not line or line.isspace():
647 return line
648 m = _classic_prompt_re.match(line)
649 if m:
650 return line[len(m.group(0)):]
651 else:
652 return line
653
654
655 _ipy_prompt_re = re.compile(r'^([ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
656
657 def transform_ipy_prompt(line):
658 """Handle inputs that start classic IPython prompt syntax."""
659
660 if not line or line.isspace():
661 return line
662 m = _ipy_prompt_re.match(line)
663 if m:
664 return line[len(m.group(0)):]
665 else:
666 return line
667
668
669 class EscapedTransformer(object):
670 """Class to transform lines that are explicitly escaped out."""
671
672 def __init__(self):
673 tr = { ESC_SHELL : self.tr_system,
674 ESC_SH_CAP : self.tr_system2,
675 ESC_HELP : self.tr_help,
676 ESC_HELP2 : self.tr_help,
677 ESC_MAGIC : self.tr_magic,
678 ESC_QUOTE : self.tr_quote,
679 ESC_QUOTE2 : self.tr_quote2,
680 ESC_PAREN : self.tr_paren }
681 self.tr = tr
682
683 # Support for syntax transformations that use explicit escapes typed by the
684 # user at the beginning of a line
685 @staticmethod
686 def tr_system(line_info):
687 "Translate lines escaped with: !"
688 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
689 return '%sget_ipython().system(%s)' % (line_info.lspace,
690 make_quoted_expr(cmd))
691
692 @staticmethod
693 def tr_system2(line_info):
694 "Translate lines escaped with: !!"
695 cmd = line_info.line.lstrip()[2:]
696 return '%sget_ipython().getoutput(%s)' % (line_info.lspace,
697 make_quoted_expr(cmd))
698
699 @staticmethod
700 def tr_help(line_info):
701 "Translate lines escaped with: ?/??"
702 # A naked help line should just fire the intro help screen
703 if not line_info.line[1:]:
704 return 'get_ipython().show_usage()'
705
706 # There may be one or two '?' at the end, move them to the front so that
707 # the rest of the logic can assume escapes are at the start
708 line = line_info.line
709 if line.endswith('?'):
710 line = line[-1] + line[:-1]
711 if line.endswith('?'):
712 line = line[-1] + line[:-1]
713 line_info = LineInfo(line)
714
715 # From here on, simply choose which level of detail to get.
716 if line_info.esc == '?':
717 pinfo = 'pinfo'
718 elif line_info.esc == '??':
719 pinfo = 'pinfo2'
720
721 tpl = '%sget_ipython().magic("%s %s")'
722 return tpl % (line_info.lspace, pinfo,
723 ' '.join([line_info.fpart, line_info.rest]).strip())
724
725 @staticmethod
726 def tr_magic(line_info):
727 "Translate lines escaped with: %"
728 tpl = '%sget_ipython().magic(%s)'
729 cmd = make_quoted_expr(' '.join([line_info.fpart,
730 line_info.rest])).strip()
731 return tpl % (line_info.lspace, cmd)
732
733 @staticmethod
734 def tr_quote(line_info):
735 "Translate lines escaped with: ,"
736 return '%s%s("%s")' % (line_info.lspace, line_info.fpart,
737 '", "'.join(line_info.rest.split()) )
738
739 @staticmethod
740 def tr_quote2(line_info):
741 "Translate lines escaped with: ;"
742 return '%s%s("%s")' % (line_info.lspace, line_info.fpart,
743 line_info.rest)
744
745 @staticmethod
746 def tr_paren(line_info):
747 "Translate lines escaped with: /"
748 return '%s%s(%s)' % (line_info.lspace, line_info.fpart,
749 ", ".join(line_info.rest.split()))
750
751 def __call__(self, line):
752 """Class to transform lines that are explicitly escaped out.
753
754 This calls the above tr_* static methods for the actual line
755 translations."""
756
757 # Empty lines just get returned unmodified
758 if not line or line.isspace():
759 return line
760
761 # Get line endpoints, where the escapes can be
762 line_info = LineInfo(line)
763
764 # If the escape is not at the start, only '?' needs to be special-cased.
765 # All other escapes are only valid at the start
766 if not line_info.esc in self.tr:
767 if line.endswith(ESC_HELP):
768 return self.tr_help(line_info)
769 else:
770 # If we don't recognize the escape, don't modify the line
771 return line
772
773 return self.tr[line_info.esc](line_info)
774
775 # A function-looking object to be used by the rest of the code. The purpose of
776 # the class in this case is to organize related functionality, more than to
777 # manage state.
778 transform_escaped = EscapedTransformer()
779
780
781 class IPythonInputSplitter(InputSplitter):
782 """An input splitter that recognizes all of IPython's special syntax."""
783
784 def push(self, lines):
785 """Push one or more lines of IPython input.
786 """
787 if not lines:
788 return super(IPythonInputSplitter, self).push(lines)
789
790 lines_list = lines.splitlines()
791
792 transforms = [transform_escaped, transform_assign_system,
793 transform_assign_magic, transform_ipy_prompt,
794 transform_classic_prompt]
795
796 # Transform logic
797 #
798 # We only apply the line transformers to the input if we have either no
799 # input yet, or complete input, or if the last line of the buffer ends
800 # with ':' (opening an indented block). This prevents the accidental
801 # transformation of escapes inside multiline expressions like
802 # triple-quoted strings or parenthesized expressions.
803 #
804 # The last heuristic, while ugly, ensures that the first line of an
805 # indented block is correctly transformed.
806 #
807 # FIXME: try to find a cleaner approach for this last bit.
808
809 for line in lines_list:
810 if self._is_complete or not self._buffer or \
811 (self._buffer and self._buffer[-1].rstrip().endswith(':')):
812 for f in transforms:
813 line = f(line)
814
815 out = super(IPythonInputSplitter, self).push(line)
816
817 return out
@@ -1,3 +1,4 b''
1 # -*- coding: utf-8 -*-
1 """Tests for the inputsplitter module.
2 """Tests for the inputsplitter module.
2 """
3 """
3 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
@@ -12,6 +13,7 b''
12 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
13 # stdlib
14 # stdlib
14 import unittest
15 import unittest
16 import sys
15
17
16 # Third party
18 # Third party
17 import nose.tools as nt
19 import nose.tools as nt
@@ -22,6 +24,10 b' from IPython.core import inputsplitter as isp'
22 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
23 # Semi-complete examples (also used as tests)
25 # Semi-complete examples (also used as tests)
24 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
28 # Note: at the bottom, there's a slightly more complete version of this that
29 # can be useful during development of code here.
30
25 def mini_interactive_loop(raw_input):
31 def mini_interactive_loop(raw_input):
26 """Minimal example of the logic of an interactive interpreter loop.
32 """Minimal example of the logic of an interactive interpreter loop.
27
33
@@ -43,7 +49,7 b' def mini_interactive_loop(raw_input):'
43 # Here we just return input so we can use it in a test suite, but a real
49 # Here we just return input so we can use it in a test suite, but a real
44 # interpreter would instead send it for execution somewhere.
50 # interpreter would instead send it for execution somewhere.
45 src = isp.source_reset()
51 src = isp.source_reset()
46 print 'Input source was:\n', src
52 #print 'Input source was:\n', src # dbg
47 return src
53 return src
48
54
49 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
@@ -108,6 +114,23 b' def test_get_input_encoding():'
108 nt.assert_equal('test'.encode(encoding), 'test')
114 nt.assert_equal('test'.encode(encoding), 'test')
109
115
110
116
117 class NoInputEncodingTestCase(unittest.TestCase):
118 def setUp(self):
119 self.old_stdin = sys.stdin
120 class X: pass
121 fake_stdin = X()
122 sys.stdin = fake_stdin
123
124 def test(self):
125 # Verify that if sys.stdin has no 'encoding' attribute we do the right
126 # thing
127 enc = isp.get_input_encoding()
128 self.assertEqual(enc, 'ascii')
129
130 def tearDown(self):
131 sys.stdin = self.old_stdin
132
133
111 class InputSplitterTestCase(unittest.TestCase):
134 class InputSplitterTestCase(unittest.TestCase):
112 def setUp(self):
135 def setUp(self):
113 self.isp = isp.InputSplitter()
136 self.isp = isp.InputSplitter()
@@ -344,3 +367,255 b' class InteractiveLoopTestCase(unittest.TestCase):'
344 def test_multi(self):
367 def test_multi(self):
345 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
368 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
346
369
370
371 def test_LineInfo():
372 """Simple test for LineInfo construction and str()"""
373 linfo = isp.LineInfo(' %cd /home')
374 nt.assert_equals(str(linfo), 'LineInfo [ |%|cd|/home]')
375
376
377 def test_split_user_input():
378 """Unicode test - split_user_input already has good doctests"""
379 line = u"Pérez Fernando"
380 parts = isp.split_user_input(line)
381 parts_expected = (u'', u'', u'', line)
382 nt.assert_equal(parts, parts_expected)
383
384
385 # Transformer tests
386 def transform_checker(tests, func):
387 """Utility to loop over test inputs"""
388 for inp, tr in tests:
389 nt.assert_equals(func(inp), tr)
390
391 # Data for all the syntax tests in the form of lists of pairs of
392 # raw/transformed input. We store it here as a global dict so that we can use
393 # it both within single-function tests and also to validate the behavior of the
394 # larger objects
395
396 syntax = \
397 dict(assign_system =
398 [('a =! ls', 'a = get_ipython().magic("sc -l = ls")'),
399 ('b = !ls', 'b = get_ipython().magic("sc -l = ls")'),
400 ('x=1', 'x=1'), # normal input is unmodified
401 (' ',' '), # blank lines are kept intact
402 ],
403
404 assign_magic =
405 [('a =% who', 'a = get_ipython().magic("who")'),
406 ('b = %who', 'b = get_ipython().magic("who")'),
407 ('x=1', 'x=1'), # normal input is unmodified
408 (' ',' '), # blank lines are kept intact
409 ],
410
411 classic_prompt =
412 [('>>> x=1', 'x=1'),
413 ('x=1', 'x=1'), # normal input is unmodified
414 (' ',' '), # blank lines are kept intact
415 ],
416
417 ipy_prompt =
418 [('In [1]: x=1', 'x=1'),
419 ('x=1', 'x=1'), # normal input is unmodified
420 (' ',' '), # blank lines are kept intact
421 ],
422
423 # Tests for the escape transformer to leave normal code alone
424 escaped_noesc =
425 [ (' ', ' '),
426 ('x=1', 'x=1'),
427 ],
428
429 # System calls
430 escaped_shell =
431 [ ('!ls', 'get_ipython().system("ls")'),
432 # Double-escape shell, this means to capture the output of the
433 # subprocess and return it
434 ('!!ls', 'get_ipython().getoutput("ls")'),
435 ],
436
437 # Help/object info
438 escaped_help =
439 [ ('?', 'get_ipython().show_usage()'),
440 ('?x1', 'get_ipython().magic("pinfo x1")'),
441 ('??x2', 'get_ipython().magic("pinfo2 x2")'),
442 ('x3?', 'get_ipython().magic("pinfo x3")'),
443 ('x4??', 'get_ipython().magic("pinfo2 x4")'),
444 ],
445
446 # Explicit magic calls
447 escaped_magic =
448 [ ('%cd', 'get_ipython().magic("cd")'),
449 ('%cd /home', 'get_ipython().magic("cd /home")'),
450 (' %magic', ' get_ipython().magic("magic")'),
451 ],
452
453 # Quoting with separate arguments
454 escaped_quote =
455 [ (',f', 'f("")'),
456 (',f x', 'f("x")'),
457 (' ,f y', ' f("y")'),
458 (',f a b', 'f("a", "b")'),
459 ],
460
461 # Quoting with single argument
462 escaped_quote2 =
463 [ (';f', 'f("")'),
464 (';f x', 'f("x")'),
465 (' ;f y', ' f("y")'),
466 (';f a b', 'f("a b")'),
467 ],
468
469 # Simply apply parens
470 escaped_paren =
471 [ ('/f', 'f()'),
472 ('/f x', 'f(x)'),
473 (' /f y', ' f(y)'),
474 ('/f a b', 'f(a, b)'),
475 ],
476
477 # More complex multiline tests
478 ## escaped_multiline =
479 ## [()],
480 )
481
482 # multiline syntax examples. Each of these should be a list of lists, with
483 # each entry itself having pairs of raw/transformed input. The union (with
484 # '\n'.join() of the transformed inputs is what the splitter should produce
485 # when fed the raw lines one at a time via push.
486 syntax_ml = \
487 dict(classic_prompt =
488 [ [('>>> for i in range(10):','for i in range(10):'),
489 ('... print i',' print i'),
490 ('... ', ''),
491 ],
492 ],
493
494 ipy_prompt =
495 [ [('In [24]: for i in range(10):','for i in range(10):'),
496 (' ....: print i',' print i'),
497 (' ....: ', ''),
498 ],
499 ],
500 )
501
502
503 def test_assign_system():
504 transform_checker(syntax['assign_system'], isp.transform_assign_system)
505
506
507 def test_assign_magic():
508 transform_checker(syntax['assign_magic'], isp.transform_assign_magic)
509
510
511 def test_classic_prompt():
512 transform_checker(syntax['classic_prompt'], isp.transform_classic_prompt)
513 for example in syntax_ml['classic_prompt']:
514 transform_checker(example, isp.transform_classic_prompt)
515
516
517 def test_ipy_prompt():
518 transform_checker(syntax['ipy_prompt'], isp.transform_ipy_prompt)
519 for example in syntax_ml['ipy_prompt']:
520 transform_checker(example, isp.transform_ipy_prompt)
521
522
523 def test_escaped_noesc():
524 transform_checker(syntax['escaped_noesc'], isp.transform_escaped)
525
526
527 def test_escaped_shell():
528 transform_checker(syntax['escaped_shell'], isp.transform_escaped)
529
530
531 def test_escaped_help():
532 transform_checker(syntax['escaped_help'], isp.transform_escaped)
533
534
535 def test_escaped_magic():
536 transform_checker(syntax['escaped_magic'], isp.transform_escaped)
537
538
539 def test_escaped_quote():
540 transform_checker(syntax['escaped_quote'], isp.transform_escaped)
541
542
543 def test_escaped_quote2():
544 transform_checker(syntax['escaped_quote2'], isp.transform_escaped)
545
546
547 def test_escaped_paren():
548 transform_checker(syntax['escaped_paren'], isp.transform_escaped)
549
550
551 class IPythonInputTestCase(InputSplitterTestCase):
552 """By just creating a new class whose .isp is a different instance, we
553 re-run the same test battery on the new input splitter.
554
555 In addition, this runs the tests over the syntax and syntax_ml dicts that
556 were tested by individual functions, as part of the OO interface.
557 """
558 def setUp(self):
559 self.isp = isp.IPythonInputSplitter()
560
561 def test_syntax(self):
562 """Call all single-line syntax tests from the main object"""
563 isp = self.isp
564 for example in syntax.itervalues():
565 for raw, out_t in example:
566 if raw.startswith(' '):
567 continue
568
569 isp.push(raw)
570 out = isp.source_reset().rstrip()
571 self.assertEqual(out, out_t)
572
573 def test_syntax_multiline(self):
574 isp = self.isp
575 for example in syntax_ml.itervalues():
576 out_t_parts = []
577 for line_pairs in example:
578 for raw, out_t_part in line_pairs:
579 isp.push(raw)
580 out_t_parts.append(out_t_part)
581
582 out = isp.source_reset().rstrip()
583 out_t = '\n'.join(out_t_parts).rstrip()
584 self.assertEqual(out, out_t)
585
586
587 #-----------------------------------------------------------------------------
588 # Main - use as a script
589 #-----------------------------------------------------------------------------
590
591 if __name__ == '__main__':
592 # A simple demo for interactive experimentation. This code will not get
593 # picked up by any test suite. Useful mostly for illustration and during
594 # development.
595 from IPython.core.inputsplitter import InputSplitter, IPythonInputSplitter
596
597 # configure here the syntax to use, prompt and whether to autoindent
598 #isp, start_prompt = InputSplitter(), '>>> '
599 isp, start_prompt = IPythonInputSplitter(), 'In> '
600
601 autoindent = True
602 #autoindent = False
603
604 try:
605 while True:
606 prompt = start_prompt
607 while isp.push_accepts_more():
608 indent = ' '*isp.indent_spaces
609 if autoindent:
610 line = indent + raw_input(prompt+indent)
611 else:
612 line = raw_input(prompt)
613 isp.push(line)
614 prompt = '... '
615
616 # Here we just return input so we can use it in a test suite, but a
617 # real interpreter would instead send it for execution somewhere.
618 src = isp.source_reset()
619 print 'Input source was:\n', src
620 except EOFError:
621 print 'Bye'
@@ -295,8 +295,9 b' def make_quoted_expr(s):'
295 quote = "'''"
295 quote = "'''"
296 else:
296 else:
297 # give up, backslash-escaped string will do
297 # give up, backslash-escaped string will do
298 return '"%s"' % esc_quotes(s)
298 return '"%s"' % esc_quotes(s).strip()
299 res = raw + quote + s + tailpadding + quote + tail
299 txt = (s + tailpadding).strip()
300 res = raw + quote + txt + quote + tail
300 return res
301 return res
301
302
302
303
General Comments 0
You need to be logged in to leave comments. Login now