Show More
@@ -17,12 +17,68 b' Authors' | |||||
17 | #----------------------------------------------------------------------------- |
|
17 | #----------------------------------------------------------------------------- | |
18 | # stdlib |
|
18 | # stdlib | |
19 | import sys |
|
19 | import sys | |
|
20 | import types | |||
20 | import unittest |
|
21 | import unittest | |
21 |
|
22 | |||
|
23 | from IPython.core.inputtransformer import InputTransformer | |||
22 | from IPython.testing.decorators import skipif |
|
24 | from IPython.testing.decorators import skipif | |
23 | from IPython.utils import py3compat |
|
25 | from IPython.utils import py3compat | |
24 | from IPython.testing import tools as tt |
|
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 | class InteractiveShellTestCase(unittest.TestCase): |
|
82 | class InteractiveShellTestCase(unittest.TestCase): | |
27 | def rl_hist_entries(self, rl, n): |
|
83 | def rl_hist_entries(self, rl, n): | |
28 | """Get last n readline history entries as a list""" |
|
84 | """Get last n readline history entries as a list""" | |
@@ -171,6 +227,42 b' class InteractiveShellTestCase(unittest.TestCase):' | |||||
171 | expected = [ py3compat.unicode_to_str(e, enc) for e in expected ] |
|
227 | expected = [ py3compat.unicode_to_str(e, enc) for e in expected ] | |
172 | self.assertEqual(hist, expected) |
|
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 | class TerminalMagicsTestCase(unittest.TestCase): |
|
266 | class TerminalMagicsTestCase(unittest.TestCase): | |
175 | def test_paste_magics_message(self): |
|
267 | def test_paste_magics_message(self): | |
176 | """Test that an IndentationError while using paste magics doesn't |
|
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 | return ipython_cmd |
|
174 | return ipython_cmd | |
175 |
|
175 | |||
176 |
def ipexec(fname, options=None |
|
176 | def ipexec(fname, options=None): | |
177 | """Utility to call 'ipython filename'. |
|
177 | """Utility to call 'ipython filename'. | |
178 |
|
178 | |||
179 | Starts IPython with a minimal and safe configuration to make startup as fast |
|
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 | options : optional, list |
|
189 | options : optional, list | |
190 | Extra command-line flags to be passed to IPython. |
|
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 | Returns |
|
192 | Returns | |
196 | ------- |
|
193 | ------- | |
197 | (stdout, stderr) of ipython subprocess. |
|
194 | (stdout, stderr) of ipython subprocess. | |
@@ -211,10 +208,6 b' def ipexec(fname, options=None, pipe=False):' | |||||
211 | ipython_cmd = get_ipython_cmd() |
|
208 | ipython_cmd = get_ipython_cmd() | |
212 | # Absolute path for filename |
|
209 | # Absolute path for filename | |
213 | full_fname = os.path.join(test_dir, fname) |
|
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 | full_cmd = ipython_cmd + cmdargs + [full_fname] | |
219 |
|
|
212 | p = Popen(full_cmd, stdout=PIPE, stderr=PIPE) | |
220 | out, err = p.communicate() |
|
213 | out, err = p.communicate() |
@@ -42,6 +42,11 b' class IOStream:' | |||||
42 | for meth in filter(clone, dir(stream)): |
|
42 | for meth in filter(clone, dir(stream)): | |
43 | setattr(self, meth, getattr(stream, meth)) |
|
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 | def write(self,data): |
|
50 | def write(self,data): | |
46 | try: |
|
51 | try: | |
47 | self._swrite(data) |
|
52 | self._swrite(data) |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now