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