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