##// END OF EJS Templates
raise an error when user tries to open a standard stream...
Osher De Paz -
Show More

The requested changes are too big and content was truncated. Show full diff

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