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 |
|
|
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,10 +208,6 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 | 211 |
|
|
219 | 212 |
|
|
220 | 213 | out, err = p.communicate() |
@@ -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