##// END OF EJS Templates
Also catch SyntaxErrors from InputTransformers in run_cell()...
Volker Braun -
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