##// END OF EJS Templates
[issue6883] catch keyboardinterrupt if generated during shell.system() calls
mvr -
Show More

The requested changes are too big and content was truncated. Show full diff

1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,859 +1,869 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for the key interactiveshell module.
2 """Tests for the key interactiveshell module.
3
3
4 Historically the main classes in interactiveshell have been under-tested. This
4 Historically the main classes in interactiveshell have been under-tested. This
5 module should grow as many single-method tests as possible to trap many of the
5 module should grow as many single-method tests as possible to trap many of the
6 recurring bugs we seem to encounter with high-level interaction.
6 recurring bugs we seem to encounter with high-level interaction.
7 """
7 """
8
8
9 # Copyright (c) IPython Development Team.
9 # Copyright (c) IPython Development Team.
10 # Distributed under the terms of the Modified BSD License.
10 # Distributed under the terms of the Modified BSD License.
11
11
12 import ast
12 import ast
13 import os
13 import os
14 import signal
14 import signal
15 import shutil
15 import shutil
16 import sys
16 import sys
17 import tempfile
17 import tempfile
18 import unittest
18 import unittest
19 try:
19 try:
20 from unittest import mock
20 from unittest import mock
21 except ImportError:
21 except ImportError:
22 import mock
22 import mock
23 from os.path import join
23 from os.path import join
24
24
25 import nose.tools as nt
25 import nose.tools as nt
26
26
27 from IPython.core.error import InputRejected
27 from IPython.core.error import InputRejected
28 from IPython.core.inputtransformer import InputTransformer
28 from IPython.core.inputtransformer import InputTransformer
29 from IPython.testing.decorators import (
29 from IPython.testing.decorators import (
30 skipif, skip_win32, onlyif_unicode_paths, onlyif_cmds_exist,
30 skipif, skip_win32, onlyif_unicode_paths, onlyif_cmds_exist,
31 )
31 )
32 from IPython.testing import tools as tt
32 from IPython.testing import tools as tt
33 from IPython.utils import io
33 from IPython.utils import io
34 from IPython.utils.process import find_cmd
34 from IPython.utils.process import find_cmd
35 from IPython.utils import py3compat
35 from IPython.utils import py3compat
36 from IPython.utils.py3compat import unicode_type, PY3
36 from IPython.utils.py3compat import unicode_type, PY3
37
37
38 if PY3:
38 if PY3:
39 from io import StringIO
39 from io import StringIO
40 else:
40 else:
41 from StringIO import StringIO
41 from StringIO import StringIO
42
42
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44 # Globals
44 # Globals
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46 # This is used by every single test, no point repeating it ad nauseam
46 # This is used by every single test, no point repeating it ad nauseam
47 ip = get_ipython()
47 ip = get_ipython()
48
48
49 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
50 # Tests
50 # Tests
51 #-----------------------------------------------------------------------------
51 #-----------------------------------------------------------------------------
52
52
53 class InteractiveShellTestCase(unittest.TestCase):
53 class InteractiveShellTestCase(unittest.TestCase):
54 def test_naked_string_cells(self):
54 def test_naked_string_cells(self):
55 """Test that cells with only naked strings are fully executed"""
55 """Test that cells with only naked strings are fully executed"""
56 # First, single-line inputs
56 # First, single-line inputs
57 ip.run_cell('"a"\n')
57 ip.run_cell('"a"\n')
58 self.assertEqual(ip.user_ns['_'], 'a')
58 self.assertEqual(ip.user_ns['_'], 'a')
59 # And also multi-line cells
59 # And also multi-line cells
60 ip.run_cell('"""a\nb"""\n')
60 ip.run_cell('"""a\nb"""\n')
61 self.assertEqual(ip.user_ns['_'], 'a\nb')
61 self.assertEqual(ip.user_ns['_'], 'a\nb')
62
62
63 def test_run_empty_cell(self):
63 def test_run_empty_cell(self):
64 """Just make sure we don't get a horrible error with a blank
64 """Just make sure we don't get a horrible error with a blank
65 cell of input. Yes, I did overlook that."""
65 cell of input. Yes, I did overlook that."""
66 old_xc = ip.execution_count
66 old_xc = ip.execution_count
67 ip.run_cell('')
67 ip.run_cell('')
68 self.assertEqual(ip.execution_count, old_xc)
68 self.assertEqual(ip.execution_count, old_xc)
69
69
70 def test_run_cell_multiline(self):
70 def test_run_cell_multiline(self):
71 """Multi-block, multi-line cells must execute correctly.
71 """Multi-block, multi-line cells must execute correctly.
72 """
72 """
73 src = '\n'.join(["x=1",
73 src = '\n'.join(["x=1",
74 "y=2",
74 "y=2",
75 "if 1:",
75 "if 1:",
76 " x += 1",
76 " x += 1",
77 " y += 1",])
77 " y += 1",])
78 ip.run_cell(src)
78 ip.run_cell(src)
79 self.assertEqual(ip.user_ns['x'], 2)
79 self.assertEqual(ip.user_ns['x'], 2)
80 self.assertEqual(ip.user_ns['y'], 3)
80 self.assertEqual(ip.user_ns['y'], 3)
81
81
82 def test_multiline_string_cells(self):
82 def test_multiline_string_cells(self):
83 "Code sprinkled with multiline strings should execute (GH-306)"
83 "Code sprinkled with multiline strings should execute (GH-306)"
84 ip.run_cell('tmp=0')
84 ip.run_cell('tmp=0')
85 self.assertEqual(ip.user_ns['tmp'], 0)
85 self.assertEqual(ip.user_ns['tmp'], 0)
86 ip.run_cell('tmp=1;"""a\nb"""\n')
86 ip.run_cell('tmp=1;"""a\nb"""\n')
87 self.assertEqual(ip.user_ns['tmp'], 1)
87 self.assertEqual(ip.user_ns['tmp'], 1)
88
88
89 def test_dont_cache_with_semicolon(self):
89 def test_dont_cache_with_semicolon(self):
90 "Ending a line with semicolon should not cache the returned object (GH-307)"
90 "Ending a line with semicolon should not cache the returned object (GH-307)"
91 oldlen = len(ip.user_ns['Out'])
91 oldlen = len(ip.user_ns['Out'])
92 for cell in ['1;', '1;1;']:
92 for cell in ['1;', '1;1;']:
93 ip.run_cell(cell, store_history=True)
93 ip.run_cell(cell, store_history=True)
94 newlen = len(ip.user_ns['Out'])
94 newlen = len(ip.user_ns['Out'])
95 self.assertEqual(oldlen, newlen)
95 self.assertEqual(oldlen, newlen)
96 i = 0
96 i = 0
97 #also test the default caching behavior
97 #also test the default caching behavior
98 for cell in ['1', '1;1']:
98 for cell in ['1', '1;1']:
99 ip.run_cell(cell, store_history=True)
99 ip.run_cell(cell, store_history=True)
100 newlen = len(ip.user_ns['Out'])
100 newlen = len(ip.user_ns['Out'])
101 i += 1
101 i += 1
102 self.assertEqual(oldlen+i, newlen)
102 self.assertEqual(oldlen+i, newlen)
103
103
104 def test_In_variable(self):
104 def test_In_variable(self):
105 "Verify that In variable grows with user input (GH-284)"
105 "Verify that In variable grows with user input (GH-284)"
106 oldlen = len(ip.user_ns['In'])
106 oldlen = len(ip.user_ns['In'])
107 ip.run_cell('1;', store_history=True)
107 ip.run_cell('1;', store_history=True)
108 newlen = len(ip.user_ns['In'])
108 newlen = len(ip.user_ns['In'])
109 self.assertEqual(oldlen+1, newlen)
109 self.assertEqual(oldlen+1, newlen)
110 self.assertEqual(ip.user_ns['In'][-1],'1;')
110 self.assertEqual(ip.user_ns['In'][-1],'1;')
111
111
112 def test_magic_names_in_string(self):
112 def test_magic_names_in_string(self):
113 ip.run_cell('a = """\n%exit\n"""')
113 ip.run_cell('a = """\n%exit\n"""')
114 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
114 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
115
115
116 def test_trailing_newline(self):
116 def test_trailing_newline(self):
117 """test that running !(command) does not raise a SyntaxError"""
117 """test that running !(command) does not raise a SyntaxError"""
118 ip.run_cell('!(true)\n', False)
118 ip.run_cell('!(true)\n', False)
119 ip.run_cell('!(true)\n\n\n', False)
119 ip.run_cell('!(true)\n\n\n', False)
120
120
121 def test_gh_597(self):
121 def test_gh_597(self):
122 """Pretty-printing lists of objects with non-ascii reprs may cause
122 """Pretty-printing lists of objects with non-ascii reprs may cause
123 problems."""
123 problems."""
124 class Spam(object):
124 class Spam(object):
125 def __repr__(self):
125 def __repr__(self):
126 return "\xe9"*50
126 return "\xe9"*50
127 import IPython.core.formatters
127 import IPython.core.formatters
128 f = IPython.core.formatters.PlainTextFormatter()
128 f = IPython.core.formatters.PlainTextFormatter()
129 f([Spam(),Spam()])
129 f([Spam(),Spam()])
130
130
131
131
132 def test_future_flags(self):
132 def test_future_flags(self):
133 """Check that future flags are used for parsing code (gh-777)"""
133 """Check that future flags are used for parsing code (gh-777)"""
134 ip.run_cell('from __future__ import print_function')
134 ip.run_cell('from __future__ import print_function')
135 try:
135 try:
136 ip.run_cell('prfunc_return_val = print(1,2, sep=" ")')
136 ip.run_cell('prfunc_return_val = print(1,2, sep=" ")')
137 assert 'prfunc_return_val' in ip.user_ns
137 assert 'prfunc_return_val' in ip.user_ns
138 finally:
138 finally:
139 # Reset compiler flags so we don't mess up other tests.
139 # Reset compiler flags so we don't mess up other tests.
140 ip.compile.reset_compiler_flags()
140 ip.compile.reset_compiler_flags()
141
141
142 def test_future_unicode(self):
142 def test_future_unicode(self):
143 """Check that unicode_literals is imported from __future__ (gh #786)"""
143 """Check that unicode_literals is imported from __future__ (gh #786)"""
144 try:
144 try:
145 ip.run_cell(u'byte_str = "a"')
145 ip.run_cell(u'byte_str = "a"')
146 assert isinstance(ip.user_ns['byte_str'], str) # string literals are byte strings by default
146 assert isinstance(ip.user_ns['byte_str'], str) # string literals are byte strings by default
147 ip.run_cell('from __future__ import unicode_literals')
147 ip.run_cell('from __future__ import unicode_literals')
148 ip.run_cell(u'unicode_str = "a"')
148 ip.run_cell(u'unicode_str = "a"')
149 assert isinstance(ip.user_ns['unicode_str'], unicode_type) # strings literals are now unicode
149 assert isinstance(ip.user_ns['unicode_str'], unicode_type) # strings literals are now unicode
150 finally:
150 finally:
151 # Reset compiler flags so we don't mess up other tests.
151 # Reset compiler flags so we don't mess up other tests.
152 ip.compile.reset_compiler_flags()
152 ip.compile.reset_compiler_flags()
153
153
154 def test_can_pickle(self):
154 def test_can_pickle(self):
155 "Can we pickle objects defined interactively (GH-29)"
155 "Can we pickle objects defined interactively (GH-29)"
156 ip = get_ipython()
156 ip = get_ipython()
157 ip.reset()
157 ip.reset()
158 ip.run_cell(("class Mylist(list):\n"
158 ip.run_cell(("class Mylist(list):\n"
159 " def __init__(self,x=[]):\n"
159 " def __init__(self,x=[]):\n"
160 " list.__init__(self,x)"))
160 " list.__init__(self,x)"))
161 ip.run_cell("w=Mylist([1,2,3])")
161 ip.run_cell("w=Mylist([1,2,3])")
162
162
163 from pickle import dumps
163 from pickle import dumps
164
164
165 # We need to swap in our main module - this is only necessary
165 # We need to swap in our main module - this is only necessary
166 # inside the test framework, because IPython puts the interactive module
166 # inside the test framework, because IPython puts the interactive module
167 # in place (but the test framework undoes this).
167 # in place (but the test framework undoes this).
168 _main = sys.modules['__main__']
168 _main = sys.modules['__main__']
169 sys.modules['__main__'] = ip.user_module
169 sys.modules['__main__'] = ip.user_module
170 try:
170 try:
171 res = dumps(ip.user_ns["w"])
171 res = dumps(ip.user_ns["w"])
172 finally:
172 finally:
173 sys.modules['__main__'] = _main
173 sys.modules['__main__'] = _main
174 self.assertTrue(isinstance(res, bytes))
174 self.assertTrue(isinstance(res, bytes))
175
175
176 def test_global_ns(self):
176 def test_global_ns(self):
177 "Code in functions must be able to access variables outside them."
177 "Code in functions must be able to access variables outside them."
178 ip = get_ipython()
178 ip = get_ipython()
179 ip.run_cell("a = 10")
179 ip.run_cell("a = 10")
180 ip.run_cell(("def f(x):\n"
180 ip.run_cell(("def f(x):\n"
181 " return x + a"))
181 " return x + a"))
182 ip.run_cell("b = f(12)")
182 ip.run_cell("b = f(12)")
183 self.assertEqual(ip.user_ns["b"], 22)
183 self.assertEqual(ip.user_ns["b"], 22)
184
184
185 def test_bad_custom_tb(self):
185 def test_bad_custom_tb(self):
186 """Check that InteractiveShell is protected from bad custom exception handlers"""
186 """Check that InteractiveShell is protected from bad custom exception handlers"""
187 from IPython.utils import io
187 from IPython.utils import io
188 save_stderr = io.stderr
188 save_stderr = io.stderr
189 try:
189 try:
190 # capture stderr
190 # capture stderr
191 io.stderr = StringIO()
191 io.stderr = StringIO()
192 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
192 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
193 self.assertEqual(ip.custom_exceptions, (IOError,))
193 self.assertEqual(ip.custom_exceptions, (IOError,))
194 ip.run_cell(u'raise IOError("foo")')
194 ip.run_cell(u'raise IOError("foo")')
195 self.assertEqual(ip.custom_exceptions, ())
195 self.assertEqual(ip.custom_exceptions, ())
196 self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
196 self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
197 finally:
197 finally:
198 io.stderr = save_stderr
198 io.stderr = save_stderr
199
199
200 def test_bad_custom_tb_return(self):
200 def test_bad_custom_tb_return(self):
201 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
201 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
202 from IPython.utils import io
202 from IPython.utils import io
203 save_stderr = io.stderr
203 save_stderr = io.stderr
204 try:
204 try:
205 # capture stderr
205 # capture stderr
206 io.stderr = StringIO()
206 io.stderr = StringIO()
207 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
207 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
208 self.assertEqual(ip.custom_exceptions, (NameError,))
208 self.assertEqual(ip.custom_exceptions, (NameError,))
209 ip.run_cell(u'a=abracadabra')
209 ip.run_cell(u'a=abracadabra')
210 self.assertEqual(ip.custom_exceptions, ())
210 self.assertEqual(ip.custom_exceptions, ())
211 self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
211 self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
212 finally:
212 finally:
213 io.stderr = save_stderr
213 io.stderr = save_stderr
214
214
215 def test_drop_by_id(self):
215 def test_drop_by_id(self):
216 myvars = {"a":object(), "b":object(), "c": object()}
216 myvars = {"a":object(), "b":object(), "c": object()}
217 ip.push(myvars, interactive=False)
217 ip.push(myvars, interactive=False)
218 for name in myvars:
218 for name in myvars:
219 assert name in ip.user_ns, name
219 assert name in ip.user_ns, name
220 assert name in ip.user_ns_hidden, name
220 assert name in ip.user_ns_hidden, name
221 ip.user_ns['b'] = 12
221 ip.user_ns['b'] = 12
222 ip.drop_by_id(myvars)
222 ip.drop_by_id(myvars)
223 for name in ["a", "c"]:
223 for name in ["a", "c"]:
224 assert name not in ip.user_ns, name
224 assert name not in ip.user_ns, name
225 assert name not in ip.user_ns_hidden, name
225 assert name not in ip.user_ns_hidden, name
226 assert ip.user_ns['b'] == 12
226 assert ip.user_ns['b'] == 12
227 ip.reset()
227 ip.reset()
228
228
229 def test_var_expand(self):
229 def test_var_expand(self):
230 ip.user_ns['f'] = u'Ca\xf1o'
230 ip.user_ns['f'] = u'Ca\xf1o'
231 self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
231 self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
232 self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
232 self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
233 self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
233 self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
234 self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
234 self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
235
235
236 ip.user_ns['f'] = b'Ca\xc3\xb1o'
236 ip.user_ns['f'] = b'Ca\xc3\xb1o'
237 # This should not raise any exception:
237 # This should not raise any exception:
238 ip.var_expand(u'echo $f')
238 ip.var_expand(u'echo $f')
239
239
240 def test_var_expand_local(self):
240 def test_var_expand_local(self):
241 """Test local variable expansion in !system and %magic calls"""
241 """Test local variable expansion in !system and %magic calls"""
242 # !system
242 # !system
243 ip.run_cell('def test():\n'
243 ip.run_cell('def test():\n'
244 ' lvar = "ttt"\n'
244 ' lvar = "ttt"\n'
245 ' ret = !echo {lvar}\n'
245 ' ret = !echo {lvar}\n'
246 ' return ret[0]\n')
246 ' return ret[0]\n')
247 res = ip.user_ns['test']()
247 res = ip.user_ns['test']()
248 nt.assert_in('ttt', res)
248 nt.assert_in('ttt', res)
249
249
250 # %magic
250 # %magic
251 ip.run_cell('def makemacro():\n'
251 ip.run_cell('def makemacro():\n'
252 ' macroname = "macro_var_expand_locals"\n'
252 ' macroname = "macro_var_expand_locals"\n'
253 ' %macro {macroname} codestr\n')
253 ' %macro {macroname} codestr\n')
254 ip.user_ns['codestr'] = "str(12)"
254 ip.user_ns['codestr'] = "str(12)"
255 ip.run_cell('makemacro()')
255 ip.run_cell('makemacro()')
256 nt.assert_in('macro_var_expand_locals', ip.user_ns)
256 nt.assert_in('macro_var_expand_locals', ip.user_ns)
257
257
258 def test_var_expand_self(self):
258 def test_var_expand_self(self):
259 """Test variable expansion with the name 'self', which was failing.
259 """Test variable expansion with the name 'self', which was failing.
260
260
261 See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218
261 See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218
262 """
262 """
263 ip.run_cell('class cTest:\n'
263 ip.run_cell('class cTest:\n'
264 ' classvar="see me"\n'
264 ' classvar="see me"\n'
265 ' def test(self):\n'
265 ' def test(self):\n'
266 ' res = !echo Variable: {self.classvar}\n'
266 ' res = !echo Variable: {self.classvar}\n'
267 ' return res[0]\n')
267 ' return res[0]\n')
268 nt.assert_in('see me', ip.user_ns['cTest']().test())
268 nt.assert_in('see me', ip.user_ns['cTest']().test())
269
269
270 def test_bad_var_expand(self):
270 def test_bad_var_expand(self):
271 """var_expand on invalid formats shouldn't raise"""
271 """var_expand on invalid formats shouldn't raise"""
272 # SyntaxError
272 # SyntaxError
273 self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
273 self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
274 # NameError
274 # NameError
275 self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
275 self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
276 # ZeroDivisionError
276 # ZeroDivisionError
277 self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
277 self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
278
278
279 def test_silent_postexec(self):
279 def test_silent_postexec(self):
280 """run_cell(silent=True) doesn't invoke pre/post_run_cell callbacks"""
280 """run_cell(silent=True) doesn't invoke pre/post_run_cell callbacks"""
281 pre_explicit = mock.Mock()
281 pre_explicit = mock.Mock()
282 pre_always = mock.Mock()
282 pre_always = mock.Mock()
283 post_explicit = mock.Mock()
283 post_explicit = mock.Mock()
284 post_always = mock.Mock()
284 post_always = mock.Mock()
285
285
286 ip.events.register('pre_run_cell', pre_explicit)
286 ip.events.register('pre_run_cell', pre_explicit)
287 ip.events.register('pre_execute', pre_always)
287 ip.events.register('pre_execute', pre_always)
288 ip.events.register('post_run_cell', post_explicit)
288 ip.events.register('post_run_cell', post_explicit)
289 ip.events.register('post_execute', post_always)
289 ip.events.register('post_execute', post_always)
290
290
291 try:
291 try:
292 ip.run_cell("1", silent=True)
292 ip.run_cell("1", silent=True)
293 assert pre_always.called
293 assert pre_always.called
294 assert not pre_explicit.called
294 assert not pre_explicit.called
295 assert post_always.called
295 assert post_always.called
296 assert not post_explicit.called
296 assert not post_explicit.called
297 # double-check that non-silent exec did what we expected
297 # double-check that non-silent exec did what we expected
298 # silent to avoid
298 # silent to avoid
299 ip.run_cell("1")
299 ip.run_cell("1")
300 assert pre_explicit.called
300 assert pre_explicit.called
301 assert post_explicit.called
301 assert post_explicit.called
302 finally:
302 finally:
303 # remove post-exec
303 # remove post-exec
304 ip.events.unregister('pre_run_cell', pre_explicit)
304 ip.events.unregister('pre_run_cell', pre_explicit)
305 ip.events.unregister('pre_execute', pre_always)
305 ip.events.unregister('pre_execute', pre_always)
306 ip.events.unregister('post_run_cell', post_explicit)
306 ip.events.unregister('post_run_cell', post_explicit)
307 ip.events.unregister('post_execute', post_always)
307 ip.events.unregister('post_execute', post_always)
308
308
309 def test_silent_noadvance(self):
309 def test_silent_noadvance(self):
310 """run_cell(silent=True) doesn't advance execution_count"""
310 """run_cell(silent=True) doesn't advance execution_count"""
311 ec = ip.execution_count
311 ec = ip.execution_count
312 # silent should force store_history=False
312 # silent should force store_history=False
313 ip.run_cell("1", store_history=True, silent=True)
313 ip.run_cell("1", store_history=True, silent=True)
314
314
315 self.assertEqual(ec, ip.execution_count)
315 self.assertEqual(ec, ip.execution_count)
316 # double-check that non-silent exec did what we expected
316 # double-check that non-silent exec did what we expected
317 # silent to avoid
317 # silent to avoid
318 ip.run_cell("1", store_history=True)
318 ip.run_cell("1", store_history=True)
319 self.assertEqual(ec+1, ip.execution_count)
319 self.assertEqual(ec+1, ip.execution_count)
320
320
321 def test_silent_nodisplayhook(self):
321 def test_silent_nodisplayhook(self):
322 """run_cell(silent=True) doesn't trigger displayhook"""
322 """run_cell(silent=True) doesn't trigger displayhook"""
323 d = dict(called=False)
323 d = dict(called=False)
324
324
325 trap = ip.display_trap
325 trap = ip.display_trap
326 save_hook = trap.hook
326 save_hook = trap.hook
327
327
328 def failing_hook(*args, **kwargs):
328 def failing_hook(*args, **kwargs):
329 d['called'] = True
329 d['called'] = True
330
330
331 try:
331 try:
332 trap.hook = failing_hook
332 trap.hook = failing_hook
333 ip.run_cell("1", silent=True)
333 ip.run_cell("1", silent=True)
334 self.assertFalse(d['called'])
334 self.assertFalse(d['called'])
335 # double-check that non-silent exec did what we expected
335 # double-check that non-silent exec did what we expected
336 # silent to avoid
336 # silent to avoid
337 ip.run_cell("1")
337 ip.run_cell("1")
338 self.assertTrue(d['called'])
338 self.assertTrue(d['called'])
339 finally:
339 finally:
340 trap.hook = save_hook
340 trap.hook = save_hook
341
341
342 @skipif(sys.version_info[0] >= 3, "softspace removed in py3")
342 @skipif(sys.version_info[0] >= 3, "softspace removed in py3")
343 def test_print_softspace(self):
343 def test_print_softspace(self):
344 """Verify that softspace is handled correctly when executing multiple
344 """Verify that softspace is handled correctly when executing multiple
345 statements.
345 statements.
346
346
347 In [1]: print 1; print 2
347 In [1]: print 1; print 2
348 1
348 1
349 2
349 2
350
350
351 In [2]: print 1,; print 2
351 In [2]: print 1,; print 2
352 1 2
352 1 2
353 """
353 """
354
354
355 def test_ofind_line_magic(self):
355 def test_ofind_line_magic(self):
356 from IPython.core.magic import register_line_magic
356 from IPython.core.magic import register_line_magic
357
357
358 @register_line_magic
358 @register_line_magic
359 def lmagic(line):
359 def lmagic(line):
360 "A line magic"
360 "A line magic"
361
361
362 # Get info on line magic
362 # Get info on line magic
363 lfind = ip._ofind('lmagic')
363 lfind = ip._ofind('lmagic')
364 info = dict(found=True, isalias=False, ismagic=True,
364 info = dict(found=True, isalias=False, ismagic=True,
365 namespace = 'IPython internal', obj= lmagic.__wrapped__,
365 namespace = 'IPython internal', obj= lmagic.__wrapped__,
366 parent = None)
366 parent = None)
367 nt.assert_equal(lfind, info)
367 nt.assert_equal(lfind, info)
368
368
369 def test_ofind_cell_magic(self):
369 def test_ofind_cell_magic(self):
370 from IPython.core.magic import register_cell_magic
370 from IPython.core.magic import register_cell_magic
371
371
372 @register_cell_magic
372 @register_cell_magic
373 def cmagic(line, cell):
373 def cmagic(line, cell):
374 "A cell magic"
374 "A cell magic"
375
375
376 # Get info on cell magic
376 # Get info on cell magic
377 find = ip._ofind('cmagic')
377 find = ip._ofind('cmagic')
378 info = dict(found=True, isalias=False, ismagic=True,
378 info = dict(found=True, isalias=False, ismagic=True,
379 namespace = 'IPython internal', obj= cmagic.__wrapped__,
379 namespace = 'IPython internal', obj= cmagic.__wrapped__,
380 parent = None)
380 parent = None)
381 nt.assert_equal(find, info)
381 nt.assert_equal(find, info)
382
382
383 def test_ofind_property_with_error(self):
383 def test_ofind_property_with_error(self):
384 class A(object):
384 class A(object):
385 @property
385 @property
386 def foo(self):
386 def foo(self):
387 raise NotImplementedError()
387 raise NotImplementedError()
388 a = A()
388 a = A()
389
389
390 found = ip._ofind('a.foo', [('locals', locals())])
390 found = ip._ofind('a.foo', [('locals', locals())])
391 info = dict(found=True, isalias=False, ismagic=False,
391 info = dict(found=True, isalias=False, ismagic=False,
392 namespace='locals', obj=A.foo, parent=a)
392 namespace='locals', obj=A.foo, parent=a)
393 nt.assert_equal(found, info)
393 nt.assert_equal(found, info)
394
394
395 def test_ofind_multiple_attribute_lookups(self):
395 def test_ofind_multiple_attribute_lookups(self):
396 class A(object):
396 class A(object):
397 @property
397 @property
398 def foo(self):
398 def foo(self):
399 raise NotImplementedError()
399 raise NotImplementedError()
400
400
401 a = A()
401 a = A()
402 a.a = A()
402 a.a = A()
403 a.a.a = A()
403 a.a.a = A()
404
404
405 found = ip._ofind('a.a.a.foo', [('locals', locals())])
405 found = ip._ofind('a.a.a.foo', [('locals', locals())])
406 info = dict(found=True, isalias=False, ismagic=False,
406 info = dict(found=True, isalias=False, ismagic=False,
407 namespace='locals', obj=A.foo, parent=a.a.a)
407 namespace='locals', obj=A.foo, parent=a.a.a)
408 nt.assert_equal(found, info)
408 nt.assert_equal(found, info)
409
409
410 def test_ofind_slotted_attributes(self):
410 def test_ofind_slotted_attributes(self):
411 class A(object):
411 class A(object):
412 __slots__ = ['foo']
412 __slots__ = ['foo']
413 def __init__(self):
413 def __init__(self):
414 self.foo = 'bar'
414 self.foo = 'bar'
415
415
416 a = A()
416 a = A()
417 found = ip._ofind('a.foo', [('locals', locals())])
417 found = ip._ofind('a.foo', [('locals', locals())])
418 info = dict(found=True, isalias=False, ismagic=False,
418 info = dict(found=True, isalias=False, ismagic=False,
419 namespace='locals', obj=a.foo, parent=a)
419 namespace='locals', obj=a.foo, parent=a)
420 nt.assert_equal(found, info)
420 nt.assert_equal(found, info)
421
421
422 found = ip._ofind('a.bar', [('locals', locals())])
422 found = ip._ofind('a.bar', [('locals', locals())])
423 info = dict(found=False, isalias=False, ismagic=False,
423 info = dict(found=False, isalias=False, ismagic=False,
424 namespace=None, obj=None, parent=a)
424 namespace=None, obj=None, parent=a)
425 nt.assert_equal(found, info)
425 nt.assert_equal(found, info)
426
426
427 def test_ofind_prefers_property_to_instance_level_attribute(self):
427 def test_ofind_prefers_property_to_instance_level_attribute(self):
428 class A(object):
428 class A(object):
429 @property
429 @property
430 def foo(self):
430 def foo(self):
431 return 'bar'
431 return 'bar'
432 a = A()
432 a = A()
433 a.__dict__['foo'] = 'baz'
433 a.__dict__['foo'] = 'baz'
434 nt.assert_equal(a.foo, 'bar')
434 nt.assert_equal(a.foo, 'bar')
435 found = ip._ofind('a.foo', [('locals', locals())])
435 found = ip._ofind('a.foo', [('locals', locals())])
436 nt.assert_is(found['obj'], A.foo)
436 nt.assert_is(found['obj'], A.foo)
437
437
438 def test_custom_exception(self):
438 def test_custom_exception(self):
439 called = []
439 called = []
440 def my_handler(shell, etype, value, tb, tb_offset=None):
440 def my_handler(shell, etype, value, tb, tb_offset=None):
441 called.append(etype)
441 called.append(etype)
442 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
442 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
443
443
444 ip.set_custom_exc((ValueError,), my_handler)
444 ip.set_custom_exc((ValueError,), my_handler)
445 try:
445 try:
446 ip.run_cell("raise ValueError('test')")
446 ip.run_cell("raise ValueError('test')")
447 # Check that this was called, and only once.
447 # Check that this was called, and only once.
448 self.assertEqual(called, [ValueError])
448 self.assertEqual(called, [ValueError])
449 finally:
449 finally:
450 # Reset the custom exception hook
450 # Reset the custom exception hook
451 ip.set_custom_exc((), None)
451 ip.set_custom_exc((), None)
452
452
453 @skipif(sys.version_info[0] >= 3, "no differences with __future__ in py3")
453 @skipif(sys.version_info[0] >= 3, "no differences with __future__ in py3")
454 def test_future_environment(self):
454 def test_future_environment(self):
455 "Can we run code with & without the shell's __future__ imports?"
455 "Can we run code with & without the shell's __future__ imports?"
456 ip.run_cell("from __future__ import division")
456 ip.run_cell("from __future__ import division")
457 ip.run_cell("a = 1/2", shell_futures=True)
457 ip.run_cell("a = 1/2", shell_futures=True)
458 self.assertEqual(ip.user_ns['a'], 0.5)
458 self.assertEqual(ip.user_ns['a'], 0.5)
459 ip.run_cell("b = 1/2", shell_futures=False)
459 ip.run_cell("b = 1/2", shell_futures=False)
460 self.assertEqual(ip.user_ns['b'], 0)
460 self.assertEqual(ip.user_ns['b'], 0)
461
461
462 ip.compile.reset_compiler_flags()
462 ip.compile.reset_compiler_flags()
463 # This shouldn't leak to the shell's compiler
463 # This shouldn't leak to the shell's compiler
464 ip.run_cell("from __future__ import division \nc=1/2", shell_futures=False)
464 ip.run_cell("from __future__ import division \nc=1/2", shell_futures=False)
465 self.assertEqual(ip.user_ns['c'], 0.5)
465 self.assertEqual(ip.user_ns['c'], 0.5)
466 ip.run_cell("d = 1/2", shell_futures=True)
466 ip.run_cell("d = 1/2", shell_futures=True)
467 self.assertEqual(ip.user_ns['d'], 0)
467 self.assertEqual(ip.user_ns['d'], 0)
468
468
469 def test_mktempfile(self):
469 def test_mktempfile(self):
470 filename = ip.mktempfile()
470 filename = ip.mktempfile()
471 # Check that we can open the file again on Windows
471 # Check that we can open the file again on Windows
472 with open(filename, 'w') as f:
472 with open(filename, 'w') as f:
473 f.write('abc')
473 f.write('abc')
474
474
475 filename = ip.mktempfile(data='blah')
475 filename = ip.mktempfile(data='blah')
476 with open(filename, 'r') as f:
476 with open(filename, 'r') as f:
477 self.assertEqual(f.read(), 'blah')
477 self.assertEqual(f.read(), 'blah')
478
478
479 def test_new_main_mod(self):
479 def test_new_main_mod(self):
480 # Smoketest to check that this accepts a unicode module name
480 # Smoketest to check that this accepts a unicode module name
481 name = u'jiefmw'
481 name = u'jiefmw'
482 mod = ip.new_main_mod(u'%s.py' % name, name)
482 mod = ip.new_main_mod(u'%s.py' % name, name)
483 self.assertEqual(mod.__name__, name)
483 self.assertEqual(mod.__name__, name)
484
484
485 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
485 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
486
486
487 @onlyif_unicode_paths
487 @onlyif_unicode_paths
488 def setUp(self):
488 def setUp(self):
489 self.BASETESTDIR = tempfile.mkdtemp()
489 self.BASETESTDIR = tempfile.mkdtemp()
490 self.TESTDIR = join(self.BASETESTDIR, u"åäö")
490 self.TESTDIR = join(self.BASETESTDIR, u"åäö")
491 os.mkdir(self.TESTDIR)
491 os.mkdir(self.TESTDIR)
492 with open(join(self.TESTDIR, u"åäötestscript.py"), "w") as sfile:
492 with open(join(self.TESTDIR, u"åäötestscript.py"), "w") as sfile:
493 sfile.write("pass\n")
493 sfile.write("pass\n")
494 self.oldpath = py3compat.getcwd()
494 self.oldpath = py3compat.getcwd()
495 os.chdir(self.TESTDIR)
495 os.chdir(self.TESTDIR)
496 self.fname = u"åäötestscript.py"
496 self.fname = u"åäötestscript.py"
497
497
498 def tearDown(self):
498 def tearDown(self):
499 os.chdir(self.oldpath)
499 os.chdir(self.oldpath)
500 shutil.rmtree(self.BASETESTDIR)
500 shutil.rmtree(self.BASETESTDIR)
501
501
502 @onlyif_unicode_paths
502 @onlyif_unicode_paths
503 def test_1(self):
503 def test_1(self):
504 """Test safe_execfile with non-ascii path
504 """Test safe_execfile with non-ascii path
505 """
505 """
506 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
506 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
507
507
508 class ExitCodeChecks(tt.TempFileMixin):
508 class ExitCodeChecks(tt.TempFileMixin):
509 def test_exit_code_ok(self):
509 def test_exit_code_ok(self):
510 self.system('exit 0')
510 self.system('exit 0')
511 self.assertEqual(ip.user_ns['_exit_code'], 0)
511 self.assertEqual(ip.user_ns['_exit_code'], 0)
512
512
513 def test_exit_code_error(self):
513 def test_exit_code_error(self):
514 self.system('exit 1')
514 self.system('exit 1')
515 self.assertEqual(ip.user_ns['_exit_code'], 1)
515 self.assertEqual(ip.user_ns['_exit_code'], 1)
516
516
517 @skipif(not hasattr(signal, 'SIGALRM'))
517 @skipif(not hasattr(signal, 'SIGALRM'))
518 def test_exit_code_signal(self):
518 def test_exit_code_signal(self):
519 self.mktmp("import signal, time\n"
519 self.mktmp("import signal, time\n"
520 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
520 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
521 "time.sleep(1)\n")
521 "time.sleep(1)\n")
522 self.system("%s %s" % (sys.executable, self.fname))
522 self.system("%s %s" % (sys.executable, self.fname))
523 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
523 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
524
524
525 @onlyif_cmds_exist("csh")
525 @onlyif_cmds_exist("csh")
526 def test_exit_code_signal_csh(self):
526 def test_exit_code_signal_csh(self):
527 SHELL = os.environ.get('SHELL', None)
527 SHELL = os.environ.get('SHELL', None)
528 os.environ['SHELL'] = find_cmd("csh")
528 os.environ['SHELL'] = find_cmd("csh")
529 try:
529 try:
530 self.test_exit_code_signal()
530 self.test_exit_code_signal()
531 finally:
531 finally:
532 if SHELL is not None:
532 if SHELL is not None:
533 os.environ['SHELL'] = SHELL
533 os.environ['SHELL'] = SHELL
534 else:
534 else:
535 del os.environ['SHELL']
535 del os.environ['SHELL']
536
536
537 class TestSystemRaw(unittest.TestCase, ExitCodeChecks):
537 class TestSystemRaw(unittest.TestCase, ExitCodeChecks):
538 system = ip.system_raw
538 system = ip.system_raw
539
539
540 @onlyif_unicode_paths
540 @onlyif_unicode_paths
541 def test_1(self):
541 def test_1(self):
542 """Test system_raw with non-ascii cmd
542 """Test system_raw with non-ascii cmd
543 """
543 """
544 cmd = u'''python -c "'åäö'" '''
544 cmd = u'''python -c "'åäö'" '''
545 ip.system_raw(cmd)
545 ip.system_raw(cmd)
546
546
547 @mock.patch('subprocess.call')
548 def test_control_c(self, call_mock):
549 call_mock.side_effect = KeyboardInterrupt()
550 try:
551 self.system("sleep 1 # wont happen")
552 except KeyboardInterrupt:
553 self.fail("system call should intercept "
554 "keyboard interrupt from subprocess.call")
555 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGINT)
556
547 # TODO: Exit codes are currently ignored on Windows.
557 # TODO: Exit codes are currently ignored on Windows.
548 class TestSystemPipedExitCode(unittest.TestCase, ExitCodeChecks):
558 class TestSystemPipedExitCode(unittest.TestCase, ExitCodeChecks):
549 system = ip.system_piped
559 system = ip.system_piped
550
560
551 @skip_win32
561 @skip_win32
552 def test_exit_code_ok(self):
562 def test_exit_code_ok(self):
553 ExitCodeChecks.test_exit_code_ok(self)
563 ExitCodeChecks.test_exit_code_ok(self)
554
564
555 @skip_win32
565 @skip_win32
556 def test_exit_code_error(self):
566 def test_exit_code_error(self):
557 ExitCodeChecks.test_exit_code_error(self)
567 ExitCodeChecks.test_exit_code_error(self)
558
568
559 @skip_win32
569 @skip_win32
560 def test_exit_code_signal(self):
570 def test_exit_code_signal(self):
561 ExitCodeChecks.test_exit_code_signal(self)
571 ExitCodeChecks.test_exit_code_signal(self)
562
572
563 class TestModules(unittest.TestCase, tt.TempFileMixin):
573 class TestModules(unittest.TestCase, tt.TempFileMixin):
564 def test_extraneous_loads(self):
574 def test_extraneous_loads(self):
565 """Test we're not loading modules on startup that we shouldn't.
575 """Test we're not loading modules on startup that we shouldn't.
566 """
576 """
567 self.mktmp("import sys\n"
577 self.mktmp("import sys\n"
568 "print('numpy' in sys.modules)\n"
578 "print('numpy' in sys.modules)\n"
569 "print('IPython.parallel' in sys.modules)\n"
579 "print('IPython.parallel' in sys.modules)\n"
570 "print('IPython.kernel.zmq' in sys.modules)\n"
580 "print('IPython.kernel.zmq' in sys.modules)\n"
571 )
581 )
572 out = "False\nFalse\nFalse\n"
582 out = "False\nFalse\nFalse\n"
573 tt.ipexec_validate(self.fname, out)
583 tt.ipexec_validate(self.fname, out)
574
584
575 class Negator(ast.NodeTransformer):
585 class Negator(ast.NodeTransformer):
576 """Negates all number literals in an AST."""
586 """Negates all number literals in an AST."""
577 def visit_Num(self, node):
587 def visit_Num(self, node):
578 node.n = -node.n
588 node.n = -node.n
579 return node
589 return node
580
590
581 class TestAstTransform(unittest.TestCase):
591 class TestAstTransform(unittest.TestCase):
582 def setUp(self):
592 def setUp(self):
583 self.negator = Negator()
593 self.negator = Negator()
584 ip.ast_transformers.append(self.negator)
594 ip.ast_transformers.append(self.negator)
585
595
586 def tearDown(self):
596 def tearDown(self):
587 ip.ast_transformers.remove(self.negator)
597 ip.ast_transformers.remove(self.negator)
588
598
589 def test_run_cell(self):
599 def test_run_cell(self):
590 with tt.AssertPrints('-34'):
600 with tt.AssertPrints('-34'):
591 ip.run_cell('print (12 + 22)')
601 ip.run_cell('print (12 + 22)')
592
602
593 # A named reference to a number shouldn't be transformed.
603 # A named reference to a number shouldn't be transformed.
594 ip.user_ns['n'] = 55
604 ip.user_ns['n'] = 55
595 with tt.AssertNotPrints('-55'):
605 with tt.AssertNotPrints('-55'):
596 ip.run_cell('print (n)')
606 ip.run_cell('print (n)')
597
607
598 def test_timeit(self):
608 def test_timeit(self):
599 called = set()
609 called = set()
600 def f(x):
610 def f(x):
601 called.add(x)
611 called.add(x)
602 ip.push({'f':f})
612 ip.push({'f':f})
603
613
604 with tt.AssertPrints("best of "):
614 with tt.AssertPrints("best of "):
605 ip.run_line_magic("timeit", "-n1 f(1)")
615 ip.run_line_magic("timeit", "-n1 f(1)")
606 self.assertEqual(called, set([-1]))
616 self.assertEqual(called, set([-1]))
607 called.clear()
617 called.clear()
608
618
609 with tt.AssertPrints("best of "):
619 with tt.AssertPrints("best of "):
610 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
620 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
611 self.assertEqual(called, set([-2, -3]))
621 self.assertEqual(called, set([-2, -3]))
612
622
613 def test_time(self):
623 def test_time(self):
614 called = []
624 called = []
615 def f(x):
625 def f(x):
616 called.append(x)
626 called.append(x)
617 ip.push({'f':f})
627 ip.push({'f':f})
618
628
619 # Test with an expression
629 # Test with an expression
620 with tt.AssertPrints("Wall time: "):
630 with tt.AssertPrints("Wall time: "):
621 ip.run_line_magic("time", "f(5+9)")
631 ip.run_line_magic("time", "f(5+9)")
622 self.assertEqual(called, [-14])
632 self.assertEqual(called, [-14])
623 called[:] = []
633 called[:] = []
624
634
625 # Test with a statement (different code path)
635 # Test with a statement (different code path)
626 with tt.AssertPrints("Wall time: "):
636 with tt.AssertPrints("Wall time: "):
627 ip.run_line_magic("time", "a = f(-3 + -2)")
637 ip.run_line_magic("time", "a = f(-3 + -2)")
628 self.assertEqual(called, [5])
638 self.assertEqual(called, [5])
629
639
630 def test_macro(self):
640 def test_macro(self):
631 ip.push({'a':10})
641 ip.push({'a':10})
632 # The AST transformation makes this do a+=-1
642 # The AST transformation makes this do a+=-1
633 ip.define_macro("amacro", "a+=1\nprint(a)")
643 ip.define_macro("amacro", "a+=1\nprint(a)")
634
644
635 with tt.AssertPrints("9"):
645 with tt.AssertPrints("9"):
636 ip.run_cell("amacro")
646 ip.run_cell("amacro")
637 with tt.AssertPrints("8"):
647 with tt.AssertPrints("8"):
638 ip.run_cell("amacro")
648 ip.run_cell("amacro")
639
649
640 class IntegerWrapper(ast.NodeTransformer):
650 class IntegerWrapper(ast.NodeTransformer):
641 """Wraps all integers in a call to Integer()"""
651 """Wraps all integers in a call to Integer()"""
642 def visit_Num(self, node):
652 def visit_Num(self, node):
643 if isinstance(node.n, int):
653 if isinstance(node.n, int):
644 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
654 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
645 args=[node], keywords=[])
655 args=[node], keywords=[])
646 return node
656 return node
647
657
648 class TestAstTransform2(unittest.TestCase):
658 class TestAstTransform2(unittest.TestCase):
649 def setUp(self):
659 def setUp(self):
650 self.intwrapper = IntegerWrapper()
660 self.intwrapper = IntegerWrapper()
651 ip.ast_transformers.append(self.intwrapper)
661 ip.ast_transformers.append(self.intwrapper)
652
662
653 self.calls = []
663 self.calls = []
654 def Integer(*args):
664 def Integer(*args):
655 self.calls.append(args)
665 self.calls.append(args)
656 return args
666 return args
657 ip.push({"Integer": Integer})
667 ip.push({"Integer": Integer})
658
668
659 def tearDown(self):
669 def tearDown(self):
660 ip.ast_transformers.remove(self.intwrapper)
670 ip.ast_transformers.remove(self.intwrapper)
661 del ip.user_ns['Integer']
671 del ip.user_ns['Integer']
662
672
663 def test_run_cell(self):
673 def test_run_cell(self):
664 ip.run_cell("n = 2")
674 ip.run_cell("n = 2")
665 self.assertEqual(self.calls, [(2,)])
675 self.assertEqual(self.calls, [(2,)])
666
676
667 # This shouldn't throw an error
677 # This shouldn't throw an error
668 ip.run_cell("o = 2.0")
678 ip.run_cell("o = 2.0")
669 self.assertEqual(ip.user_ns['o'], 2.0)
679 self.assertEqual(ip.user_ns['o'], 2.0)
670
680
671 def test_timeit(self):
681 def test_timeit(self):
672 called = set()
682 called = set()
673 def f(x):
683 def f(x):
674 called.add(x)
684 called.add(x)
675 ip.push({'f':f})
685 ip.push({'f':f})
676
686
677 with tt.AssertPrints("best of "):
687 with tt.AssertPrints("best of "):
678 ip.run_line_magic("timeit", "-n1 f(1)")
688 ip.run_line_magic("timeit", "-n1 f(1)")
679 self.assertEqual(called, set([(1,)]))
689 self.assertEqual(called, set([(1,)]))
680 called.clear()
690 called.clear()
681
691
682 with tt.AssertPrints("best of "):
692 with tt.AssertPrints("best of "):
683 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
693 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
684 self.assertEqual(called, set([(2,), (3,)]))
694 self.assertEqual(called, set([(2,), (3,)]))
685
695
686 class ErrorTransformer(ast.NodeTransformer):
696 class ErrorTransformer(ast.NodeTransformer):
687 """Throws an error when it sees a number."""
697 """Throws an error when it sees a number."""
688 def visit_Num(self, node):
698 def visit_Num(self, node):
689 raise ValueError("test")
699 raise ValueError("test")
690
700
691 class TestAstTransformError(unittest.TestCase):
701 class TestAstTransformError(unittest.TestCase):
692 def test_unregistering(self):
702 def test_unregistering(self):
693 err_transformer = ErrorTransformer()
703 err_transformer = ErrorTransformer()
694 ip.ast_transformers.append(err_transformer)
704 ip.ast_transformers.append(err_transformer)
695
705
696 with tt.AssertPrints("unregister", channel='stderr'):
706 with tt.AssertPrints("unregister", channel='stderr'):
697 ip.run_cell("1 + 2")
707 ip.run_cell("1 + 2")
698
708
699 # This should have been removed.
709 # This should have been removed.
700 nt.assert_not_in(err_transformer, ip.ast_transformers)
710 nt.assert_not_in(err_transformer, ip.ast_transformers)
701
711
702
712
703 class StringRejector(ast.NodeTransformer):
713 class StringRejector(ast.NodeTransformer):
704 """Throws an InputRejected when it sees a string literal.
714 """Throws an InputRejected when it sees a string literal.
705
715
706 Used to verify that NodeTransformers can signal that a piece of code should
716 Used to verify that NodeTransformers can signal that a piece of code should
707 not be executed by throwing an InputRejected.
717 not be executed by throwing an InputRejected.
708 """
718 """
709
719
710 def visit_Str(self, node):
720 def visit_Str(self, node):
711 raise InputRejected("test")
721 raise InputRejected("test")
712
722
713
723
714 class TestAstTransformInputRejection(unittest.TestCase):
724 class TestAstTransformInputRejection(unittest.TestCase):
715
725
716 def setUp(self):
726 def setUp(self):
717 self.transformer = StringRejector()
727 self.transformer = StringRejector()
718 ip.ast_transformers.append(self.transformer)
728 ip.ast_transformers.append(self.transformer)
719
729
720 def tearDown(self):
730 def tearDown(self):
721 ip.ast_transformers.remove(self.transformer)
731 ip.ast_transformers.remove(self.transformer)
722
732
723 def test_input_rejection(self):
733 def test_input_rejection(self):
724 """Check that NodeTransformers can reject input."""
734 """Check that NodeTransformers can reject input."""
725
735
726 expect_exception_tb = tt.AssertPrints("InputRejected: test")
736 expect_exception_tb = tt.AssertPrints("InputRejected: test")
727 expect_no_cell_output = tt.AssertNotPrints("'unsafe'", suppress=False)
737 expect_no_cell_output = tt.AssertNotPrints("'unsafe'", suppress=False)
728
738
729 # Run the same check twice to verify that the transformer is not
739 # Run the same check twice to verify that the transformer is not
730 # disabled after raising.
740 # disabled after raising.
731 with expect_exception_tb, expect_no_cell_output:
741 with expect_exception_tb, expect_no_cell_output:
732 ip.run_cell("'unsafe'")
742 ip.run_cell("'unsafe'")
733
743
734 with expect_exception_tb, expect_no_cell_output:
744 with expect_exception_tb, expect_no_cell_output:
735 ip.run_cell("'unsafe'")
745 ip.run_cell("'unsafe'")
736
746
737 def test__IPYTHON__():
747 def test__IPYTHON__():
738 # This shouldn't raise a NameError, that's all
748 # This shouldn't raise a NameError, that's all
739 __IPYTHON__
749 __IPYTHON__
740
750
741
751
742 class DummyRepr(object):
752 class DummyRepr(object):
743 def __repr__(self):
753 def __repr__(self):
744 return "DummyRepr"
754 return "DummyRepr"
745
755
746 def _repr_html_(self):
756 def _repr_html_(self):
747 return "<b>dummy</b>"
757 return "<b>dummy</b>"
748
758
749 def _repr_javascript_(self):
759 def _repr_javascript_(self):
750 return "console.log('hi');", {'key': 'value'}
760 return "console.log('hi');", {'key': 'value'}
751
761
752
762
753 def test_user_variables():
763 def test_user_variables():
754 # enable all formatters
764 # enable all formatters
755 ip.display_formatter.active_types = ip.display_formatter.format_types
765 ip.display_formatter.active_types = ip.display_formatter.format_types
756
766
757 ip.user_ns['dummy'] = d = DummyRepr()
767 ip.user_ns['dummy'] = d = DummyRepr()
758 keys = set(['dummy', 'doesnotexist'])
768 keys = set(['dummy', 'doesnotexist'])
759 r = ip.user_expressions({ key:key for key in keys})
769 r = ip.user_expressions({ key:key for key in keys})
760
770
761 nt.assert_equal(keys, set(r.keys()))
771 nt.assert_equal(keys, set(r.keys()))
762 dummy = r['dummy']
772 dummy = r['dummy']
763 nt.assert_equal(set(['status', 'data', 'metadata']), set(dummy.keys()))
773 nt.assert_equal(set(['status', 'data', 'metadata']), set(dummy.keys()))
764 nt.assert_equal(dummy['status'], 'ok')
774 nt.assert_equal(dummy['status'], 'ok')
765 data = dummy['data']
775 data = dummy['data']
766 metadata = dummy['metadata']
776 metadata = dummy['metadata']
767 nt.assert_equal(data.get('text/html'), d._repr_html_())
777 nt.assert_equal(data.get('text/html'), d._repr_html_())
768 js, jsmd = d._repr_javascript_()
778 js, jsmd = d._repr_javascript_()
769 nt.assert_equal(data.get('application/javascript'), js)
779 nt.assert_equal(data.get('application/javascript'), js)
770 nt.assert_equal(metadata.get('application/javascript'), jsmd)
780 nt.assert_equal(metadata.get('application/javascript'), jsmd)
771
781
772 dne = r['doesnotexist']
782 dne = r['doesnotexist']
773 nt.assert_equal(dne['status'], 'error')
783 nt.assert_equal(dne['status'], 'error')
774 nt.assert_equal(dne['ename'], 'NameError')
784 nt.assert_equal(dne['ename'], 'NameError')
775
785
776 # back to text only
786 # back to text only
777 ip.display_formatter.active_types = ['text/plain']
787 ip.display_formatter.active_types = ['text/plain']
778
788
779 def test_user_expression():
789 def test_user_expression():
780 # enable all formatters
790 # enable all formatters
781 ip.display_formatter.active_types = ip.display_formatter.format_types
791 ip.display_formatter.active_types = ip.display_formatter.format_types
782 query = {
792 query = {
783 'a' : '1 + 2',
793 'a' : '1 + 2',
784 'b' : '1/0',
794 'b' : '1/0',
785 }
795 }
786 r = ip.user_expressions(query)
796 r = ip.user_expressions(query)
787 import pprint
797 import pprint
788 pprint.pprint(r)
798 pprint.pprint(r)
789 nt.assert_equal(set(r.keys()), set(query.keys()))
799 nt.assert_equal(set(r.keys()), set(query.keys()))
790 a = r['a']
800 a = r['a']
791 nt.assert_equal(set(['status', 'data', 'metadata']), set(a.keys()))
801 nt.assert_equal(set(['status', 'data', 'metadata']), set(a.keys()))
792 nt.assert_equal(a['status'], 'ok')
802 nt.assert_equal(a['status'], 'ok')
793 data = a['data']
803 data = a['data']
794 metadata = a['metadata']
804 metadata = a['metadata']
795 nt.assert_equal(data.get('text/plain'), '3')
805 nt.assert_equal(data.get('text/plain'), '3')
796
806
797 b = r['b']
807 b = r['b']
798 nt.assert_equal(b['status'], 'error')
808 nt.assert_equal(b['status'], 'error')
799 nt.assert_equal(b['ename'], 'ZeroDivisionError')
809 nt.assert_equal(b['ename'], 'ZeroDivisionError')
800
810
801 # back to text only
811 # back to text only
802 ip.display_formatter.active_types = ['text/plain']
812 ip.display_formatter.active_types = ['text/plain']
803
813
804
814
805
815
806
816
807
817
808 class TestSyntaxErrorTransformer(unittest.TestCase):
818 class TestSyntaxErrorTransformer(unittest.TestCase):
809 """Check that SyntaxError raised by an input transformer is handled by run_cell()"""
819 """Check that SyntaxError raised by an input transformer is handled by run_cell()"""
810
820
811 class SyntaxErrorTransformer(InputTransformer):
821 class SyntaxErrorTransformer(InputTransformer):
812
822
813 def push(self, line):
823 def push(self, line):
814 pos = line.find('syntaxerror')
824 pos = line.find('syntaxerror')
815 if pos >= 0:
825 if pos >= 0:
816 e = SyntaxError('input contains "syntaxerror"')
826 e = SyntaxError('input contains "syntaxerror"')
817 e.text = line
827 e.text = line
818 e.offset = pos + 1
828 e.offset = pos + 1
819 raise e
829 raise e
820 return line
830 return line
821
831
822 def reset(self):
832 def reset(self):
823 pass
833 pass
824
834
825 def setUp(self):
835 def setUp(self):
826 self.transformer = TestSyntaxErrorTransformer.SyntaxErrorTransformer()
836 self.transformer = TestSyntaxErrorTransformer.SyntaxErrorTransformer()
827 ip.input_splitter.python_line_transforms.append(self.transformer)
837 ip.input_splitter.python_line_transforms.append(self.transformer)
828 ip.input_transformer_manager.python_line_transforms.append(self.transformer)
838 ip.input_transformer_manager.python_line_transforms.append(self.transformer)
829
839
830 def tearDown(self):
840 def tearDown(self):
831 ip.input_splitter.python_line_transforms.remove(self.transformer)
841 ip.input_splitter.python_line_transforms.remove(self.transformer)
832 ip.input_transformer_manager.python_line_transforms.remove(self.transformer)
842 ip.input_transformer_manager.python_line_transforms.remove(self.transformer)
833
843
834 def test_syntaxerror_input_transformer(self):
844 def test_syntaxerror_input_transformer(self):
835 with tt.AssertPrints('1234'):
845 with tt.AssertPrints('1234'):
836 ip.run_cell('1234')
846 ip.run_cell('1234')
837 with tt.AssertPrints('SyntaxError: invalid syntax'):
847 with tt.AssertPrints('SyntaxError: invalid syntax'):
838 ip.run_cell('1 2 3') # plain python syntax error
848 ip.run_cell('1 2 3') # plain python syntax error
839 with tt.AssertPrints('SyntaxError: input contains "syntaxerror"'):
849 with tt.AssertPrints('SyntaxError: input contains "syntaxerror"'):
840 ip.run_cell('2345 # syntaxerror') # input transformer syntax error
850 ip.run_cell('2345 # syntaxerror') # input transformer syntax error
841 with tt.AssertPrints('3456'):
851 with tt.AssertPrints('3456'):
842 ip.run_cell('3456')
852 ip.run_cell('3456')
843
853
844
854
845
855
846 def test_warning_suppression():
856 def test_warning_suppression():
847 ip.run_cell("import warnings")
857 ip.run_cell("import warnings")
848 try:
858 try:
849 with tt.AssertPrints("UserWarning: asdf", channel="stderr"):
859 with tt.AssertPrints("UserWarning: asdf", channel="stderr"):
850 ip.run_cell("warnings.warn('asdf')")
860 ip.run_cell("warnings.warn('asdf')")
851 # Here's the real test -- if we run that again, we should get the
861 # Here's the real test -- if we run that again, we should get the
852 # warning again. Traditionally, each warning was only issued once per
862 # warning again. Traditionally, each warning was only issued once per
853 # IPython session (approximately), even if the user typed in new and
863 # IPython session (approximately), even if the user typed in new and
854 # different code that should have also triggered the warning, leading
864 # different code that should have also triggered the warning, leading
855 # to much confusion.
865 # to much confusion.
856 with tt.AssertPrints("UserWarning: asdf", channel="stderr"):
866 with tt.AssertPrints("UserWarning: asdf", channel="stderr"):
857 ip.run_cell("warnings.warn('asdf')")
867 ip.run_cell("warnings.warn('asdf')")
858 finally:
868 finally:
859 ip.run_cell("del warnings")
869 ip.run_cell("del warnings")
General Comments 0
You need to be logged in to leave comments. Login now