##// END OF EJS Templates
Mechanism for testing terminal interact loop in-process....
Thomas Kluyver -
Show More
@@ -17,12 +17,68 b' Authors'
17 17 #-----------------------------------------------------------------------------
18 18 # stdlib
19 19 import sys
20 import types
20 21 import unittest
21 22
23 from IPython.core.inputtransformer import InputTransformer
22 24 from IPython.testing.decorators import skipif
23 25 from IPython.utils import py3compat
24 26 from IPython.testing import tools as tt
25 27
28 # Decorator for interaction loop tests -----------------------------------------
29
30 class mock_input_helper(object):
31 """Machinery for tests of the main interact loop.
32
33 Used by the mock_input decorator.
34 """
35 def __init__(self, testgen):
36 self.testgen = testgen
37 self.exception = None
38 self.ip = get_ipython()
39
40 def __enter__(self):
41 self.orig_raw_input = self.ip.raw_input
42 self.ip.raw_input = self.fake_input
43 return self
44
45 def __exit__(self, etype, value, tb):
46 self.ip.raw_input = self.orig_raw_input
47
48 def fake_input(self, prompt):
49 try:
50 return next(self.testgen)
51 except StopIteration:
52 self.ip.exit_now = True
53 return u''
54 except:
55 self.exception = sys.exc_info()
56 self.ip.exit_now = True
57 return u''
58
59 def mock_input(testfunc):
60 """Decorator for tests of the main interact loop.
61
62 Write the test as a generator, yield-ing the input strings, which IPython
63 will see as if they were typed in at the prompt.
64 """
65 def test_method(self):
66 testgen = testfunc(self)
67 with mock_input_helper(testgen) as mih:
68 mih.ip.interact(display_banner=False)
69
70 if mih.exception is not None:
71 # Re-raise captured exception
72 etype, value, tb = mih.exception
73 import traceback
74 traceback.print_tb(tb, file=sys.stdout)
75 del tb # Avoid reference loop
76 raise value
77
78 return test_method
79
80 # Test classes -----------------------------------------------------------------
81
26 82 class InteractiveShellTestCase(unittest.TestCase):
27 83 def rl_hist_entries(self, rl, n):
28 84 """Get last n readline history entries as a list"""
@@ -171,6 +227,42 b' class InteractiveShellTestCase(unittest.TestCase):'
171 227 expected = [ py3compat.unicode_to_str(e, enc) for e in expected ]
172 228 self.assertEqual(hist, expected)
173 229
230 @mock_input
231 def test_inputtransformer_syntaxerror(self):
232 ip = get_ipython()
233 transformer = SyntaxErrorTransformer()
234 ip.input_splitter.python_line_transforms.append(transformer)
235 ip.input_transformer_manager.python_line_transforms.append(transformer)
236
237 try:
238 #raise Exception
239 with tt.AssertPrints('4', suppress=False):
240 yield u'print(2*2)'
241
242 with tt.AssertPrints('SyntaxError: input contains', suppress=False):
243 yield u'print(2345) # syntaxerror'
244
245 with tt.AssertPrints('16', suppress=False):
246 yield u'print(4*4)'
247
248 finally:
249 ip.input_splitter.python_line_transforms.remove(transformer)
250 ip.input_transformer_manager.python_line_transforms.remove(transformer)
251
252
253 class SyntaxErrorTransformer(InputTransformer):
254 def push(self, line):
255 pos = line.find('syntaxerror')
256 if pos >= 0:
257 e = SyntaxError('input contains "syntaxerror"')
258 e.text = line
259 e.offset = pos + 1
260 raise e
261 return line
262
263 def reset(self):
264 pass
265
174 266 class TerminalMagicsTestCase(unittest.TestCase):
175 267 def test_paste_magics_message(self):
176 268 """Test that an IndentationError while using paste magics doesn't
@@ -173,7 +173,7 b' def get_ipython_cmd(as_string=False):'
173 173
174 174 return ipython_cmd
175 175
176 def ipexec(fname, options=None, pipe=False):
176 def ipexec(fname, options=None):
177 177 """Utility to call 'ipython filename'.
178 178
179 179 Starts IPython with a minimal and safe configuration to make startup as fast
@@ -189,9 +189,6 b' def ipexec(fname, options=None, pipe=False):'
189 189 options : optional, list
190 190 Extra command-line flags to be passed to IPython.
191 191
192 pipe : optional, boolean
193 Pipe fname into IPython as stdin instead of calling it as external file
194
195 192 Returns
196 193 -------
197 194 (stdout, stderr) of ipython subprocess.
@@ -211,12 +208,8 b' def ipexec(fname, options=None, pipe=False):'
211 208 ipython_cmd = get_ipython_cmd()
212 209 # Absolute path for filename
213 210 full_fname = os.path.join(test_dir, fname)
214 if pipe:
215 full_cmd = ipython_cmd + cmdargs
216 p = Popen(full_cmd, stdin=open(full_fname), stdout=PIPE, stderr=PIPE)
217 else:
218 full_cmd = ipython_cmd + cmdargs + [full_fname]
219 p = Popen(full_cmd, stdout=PIPE, stderr=PIPE)
211 full_cmd = ipython_cmd + cmdargs + [full_fname]
212 p = Popen(full_cmd, stdout=PIPE, stderr=PIPE)
220 213 out, err = p.communicate()
221 214 out, err = py3compat.bytes_to_str(out), py3compat.bytes_to_str(err)
222 215 # `import readline` causes 'ESC[?1034h' to be output sometimes,
@@ -42,6 +42,11 b' class IOStream:'
42 42 for meth in filter(clone, dir(stream)):
43 43 setattr(self, meth, getattr(stream, meth))
44 44
45 def __repr__(self):
46 cls = self.__class__
47 tpl = '{mod}.{cls}({args})'
48 return tpl.format(mod=cls.__module__, cls=cls.__name__, args=self.stream)
49
45 50 def write(self,data):
46 51 try:
47 52 self._swrite(data)
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now