##// END OF EJS Templates
Merge pull request #11005 from ipython/auto-backport-of-pr-10993...
Thomas Kluyver -
r24142:5b6fe626 merge
parent child Browse files
Show More

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

1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,950 +1,961 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):
437 def test_custom_syntaxerror_exception(self):
438 called = []
438 called = []
439 def my_handler(shell, etype, value, tb, tb_offset=None):
439 def my_handler(shell, etype, value, tb, tb_offset=None):
440 called.append(etype)
440 called.append(etype)
441 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
441 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
442
442
443 ip.set_custom_exc((SyntaxError,), my_handler)
443 ip.set_custom_exc((SyntaxError,), my_handler)
444 try:
444 try:
445 ip.run_cell("1f")
445 ip.run_cell("1f")
446 # Check that this was called, and only once.
446 # Check that this was called, and only once.
447 self.assertEqual(called, [SyntaxError])
447 self.assertEqual(called, [SyntaxError])
448 finally:
448 finally:
449 # Reset the custom exception hook
449 # Reset the custom exception hook
450 ip.set_custom_exc((), None)
450 ip.set_custom_exc((), None)
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 def test_inspect_text(self):
517 def test_inspect_text(self):
518 ip.run_cell('a = 5')
518 ip.run_cell('a = 5')
519 text = ip.object_inspect_text('a')
519 text = ip.object_inspect_text('a')
520 self.assertIsInstance(text, unicode_type)
520 self.assertIsInstance(text, unicode_type)
521
521
522
522
523 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
523 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
524
524
525 @onlyif_unicode_paths
525 @onlyif_unicode_paths
526 def setUp(self):
526 def setUp(self):
527 self.BASETESTDIR = tempfile.mkdtemp()
527 self.BASETESTDIR = tempfile.mkdtemp()
528 self.TESTDIR = join(self.BASETESTDIR, u"åäö")
528 self.TESTDIR = join(self.BASETESTDIR, u"åäö")
529 os.mkdir(self.TESTDIR)
529 os.mkdir(self.TESTDIR)
530 with open(join(self.TESTDIR, u"åäötestscript.py"), "w") as sfile:
530 with open(join(self.TESTDIR, u"åäötestscript.py"), "w") as sfile:
531 sfile.write("pass\n")
531 sfile.write("pass\n")
532 self.oldpath = py3compat.getcwd()
532 self.oldpath = py3compat.getcwd()
533 os.chdir(self.TESTDIR)
533 os.chdir(self.TESTDIR)
534 self.fname = u"åäötestscript.py"
534 self.fname = u"åäötestscript.py"
535
535
536 def tearDown(self):
536 def tearDown(self):
537 os.chdir(self.oldpath)
537 os.chdir(self.oldpath)
538 shutil.rmtree(self.BASETESTDIR)
538 shutil.rmtree(self.BASETESTDIR)
539
539
540 @onlyif_unicode_paths
540 @onlyif_unicode_paths
541 def test_1(self):
541 def test_1(self):
542 """Test safe_execfile with non-ascii path
542 """Test safe_execfile with non-ascii path
543 """
543 """
544 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
544 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
545
545
546 class ExitCodeChecks(tt.TempFileMixin):
546 class ExitCodeChecks(tt.TempFileMixin):
547 def test_exit_code_ok(self):
547 def test_exit_code_ok(self):
548 self.system('exit 0')
548 self.system('exit 0')
549 self.assertEqual(ip.user_ns['_exit_code'], 0)
549 self.assertEqual(ip.user_ns['_exit_code'], 0)
550
550
551 def test_exit_code_error(self):
551 def test_exit_code_error(self):
552 self.system('exit 1')
552 self.system('exit 1')
553 self.assertEqual(ip.user_ns['_exit_code'], 1)
553 self.assertEqual(ip.user_ns['_exit_code'], 1)
554
554
555 @skipif(not hasattr(signal, 'SIGALRM'))
555 @skipif(not hasattr(signal, 'SIGALRM'))
556 def test_exit_code_signal(self):
556 def test_exit_code_signal(self):
557 self.mktmp("import signal, time\n"
557 self.mktmp("import signal, time\n"
558 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
558 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
559 "time.sleep(1)\n")
559 "time.sleep(1)\n")
560 self.system("%s %s" % (sys.executable, self.fname))
560 self.system("%s %s" % (sys.executable, self.fname))
561 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
561 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
562
562
563 @onlyif_cmds_exist("csh")
563 @onlyif_cmds_exist("csh")
564 def test_exit_code_signal_csh(self):
564 def test_exit_code_signal_csh(self):
565 SHELL = os.environ.get('SHELL', None)
565 SHELL = os.environ.get('SHELL', None)
566 os.environ['SHELL'] = find_cmd("csh")
566 os.environ['SHELL'] = find_cmd("csh")
567 try:
567 try:
568 self.test_exit_code_signal()
568 self.test_exit_code_signal()
569 finally:
569 finally:
570 if SHELL is not None:
570 if SHELL is not None:
571 os.environ['SHELL'] = SHELL
571 os.environ['SHELL'] = SHELL
572 else:
572 else:
573 del os.environ['SHELL']
573 del os.environ['SHELL']
574
574
575 class TestSystemRaw(unittest.TestCase, ExitCodeChecks):
575 class TestSystemRaw(unittest.TestCase, ExitCodeChecks):
576 system = ip.system_raw
576 system = ip.system_raw
577
577
578 @onlyif_unicode_paths
578 @onlyif_unicode_paths
579 def test_1(self):
579 def test_1(self):
580 """Test system_raw with non-ascii cmd
580 """Test system_raw with non-ascii cmd
581 """
581 """
582 cmd = u'''python -c "'åäö'" '''
582 cmd = u'''python -c "'åäö'" '''
583 ip.system_raw(cmd)
583 ip.system_raw(cmd)
584
584
585 @mock.patch('subprocess.call', side_effect=KeyboardInterrupt)
585 @mock.patch('subprocess.call', side_effect=KeyboardInterrupt)
586 @mock.patch('os.system', side_effect=KeyboardInterrupt)
586 @mock.patch('os.system', side_effect=KeyboardInterrupt)
587 def test_control_c(self, *mocks):
587 def test_control_c(self, *mocks):
588 try:
588 try:
589 self.system("sleep 1 # wont happen")
589 self.system("sleep 1 # wont happen")
590 except KeyboardInterrupt:
590 except KeyboardInterrupt:
591 self.fail("system call should intercept "
591 self.fail("system call should intercept "
592 "keyboard interrupt from subprocess.call")
592 "keyboard interrupt from subprocess.call")
593 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGINT)
593 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGINT)
594
594
595 # TODO: Exit codes are currently ignored on Windows.
595 # TODO: Exit codes are currently ignored on Windows.
596 class TestSystemPipedExitCode(unittest.TestCase, ExitCodeChecks):
596 class TestSystemPipedExitCode(unittest.TestCase, ExitCodeChecks):
597 system = ip.system_piped
597 system = ip.system_piped
598
598
599 @skip_win32
599 @skip_win32
600 def test_exit_code_ok(self):
600 def test_exit_code_ok(self):
601 ExitCodeChecks.test_exit_code_ok(self)
601 ExitCodeChecks.test_exit_code_ok(self)
602
602
603 @skip_win32
603 @skip_win32
604 def test_exit_code_error(self):
604 def test_exit_code_error(self):
605 ExitCodeChecks.test_exit_code_error(self)
605 ExitCodeChecks.test_exit_code_error(self)
606
606
607 @skip_win32
607 @skip_win32
608 def test_exit_code_signal(self):
608 def test_exit_code_signal(self):
609 ExitCodeChecks.test_exit_code_signal(self)
609 ExitCodeChecks.test_exit_code_signal(self)
610
610
611 class TestModules(unittest.TestCase, tt.TempFileMixin):
611 class TestModules(unittest.TestCase, tt.TempFileMixin):
612 def test_extraneous_loads(self):
612 def test_extraneous_loads(self):
613 """Test we're not loading modules on startup that we shouldn't.
613 """Test we're not loading modules on startup that we shouldn't.
614 """
614 """
615 self.mktmp("import sys\n"
615 self.mktmp("import sys\n"
616 "print('numpy' in sys.modules)\n"
616 "print('numpy' in sys.modules)\n"
617 "print('ipyparallel' in sys.modules)\n"
617 "print('ipyparallel' in sys.modules)\n"
618 "print('ipykernel' in sys.modules)\n"
618 "print('ipykernel' in sys.modules)\n"
619 )
619 )
620 out = "False\nFalse\nFalse\n"
620 out = "False\nFalse\nFalse\n"
621 tt.ipexec_validate(self.fname, out)
621 tt.ipexec_validate(self.fname, out)
622
622
623 class Negator(ast.NodeTransformer):
623 class Negator(ast.NodeTransformer):
624 """Negates all number literals in an AST."""
624 """Negates all number literals in an AST."""
625 def visit_Num(self, node):
625 def visit_Num(self, node):
626 node.n = -node.n
626 node.n = -node.n
627 return node
627 return node
628
628
629 class TestAstTransform(unittest.TestCase):
629 class TestAstTransform(unittest.TestCase):
630 def setUp(self):
630 def setUp(self):
631 self.negator = Negator()
631 self.negator = Negator()
632 ip.ast_transformers.append(self.negator)
632 ip.ast_transformers.append(self.negator)
633
633
634 def tearDown(self):
634 def tearDown(self):
635 ip.ast_transformers.remove(self.negator)
635 ip.ast_transformers.remove(self.negator)
636
636
637 def test_run_cell(self):
637 def test_run_cell(self):
638 with tt.AssertPrints('-34'):
638 with tt.AssertPrints('-34'):
639 ip.run_cell('print (12 + 22)')
639 ip.run_cell('print (12 + 22)')
640
640
641 # A named reference to a number shouldn't be transformed.
641 # A named reference to a number shouldn't be transformed.
642 ip.user_ns['n'] = 55
642 ip.user_ns['n'] = 55
643 with tt.AssertNotPrints('-55'):
643 with tt.AssertNotPrints('-55'):
644 ip.run_cell('print (n)')
644 ip.run_cell('print (n)')
645
645
646 def test_timeit(self):
646 def test_timeit(self):
647 called = set()
647 called = set()
648 def f(x):
648 def f(x):
649 called.add(x)
649 called.add(x)
650 ip.push({'f':f})
650 ip.push({'f':f})
651
651
652 with tt.AssertPrints("best of "):
652 with tt.AssertPrints("best of "):
653 ip.run_line_magic("timeit", "-n1 f(1)")
653 ip.run_line_magic("timeit", "-n1 f(1)")
654 self.assertEqual(called, {-1})
654 self.assertEqual(called, {-1})
655 called.clear()
655 called.clear()
656
656
657 with tt.AssertPrints("best of "):
657 with tt.AssertPrints("best of "):
658 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
658 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
659 self.assertEqual(called, {-2, -3})
659 self.assertEqual(called, {-2, -3})
660
660
661 def test_time(self):
661 def test_time(self):
662 called = []
662 called = []
663 def f(x):
663 def f(x):
664 called.append(x)
664 called.append(x)
665 ip.push({'f':f})
665 ip.push({'f':f})
666
666
667 # Test with an expression
667 # Test with an expression
668 with tt.AssertPrints("Wall time: "):
668 with tt.AssertPrints("Wall time: "):
669 ip.run_line_magic("time", "f(5+9)")
669 ip.run_line_magic("time", "f(5+9)")
670 self.assertEqual(called, [-14])
670 self.assertEqual(called, [-14])
671 called[:] = []
671 called[:] = []
672
672
673 # Test with a statement (different code path)
673 # Test with a statement (different code path)
674 with tt.AssertPrints("Wall time: "):
674 with tt.AssertPrints("Wall time: "):
675 ip.run_line_magic("time", "a = f(-3 + -2)")
675 ip.run_line_magic("time", "a = f(-3 + -2)")
676 self.assertEqual(called, [5])
676 self.assertEqual(called, [5])
677
677
678 def test_macro(self):
678 def test_macro(self):
679 ip.push({'a':10})
679 ip.push({'a':10})
680 # The AST transformation makes this do a+=-1
680 # The AST transformation makes this do a+=-1
681 ip.define_macro("amacro", "a+=1\nprint(a)")
681 ip.define_macro("amacro", "a+=1\nprint(a)")
682
682
683 with tt.AssertPrints("9"):
683 with tt.AssertPrints("9"):
684 ip.run_cell("amacro")
684 ip.run_cell("amacro")
685 with tt.AssertPrints("8"):
685 with tt.AssertPrints("8"):
686 ip.run_cell("amacro")
686 ip.run_cell("amacro")
687
687
688 class IntegerWrapper(ast.NodeTransformer):
688 class IntegerWrapper(ast.NodeTransformer):
689 """Wraps all integers in a call to Integer()"""
689 """Wraps all integers in a call to Integer()"""
690 def visit_Num(self, node):
690 def visit_Num(self, node):
691 if isinstance(node.n, int):
691 if isinstance(node.n, int):
692 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
692 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
693 args=[node], keywords=[])
693 args=[node], keywords=[])
694 return node
694 return node
695
695
696 class TestAstTransform2(unittest.TestCase):
696 class TestAstTransform2(unittest.TestCase):
697 def setUp(self):
697 def setUp(self):
698 self.intwrapper = IntegerWrapper()
698 self.intwrapper = IntegerWrapper()
699 ip.ast_transformers.append(self.intwrapper)
699 ip.ast_transformers.append(self.intwrapper)
700
700
701 self.calls = []
701 self.calls = []
702 def Integer(*args):
702 def Integer(*args):
703 self.calls.append(args)
703 self.calls.append(args)
704 return args
704 return args
705 ip.push({"Integer": Integer})
705 ip.push({"Integer": Integer})
706
706
707 def tearDown(self):
707 def tearDown(self):
708 ip.ast_transformers.remove(self.intwrapper)
708 ip.ast_transformers.remove(self.intwrapper)
709 del ip.user_ns['Integer']
709 del ip.user_ns['Integer']
710
710
711 def test_run_cell(self):
711 def test_run_cell(self):
712 ip.run_cell("n = 2")
712 ip.run_cell("n = 2")
713 self.assertEqual(self.calls, [(2,)])
713 self.assertEqual(self.calls, [(2,)])
714
714
715 # This shouldn't throw an error
715 # This shouldn't throw an error
716 ip.run_cell("o = 2.0")
716 ip.run_cell("o = 2.0")
717 self.assertEqual(ip.user_ns['o'], 2.0)
717 self.assertEqual(ip.user_ns['o'], 2.0)
718
718
719 def test_timeit(self):
719 def test_timeit(self):
720 called = set()
720 called = set()
721 def f(x):
721 def f(x):
722 called.add(x)
722 called.add(x)
723 ip.push({'f':f})
723 ip.push({'f':f})
724
724
725 with tt.AssertPrints("best of "):
725 with tt.AssertPrints("best of "):
726 ip.run_line_magic("timeit", "-n1 f(1)")
726 ip.run_line_magic("timeit", "-n1 f(1)")
727 self.assertEqual(called, {(1,)})
727 self.assertEqual(called, {(1,)})
728 called.clear()
728 called.clear()
729
729
730 with tt.AssertPrints("best of "):
730 with tt.AssertPrints("best of "):
731 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
731 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
732 self.assertEqual(called, {(2,), (3,)})
732 self.assertEqual(called, {(2,), (3,)})
733
733
734 class ErrorTransformer(ast.NodeTransformer):
734 class ErrorTransformer(ast.NodeTransformer):
735 """Throws an error when it sees a number."""
735 """Throws an error when it sees a number."""
736 def visit_Num(self, node):
736 def visit_Num(self, node):
737 raise ValueError("test")
737 raise ValueError("test")
738
738
739 class TestAstTransformError(unittest.TestCase):
739 class TestAstTransformError(unittest.TestCase):
740 def test_unregistering(self):
740 def test_unregistering(self):
741 err_transformer = ErrorTransformer()
741 err_transformer = ErrorTransformer()
742 ip.ast_transformers.append(err_transformer)
742 ip.ast_transformers.append(err_transformer)
743
743
744 with tt.AssertPrints("unregister", channel='stderr'):
744 with tt.AssertPrints("unregister", channel='stderr'):
745 ip.run_cell("1 + 2")
745 ip.run_cell("1 + 2")
746
746
747 # This should have been removed.
747 # This should have been removed.
748 nt.assert_not_in(err_transformer, ip.ast_transformers)
748 nt.assert_not_in(err_transformer, ip.ast_transformers)
749
749
750
750
751 class StringRejector(ast.NodeTransformer):
751 class StringRejector(ast.NodeTransformer):
752 """Throws an InputRejected when it sees a string literal.
752 """Throws an InputRejected when it sees a string literal.
753
753
754 Used to verify that NodeTransformers can signal that a piece of code should
754 Used to verify that NodeTransformers can signal that a piece of code should
755 not be executed by throwing an InputRejected.
755 not be executed by throwing an InputRejected.
756 """
756 """
757
757
758 def visit_Str(self, node):
758 def visit_Str(self, node):
759 raise InputRejected("test")
759 raise InputRejected("test")
760
760
761
761
762 class TestAstTransformInputRejection(unittest.TestCase):
762 class TestAstTransformInputRejection(unittest.TestCase):
763
763
764 def setUp(self):
764 def setUp(self):
765 self.transformer = StringRejector()
765 self.transformer = StringRejector()
766 ip.ast_transformers.append(self.transformer)
766 ip.ast_transformers.append(self.transformer)
767
767
768 def tearDown(self):
768 def tearDown(self):
769 ip.ast_transformers.remove(self.transformer)
769 ip.ast_transformers.remove(self.transformer)
770
770
771 def test_input_rejection(self):
771 def test_input_rejection(self):
772 """Check that NodeTransformers can reject input."""
772 """Check that NodeTransformers can reject input."""
773
773
774 expect_exception_tb = tt.AssertPrints("InputRejected: test")
774 expect_exception_tb = tt.AssertPrints("InputRejected: test")
775 expect_no_cell_output = tt.AssertNotPrints("'unsafe'", suppress=False)
775 expect_no_cell_output = tt.AssertNotPrints("'unsafe'", suppress=False)
776
776
777 # Run the same check twice to verify that the transformer is not
777 # Run the same check twice to verify that the transformer is not
778 # disabled after raising.
778 # disabled after raising.
779 with expect_exception_tb, expect_no_cell_output:
779 with expect_exception_tb, expect_no_cell_output:
780 ip.run_cell("'unsafe'")
780 ip.run_cell("'unsafe'")
781
781
782 with expect_exception_tb, expect_no_cell_output:
782 with expect_exception_tb, expect_no_cell_output:
783 res = ip.run_cell("'unsafe'")
783 res = ip.run_cell("'unsafe'")
784
784
785 self.assertIsInstance(res.error_before_exec, InputRejected)
785 self.assertIsInstance(res.error_before_exec, InputRejected)
786
786
787 def test__IPYTHON__():
787 def test__IPYTHON__():
788 # This shouldn't raise a NameError, that's all
788 # This shouldn't raise a NameError, that's all
789 __IPYTHON__
789 __IPYTHON__
790
790
791
791
792 class DummyRepr(object):
792 class DummyRepr(object):
793 def __repr__(self):
793 def __repr__(self):
794 return "DummyRepr"
794 return "DummyRepr"
795
795
796 def _repr_html_(self):
796 def _repr_html_(self):
797 return "<b>dummy</b>"
797 return "<b>dummy</b>"
798
798
799 def _repr_javascript_(self):
799 def _repr_javascript_(self):
800 return "console.log('hi');", {'key': 'value'}
800 return "console.log('hi');", {'key': 'value'}
801
801
802
802
803 def test_user_variables():
803 def test_user_variables():
804 # enable all formatters
804 # enable all formatters
805 ip.display_formatter.active_types = ip.display_formatter.format_types
805 ip.display_formatter.active_types = ip.display_formatter.format_types
806
806
807 ip.user_ns['dummy'] = d = DummyRepr()
807 ip.user_ns['dummy'] = d = DummyRepr()
808 keys = {'dummy', 'doesnotexist'}
808 keys = {'dummy', 'doesnotexist'}
809 r = ip.user_expressions({ key:key for key in keys})
809 r = ip.user_expressions({ key:key for key in keys})
810
810
811 nt.assert_equal(keys, set(r.keys()))
811 nt.assert_equal(keys, set(r.keys()))
812 dummy = r['dummy']
812 dummy = r['dummy']
813 nt.assert_equal({'status', 'data', 'metadata'}, set(dummy.keys()))
813 nt.assert_equal({'status', 'data', 'metadata'}, set(dummy.keys()))
814 nt.assert_equal(dummy['status'], 'ok')
814 nt.assert_equal(dummy['status'], 'ok')
815 data = dummy['data']
815 data = dummy['data']
816 metadata = dummy['metadata']
816 metadata = dummy['metadata']
817 nt.assert_equal(data.get('text/html'), d._repr_html_())
817 nt.assert_equal(data.get('text/html'), d._repr_html_())
818 js, jsmd = d._repr_javascript_()
818 js, jsmd = d._repr_javascript_()
819 nt.assert_equal(data.get('application/javascript'), js)
819 nt.assert_equal(data.get('application/javascript'), js)
820 nt.assert_equal(metadata.get('application/javascript'), jsmd)
820 nt.assert_equal(metadata.get('application/javascript'), jsmd)
821
821
822 dne = r['doesnotexist']
822 dne = r['doesnotexist']
823 nt.assert_equal(dne['status'], 'error')
823 nt.assert_equal(dne['status'], 'error')
824 nt.assert_equal(dne['ename'], 'NameError')
824 nt.assert_equal(dne['ename'], 'NameError')
825
825
826 # back to text only
826 # back to text only
827 ip.display_formatter.active_types = ['text/plain']
827 ip.display_formatter.active_types = ['text/plain']
828
828
829 def test_user_expression():
829 def test_user_expression():
830 # enable all formatters
830 # enable all formatters
831 ip.display_formatter.active_types = ip.display_formatter.format_types
831 ip.display_formatter.active_types = ip.display_formatter.format_types
832 query = {
832 query = {
833 'a' : '1 + 2',
833 'a' : '1 + 2',
834 'b' : '1/0',
834 'b' : '1/0',
835 }
835 }
836 r = ip.user_expressions(query)
836 r = ip.user_expressions(query)
837 import pprint
837 import pprint
838 pprint.pprint(r)
838 pprint.pprint(r)
839 nt.assert_equal(set(r.keys()), set(query.keys()))
839 nt.assert_equal(set(r.keys()), set(query.keys()))
840 a = r['a']
840 a = r['a']
841 nt.assert_equal({'status', 'data', 'metadata'}, set(a.keys()))
841 nt.assert_equal({'status', 'data', 'metadata'}, set(a.keys()))
842 nt.assert_equal(a['status'], 'ok')
842 nt.assert_equal(a['status'], 'ok')
843 data = a['data']
843 data = a['data']
844 metadata = a['metadata']
844 metadata = a['metadata']
845 nt.assert_equal(data.get('text/plain'), '3')
845 nt.assert_equal(data.get('text/plain'), '3')
846
846
847 b = r['b']
847 b = r['b']
848 nt.assert_equal(b['status'], 'error')
848 nt.assert_equal(b['status'], 'error')
849 nt.assert_equal(b['ename'], 'ZeroDivisionError')
849 nt.assert_equal(b['ename'], 'ZeroDivisionError')
850
850
851 # back to text only
851 # back to text only
852 ip.display_formatter.active_types = ['text/plain']
852 ip.display_formatter.active_types = ['text/plain']
853
853
854
854
855
855
856
856
857
857
858 class TestSyntaxErrorTransformer(unittest.TestCase):
858 class TestSyntaxErrorTransformer(unittest.TestCase):
859 """Check that SyntaxError raised by an input transformer is handled by run_cell()"""
859 """Check that SyntaxError raised by an input transformer is handled by run_cell()"""
860
860
861 class SyntaxErrorTransformer(InputTransformer):
861 class SyntaxErrorTransformer(InputTransformer):
862
862
863 def push(self, line):
863 def push(self, line):
864 pos = line.find('syntaxerror')
864 pos = line.find('syntaxerror')
865 if pos >= 0:
865 if pos >= 0:
866 e = SyntaxError('input contains "syntaxerror"')
866 e = SyntaxError('input contains "syntaxerror"')
867 e.text = line
867 e.text = line
868 e.offset = pos + 1
868 e.offset = pos + 1
869 raise e
869 raise e
870 return line
870 return line
871
871
872 def reset(self):
872 def reset(self):
873 pass
873 pass
874
874
875 def setUp(self):
875 def setUp(self):
876 self.transformer = TestSyntaxErrorTransformer.SyntaxErrorTransformer()
876 self.transformer = TestSyntaxErrorTransformer.SyntaxErrorTransformer()
877 ip.input_splitter.python_line_transforms.append(self.transformer)
877 ip.input_splitter.python_line_transforms.append(self.transformer)
878 ip.input_transformer_manager.python_line_transforms.append(self.transformer)
878 ip.input_transformer_manager.python_line_transforms.append(self.transformer)
879
879
880 def tearDown(self):
880 def tearDown(self):
881 ip.input_splitter.python_line_transforms.remove(self.transformer)
881 ip.input_splitter.python_line_transforms.remove(self.transformer)
882 ip.input_transformer_manager.python_line_transforms.remove(self.transformer)
882 ip.input_transformer_manager.python_line_transforms.remove(self.transformer)
883
883
884 def test_syntaxerror_input_transformer(self):
884 def test_syntaxerror_input_transformer(self):
885 with tt.AssertPrints('1234'):
885 with tt.AssertPrints('1234'):
886 ip.run_cell('1234')
886 ip.run_cell('1234')
887 with tt.AssertPrints('SyntaxError: invalid syntax'):
887 with tt.AssertPrints('SyntaxError: invalid syntax'):
888 ip.run_cell('1 2 3') # plain python syntax error
888 ip.run_cell('1 2 3') # plain python syntax error
889 with tt.AssertPrints('SyntaxError: input contains "syntaxerror"'):
889 with tt.AssertPrints('SyntaxError: input contains "syntaxerror"'):
890 ip.run_cell('2345 # syntaxerror') # input transformer syntax error
890 ip.run_cell('2345 # syntaxerror') # input transformer syntax error
891 with tt.AssertPrints('3456'):
891 with tt.AssertPrints('3456'):
892 ip.run_cell('3456')
892 ip.run_cell('3456')
893
893
894
894
895
895
896 def test_warning_suppression():
896 def test_warning_suppression():
897 ip.run_cell("import warnings")
897 ip.run_cell("import warnings")
898 try:
898 try:
899 with tt.AssertPrints("UserWarning: asdf", channel="stderr"):
899 with tt.AssertPrints("UserWarning: asdf", channel="stderr"):
900 ip.run_cell("warnings.warn('asdf')")
900 ip.run_cell("warnings.warn('asdf')")
901 # Here's the real test -- if we run that again, we should get the
901 # Here's the real test -- if we run that again, we should get the
902 # warning again. Traditionally, each warning was only issued once per
902 # warning again. Traditionally, each warning was only issued once per
903 # IPython session (approximately), even if the user typed in new and
903 # IPython session (approximately), even if the user typed in new and
904 # different code that should have also triggered the warning, leading
904 # different code that should have also triggered the warning, leading
905 # to much confusion.
905 # to much confusion.
906 with tt.AssertPrints("UserWarning: asdf", channel="stderr"):
906 with tt.AssertPrints("UserWarning: asdf", channel="stderr"):
907 ip.run_cell("warnings.warn('asdf')")
907 ip.run_cell("warnings.warn('asdf')")
908 finally:
908 finally:
909 ip.run_cell("del warnings")
909 ip.run_cell("del warnings")
910
910
911
911
912 def test_deprecation_warning():
912 def test_deprecation_warning():
913 ip.run_cell("""
913 ip.run_cell("""
914 import warnings
914 import warnings
915 def wrn():
915 def wrn():
916 warnings.warn(
916 warnings.warn(
917 "I AM A WARNING",
917 "I AM A WARNING",
918 DeprecationWarning
918 DeprecationWarning
919 )
919 )
920 """)
920 """)
921 try:
921 try:
922 with tt.AssertPrints("I AM A WARNING", channel="stderr"):
922 with tt.AssertPrints("I AM A WARNING", channel="stderr"):
923 ip.run_cell("wrn()")
923 ip.run_cell("wrn()")
924 finally:
924 finally:
925 ip.run_cell("del warnings")
925 ip.run_cell("del warnings")
926 ip.run_cell("del wrn")
926 ip.run_cell("del wrn")
927
927
928
928
929 class TestImportNoDeprecate(tt.TempFileMixin):
929 class TestImportNoDeprecate(tt.TempFileMixin):
930
930
931 def setup(self):
931 def setup(self):
932 """Make a valid python temp file."""
932 """Make a valid python temp file."""
933 self.mktmp("""
933 self.mktmp("""
934 import warnings
934 import warnings
935 def wrn():
935 def wrn():
936 warnings.warn(
936 warnings.warn(
937 "I AM A WARNING",
937 "I AM A WARNING",
938 DeprecationWarning
938 DeprecationWarning
939 )
939 )
940 """)
940 """)
941
941
942 def test_no_dep(self):
942 def test_no_dep(self):
943 """
943 """
944 No deprecation warning should be raised from imported functions
944 No deprecation warning should be raised from imported functions
945 """
945 """
946 ip.run_cell("from {} import wrn".format(self.fname))
946 ip.run_cell("from {} import wrn".format(self.fname))
947
947
948 with tt.AssertNotPrints("I AM A WARNING"):
948 with tt.AssertNotPrints("I AM A WARNING"):
949 ip.run_cell("wrn()")
949 ip.run_cell("wrn()")
950 ip.run_cell("del wrn")
950 ip.run_cell("del wrn")
951
952
953 def test_custom_exc_count():
954 hook = mock.Mock(return_value=None)
955 ip.set_custom_exc((SyntaxError,), hook)
956 before = ip.execution_count
957 ip.run_cell("def foo()", store_history=True)
958 # restore default excepthook
959 ip.set_custom_exc((), None)
960 nt.assert_equal(hook.call_count, 1)
961 nt.assert_equal(ip.execution_count, before + 1)
General Comments 0
You need to be logged in to leave comments. Login now