Show More
@@ -0,0 +1,58 b'' | |||
|
1 | # coding: utf-8 | |
|
2 | """Tests for the IPython terminal""" | |
|
3 | ||
|
4 | import os | |
|
5 | import tempfile | |
|
6 | import shutil | |
|
7 | ||
|
8 | import nose.tools as nt | |
|
9 | ||
|
10 | from IPython.testing.tools import make_tempfile, ipexec | |
|
11 | ||
|
12 | ||
|
13 | TEST_SYNTAX_ERROR_CMDS = """ | |
|
14 | from IPython.core.inputtransformer import InputTransformer | |
|
15 | ||
|
16 | %cpaste | |
|
17 | class SyntaxErrorTransformer(InputTransformer): | |
|
18 | ||
|
19 | def push(self, line): | |
|
20 | pos = line.find('syntaxerror') | |
|
21 | if pos >= 0: | |
|
22 | e = SyntaxError('input contains "syntaxerror"') | |
|
23 | e.text = line | |
|
24 | e.offset = pos + 1 | |
|
25 | raise e | |
|
26 | return line | |
|
27 | ||
|
28 | def reset(self): | |
|
29 | pass | |
|
30 | -- | |
|
31 | ||
|
32 | ip = get_ipython() | |
|
33 | transformer = SyntaxErrorTransformer() | |
|
34 | ip.input_splitter.python_line_transforms.append(transformer) | |
|
35 | ip.input_transformer_manager.python_line_transforms.append(transformer) | |
|
36 | ||
|
37 | # now the actual commands | |
|
38 | 1234 | |
|
39 | 2345 # syntaxerror <- triggered here | |
|
40 | 3456 | |
|
41 | """ | |
|
42 | ||
|
43 | def test_syntax_error(): | |
|
44 | """Check that the IPython terminal does not abort if a SyntaxError is raised in an InputTransformer""" | |
|
45 | try: | |
|
46 | tmp = tempfile.mkdtemp() | |
|
47 | filename = os.path.join(tmp, 'test_syntax_error.py') | |
|
48 | with open(filename, 'w') as f: | |
|
49 | f.write(TEST_SYNTAX_ERROR_CMDS) | |
|
50 | out, err = ipexec(filename, pipe=True) | |
|
51 | nt.assert_equal(err, '') | |
|
52 | nt.assert_in('1234', out) | |
|
53 | nt.assert_in(' 2345 # syntaxerror <- triggered here', out) | |
|
54 | nt.assert_in(' ^', out) | |
|
55 | nt.assert_in('SyntaxError: input contains "syntaxerror"', out) | |
|
56 | nt.assert_in('3456', out) | |
|
57 | finally: | |
|
58 | shutil.rmtree(tmp) |
@@ -47,6 +47,9 b' class InputTransformer(with_metaclass(abc.ABCMeta, object)):' | |||
|
47 | 47 | input or None if the transformer is waiting for more input. |
|
48 | 48 | |
|
49 | 49 | Must be overridden by subclasses. |
|
50 | ||
|
51 | Implementations may raise ``SyntaxError`` if the input is invalid. No | |
|
52 | other exceptions may be raised. | |
|
50 | 53 | """ |
|
51 | 54 | pass |
|
52 | 55 |
@@ -2632,7 +2632,12 b' class InteractiveShell(SingletonConfigurable):' | |||
|
2632 | 2632 | if silent: |
|
2633 | 2633 | store_history = False |
|
2634 | 2634 | |
|
2635 | self.input_transformer_manager.push(raw_cell) | |
|
2635 | prefilter_failed = False | |
|
2636 | try: | |
|
2637 | self.input_transformer_manager.push(raw_cell) | |
|
2638 | except SyntaxError: | |
|
2639 | self.showtraceback() | |
|
2640 | prefilter_failed = True | |
|
2636 | 2641 | cell = self.input_transformer_manager.source_reset() |
|
2637 | 2642 | |
|
2638 | 2643 | # Our own compiler remembers the __future__ environment. If we want to |
@@ -2641,8 +2646,7 b' class InteractiveShell(SingletonConfigurable):' | |||
|
2641 | 2646 | compiler = self.compile if shell_futures else CachingCompiler() |
|
2642 | 2647 | |
|
2643 | 2648 | with self.builtin_trap: |
|
2644 | prefilter_failed = False | |
|
2645 | if len(cell.splitlines()) == 1: | |
|
2649 | if not prefilter_failed and len(cell.splitlines()) == 1: | |
|
2646 | 2650 | try: |
|
2647 | 2651 | # use prefilter_lines to handle trailing newlines |
|
2648 | 2652 | # restore trailing newline for ast.parse |
@@ -3,13 +3,9 b'' | |||
|
3 | 3 | |
|
4 | 4 | import os |
|
5 | 5 | import tempfile |
|
6 | import shutil | |
|
7 | ||
|
8 | import nose.tools as nt | |
|
9 | 6 | |
|
10 | 7 | from IPython.core.application import BaseIPythonApplication |
|
11 | 8 | from IPython.testing import decorators as dec |
|
12 | from IPython.testing.tools import make_tempfile, ipexec | |
|
13 | 9 | from IPython.utils import py3compat |
|
14 | 10 | |
|
15 | 11 | @dec.onlyif_unicode_paths |
@@ -52,46 +48,3 b' def test_unicode_ipdir():' | |||
|
52 | 48 | os.environ["IPYTHONDIR"] = old_ipdir1 |
|
53 | 49 | if old_ipdir2: |
|
54 | 50 | os.environ["IPYTHONDIR"] = old_ipdir2 |
|
55 | ||
|
56 | ||
|
57 | ||
|
58 | TEST_SYNTAX_ERROR_CMDS = """ | |
|
59 | from IPython.core.inputtransformer import InputTransformer | |
|
60 | ||
|
61 | %cpaste | |
|
62 | class SyntaxErrorTransformer(InputTransformer): | |
|
63 | ||
|
64 | def push(self, line): | |
|
65 | if 'syntaxerror' in line: | |
|
66 | raise SyntaxError('in input '+line) | |
|
67 | return line | |
|
68 | ||
|
69 | def reset(self): | |
|
70 | pass | |
|
71 | -- | |
|
72 | ||
|
73 | ip = get_ipython() | |
|
74 | transformer = SyntaxErrorTransformer() | |
|
75 | ip.input_splitter.python_line_transforms.append(transformer) | |
|
76 | ip.input_transformer_manager.python_line_transforms.append(transformer) | |
|
77 | ||
|
78 | # now the actual commands | |
|
79 | 1234 | |
|
80 | 2345 # syntaxerror <- triggered here | |
|
81 | 3456 | |
|
82 | """ | |
|
83 | ||
|
84 | def test_syntax_error(): | |
|
85 | """Check that IPython does not abort if a SyntaxError is raised in an InputTransformer""" | |
|
86 | try: | |
|
87 | tmp = tempfile.mkdtemp() | |
|
88 | filename = os.path.join(tmp, 'test_syntax_error.py') | |
|
89 | with open(filename, 'w') as f: | |
|
90 | f.write(TEST_SYNTAX_ERROR_CMDS) | |
|
91 | out, err = ipexec(filename, pipe=True) | |
|
92 | nt.assert_equal(err, '') | |
|
93 | nt.assert_in('1234', out) | |
|
94 | nt.assert_in('SyntaxError: in input 2345 # syntaxerror <- triggered here', out) | |
|
95 | nt.assert_in('3456', out) | |
|
96 | finally: | |
|
97 | shutil.rmtree(tmp) |
@@ -33,6 +33,7 b' from os.path import join' | |||
|
33 | 33 | import nose.tools as nt |
|
34 | 34 | |
|
35 | 35 | # Our own |
|
36 | from IPython.core.inputtransformer import InputTransformer | |
|
36 | 37 | from IPython.testing.decorators import skipif, skip_win32, onlyif_unicode_paths |
|
37 | 38 | from IPython.testing import tools as tt |
|
38 | 39 | from IPython.utils import io |
@@ -674,4 +675,41 b' def test_user_expression():' | |||
|
674 | 675 | |
|
675 | 676 | |
|
676 | 677 | |
|
678 | class TestSyntaxErrorTransformer(unittest.TestCase): | |
|
679 | """Check that SyntaxError raised by an input transformer is handled by run_cell()""" | |
|
680 | ||
|
681 | class SyntaxErrorTransformer(InputTransformer): | |
|
682 | ||
|
683 | def push(self, line): | |
|
684 | pos = line.find('syntaxerror') | |
|
685 | if pos >= 0: | |
|
686 | e = SyntaxError('input contains "syntaxerror"') | |
|
687 | e.text = line | |
|
688 | e.offset = pos + 1 | |
|
689 | raise e | |
|
690 | return line | |
|
691 | ||
|
692 | def reset(self): | |
|
693 | pass | |
|
694 | ||
|
695 | def setUp(self): | |
|
696 | self.transformer = TestSyntaxErrorTransformer.SyntaxErrorTransformer() | |
|
697 | ip.input_splitter.python_line_transforms.append(self.transformer) | |
|
698 | ip.input_transformer_manager.python_line_transforms.append(self.transformer) | |
|
699 | ||
|
700 | def tearDown(self): | |
|
701 | ip.input_splitter.python_line_transforms.remove(self.transformer) | |
|
702 | ip.input_transformer_manager.python_line_transforms.remove(self.transformer) | |
|
703 | ||
|
704 | def test_syntaxerror_input_transformer(self): | |
|
705 | with tt.AssertPrints('1234'): | |
|
706 | ip.run_cell('1234') | |
|
707 | with tt.AssertPrints('SyntaxError: invalid syntax'): | |
|
708 | ip.run_cell('1 2 3') # plain python syntax error | |
|
709 | with tt.AssertPrints('SyntaxError: input contains "syntaxerror"'): | |
|
710 | ip.run_cell('2345 # syntaxerror') # input transformer syntax error | |
|
711 | with tt.AssertPrints('3456'): | |
|
712 | ip.run_cell('3456') | |
|
713 | ||
|
714 | ||
|
677 | 715 |
General Comments 0
You need to be logged in to leave comments.
Login now