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