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