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