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