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