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