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 | input or None if the transformer is waiting for more input. |
|
47 | input or None if the transformer is waiting for more input. | |
48 |
|
48 | |||
49 | Must be overridden by subclasses. |
|
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 | pass |
|
54 | pass | |
52 |
|
55 |
@@ -2632,7 +2632,12 b' class InteractiveShell(SingletonConfigurable):' | |||||
2632 | if silent: |
|
2632 | if silent: | |
2633 | store_history = False |
|
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 | cell = self.input_transformer_manager.source_reset() |
|
2641 | cell = self.input_transformer_manager.source_reset() | |
2637 |
|
2642 | |||
2638 | # Our own compiler remembers the __future__ environment. If we want to |
|
2643 | # Our own compiler remembers the __future__ environment. If we want to | |
@@ -2641,8 +2646,7 b' class InteractiveShell(SingletonConfigurable):' | |||||
2641 | compiler = self.compile if shell_futures else CachingCompiler() |
|
2646 | compiler = self.compile if shell_futures else CachingCompiler() | |
2642 |
|
2647 | |||
2643 | with self.builtin_trap: |
|
2648 | with self.builtin_trap: | |
2644 | prefilter_failed = False |
|
2649 | if not prefilter_failed and len(cell.splitlines()) == 1: | |
2645 | if len(cell.splitlines()) == 1: |
|
|||
2646 | try: |
|
2650 | try: | |
2647 | # use prefilter_lines to handle trailing newlines |
|
2651 | # use prefilter_lines to handle trailing newlines | |
2648 | # restore trailing newline for ast.parse |
|
2652 | # restore trailing newline for ast.parse |
@@ -3,13 +3,9 b'' | |||||
3 |
|
3 | |||
4 | import os |
|
4 | import os | |
5 | import tempfile |
|
5 | import tempfile | |
6 | import shutil |
|
|||
7 |
|
||||
8 | import nose.tools as nt |
|
|||
9 |
|
6 | |||
10 | from IPython.core.application import BaseIPythonApplication |
|
7 | from IPython.core.application import BaseIPythonApplication | |
11 | from IPython.testing import decorators as dec |
|
8 | from IPython.testing import decorators as dec | |
12 | from IPython.testing.tools import make_tempfile, ipexec |
|
|||
13 | from IPython.utils import py3compat |
|
9 | from IPython.utils import py3compat | |
14 |
|
10 | |||
15 | @dec.onlyif_unicode_paths |
|
11 | @dec.onlyif_unicode_paths | |
@@ -52,46 +48,3 b' def test_unicode_ipdir():' | |||||
52 | os.environ["IPYTHONDIR"] = old_ipdir1 |
|
48 | os.environ["IPYTHONDIR"] = old_ipdir1 | |
53 | if old_ipdir2: |
|
49 | if old_ipdir2: | |
54 | os.environ["IPYTHONDIR"] = old_ipdir2 |
|
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 | import nose.tools as nt |
|
33 | import nose.tools as nt | |
34 |
|
34 | |||
35 | # Our own |
|
35 | # Our own | |
|
36 | from IPython.core.inputtransformer import InputTransformer | |||
36 | from IPython.testing.decorators import skipif, skip_win32, onlyif_unicode_paths |
|
37 | from IPython.testing.decorators import skipif, skip_win32, onlyif_unicode_paths | |
37 | from IPython.testing import tools as tt |
|
38 | from IPython.testing import tools as tt | |
38 | from IPython.utils import io |
|
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