##// END OF EJS Templates
Add test for custom exception hook.
Thomas Kluyver -
Show More
@@ -1,374 +1,389 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for the key interactiveshell module.
3 3
4 4 Historically the main classes in interactiveshell have been under-tested. This
5 5 module should grow as many single-method tests as possible to trap many of the
6 6 recurring bugs we seem to encounter with high-level interaction.
7 7
8 8 Authors
9 9 -------
10 10 * Fernando Perez
11 11 """
12 12 #-----------------------------------------------------------------------------
13 13 # Copyright (C) 2011 The IPython Development Team
14 14 #
15 15 # Distributed under the terms of the BSD License. The full license is in
16 16 # the file COPYING, distributed as part of this software.
17 17 #-----------------------------------------------------------------------------
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Imports
21 21 #-----------------------------------------------------------------------------
22 22 # stdlib
23 23 import os
24 24 import shutil
25 25 import sys
26 26 import tempfile
27 27 import unittest
28 28 from os.path import join
29 29 from StringIO import StringIO
30 30
31 31 # third-party
32 32 import nose.tools as nt
33 33
34 34 # Our own
35 35 from IPython.testing.decorators import skipif
36 36 from IPython.utils import io
37 37
38 38 #-----------------------------------------------------------------------------
39 39 # Globals
40 40 #-----------------------------------------------------------------------------
41 41 # This is used by every single test, no point repeating it ad nauseam
42 42 ip = get_ipython()
43 43
44 44 #-----------------------------------------------------------------------------
45 45 # Tests
46 46 #-----------------------------------------------------------------------------
47 47
48 48 class InteractiveShellTestCase(unittest.TestCase):
49 49 def test_naked_string_cells(self):
50 50 """Test that cells with only naked strings are fully executed"""
51 51 # First, single-line inputs
52 52 ip.run_cell('"a"\n')
53 53 self.assertEquals(ip.user_ns['_'], 'a')
54 54 # And also multi-line cells
55 55 ip.run_cell('"""a\nb"""\n')
56 56 self.assertEquals(ip.user_ns['_'], 'a\nb')
57 57
58 58 def test_run_empty_cell(self):
59 59 """Just make sure we don't get a horrible error with a blank
60 60 cell of input. Yes, I did overlook that."""
61 61 old_xc = ip.execution_count
62 62 ip.run_cell('')
63 63 self.assertEquals(ip.execution_count, old_xc)
64 64
65 65 def test_run_cell_multiline(self):
66 66 """Multi-block, multi-line cells must execute correctly.
67 67 """
68 68 src = '\n'.join(["x=1",
69 69 "y=2",
70 70 "if 1:",
71 71 " x += 1",
72 72 " y += 1",])
73 73 ip.run_cell(src)
74 74 self.assertEquals(ip.user_ns['x'], 2)
75 75 self.assertEquals(ip.user_ns['y'], 3)
76 76
77 77 def test_multiline_string_cells(self):
78 78 "Code sprinkled with multiline strings should execute (GH-306)"
79 79 ip.run_cell('tmp=0')
80 80 self.assertEquals(ip.user_ns['tmp'], 0)
81 81 ip.run_cell('tmp=1;"""a\nb"""\n')
82 82 self.assertEquals(ip.user_ns['tmp'], 1)
83 83
84 84 def test_dont_cache_with_semicolon(self):
85 85 "Ending a line with semicolon should not cache the returned object (GH-307)"
86 86 oldlen = len(ip.user_ns['Out'])
87 87 a = ip.run_cell('1;', store_history=True)
88 88 newlen = len(ip.user_ns['Out'])
89 89 self.assertEquals(oldlen, newlen)
90 90 #also test the default caching behavior
91 91 ip.run_cell('1', store_history=True)
92 92 newlen = len(ip.user_ns['Out'])
93 93 self.assertEquals(oldlen+1, newlen)
94 94
95 95 def test_In_variable(self):
96 96 "Verify that In variable grows with user input (GH-284)"
97 97 oldlen = len(ip.user_ns['In'])
98 98 ip.run_cell('1;', store_history=True)
99 99 newlen = len(ip.user_ns['In'])
100 100 self.assertEquals(oldlen+1, newlen)
101 101 self.assertEquals(ip.user_ns['In'][-1],'1;')
102 102
103 103 def test_magic_names_in_string(self):
104 104 ip.run_cell('a = """\n%exit\n"""')
105 105 self.assertEquals(ip.user_ns['a'], '\n%exit\n')
106 106
107 107 def test_alias_crash(self):
108 108 """Errors in prefilter can't crash IPython"""
109 109 ip.run_cell('%alias parts echo first %s second %s')
110 110 # capture stderr:
111 111 save_err = io.stderr
112 112 io.stderr = StringIO()
113 113 ip.run_cell('parts 1')
114 114 err = io.stderr.getvalue()
115 115 io.stderr = save_err
116 116 self.assertEquals(err.split(':')[0], 'ERROR')
117 117
118 118 def test_trailing_newline(self):
119 119 """test that running !(command) does not raise a SyntaxError"""
120 120 ip.run_cell('!(true)\n', False)
121 121 ip.run_cell('!(true)\n\n\n', False)
122 122
123 123 def test_gh_597(self):
124 124 """Pretty-printing lists of objects with non-ascii reprs may cause
125 125 problems."""
126 126 class Spam(object):
127 127 def __repr__(self):
128 128 return "\xe9"*50
129 129 import IPython.core.formatters
130 130 f = IPython.core.formatters.PlainTextFormatter()
131 131 f([Spam(),Spam()])
132 132
133 133
134 134 def test_future_flags(self):
135 135 """Check that future flags are used for parsing code (gh-777)"""
136 136 ip.run_cell('from __future__ import print_function')
137 137 try:
138 138 ip.run_cell('prfunc_return_val = print(1,2, sep=" ")')
139 139 assert 'prfunc_return_val' in ip.user_ns
140 140 finally:
141 141 # Reset compiler flags so we don't mess up other tests.
142 142 ip.compile.reset_compiler_flags()
143 143
144 144 def test_future_unicode(self):
145 145 """Check that unicode_literals is imported from __future__ (gh #786)"""
146 146 try:
147 147 ip.run_cell(u'byte_str = "a"')
148 148 assert isinstance(ip.user_ns['byte_str'], str) # string literals are byte strings by default
149 149 ip.run_cell('from __future__ import unicode_literals')
150 150 ip.run_cell(u'unicode_str = "a"')
151 151 assert isinstance(ip.user_ns['unicode_str'], unicode) # strings literals are now unicode
152 152 finally:
153 153 # Reset compiler flags so we don't mess up other tests.
154 154 ip.compile.reset_compiler_flags()
155 155
156 156 def test_can_pickle(self):
157 157 "Can we pickle objects defined interactively (GH-29)"
158 158 ip = get_ipython()
159 159 ip.reset()
160 160 ip.run_cell(("class Mylist(list):\n"
161 161 " def __init__(self,x=[]):\n"
162 162 " list.__init__(self,x)"))
163 163 ip.run_cell("w=Mylist([1,2,3])")
164 164
165 165 from cPickle import dumps
166 166
167 167 # We need to swap in our main module - this is only necessary
168 168 # inside the test framework, because IPython puts the interactive module
169 169 # in place (but the test framework undoes this).
170 170 _main = sys.modules['__main__']
171 171 sys.modules['__main__'] = ip.user_module
172 172 try:
173 173 res = dumps(ip.user_ns["w"])
174 174 finally:
175 175 sys.modules['__main__'] = _main
176 176 self.assertTrue(isinstance(res, bytes))
177 177
178 178 def test_global_ns(self):
179 179 "Code in functions must be able to access variables outside them."
180 180 ip = get_ipython()
181 181 ip.run_cell("a = 10")
182 182 ip.run_cell(("def f(x):\n"
183 183 " return x + a"))
184 184 ip.run_cell("b = f(12)")
185 185 self.assertEqual(ip.user_ns["b"], 22)
186 186
187 187 def test_bad_custom_tb(self):
188 188 """Check that InteractiveShell is protected from bad custom exception handlers"""
189 189 from IPython.utils import io
190 190 save_stderr = io.stderr
191 191 try:
192 192 # capture stderr
193 193 io.stderr = StringIO()
194 194 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
195 195 self.assertEquals(ip.custom_exceptions, (IOError,))
196 196 ip.run_cell(u'raise IOError("foo")')
197 197 self.assertEquals(ip.custom_exceptions, ())
198 198 self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
199 199 finally:
200 200 io.stderr = save_stderr
201 201
202 202 def test_bad_custom_tb_return(self):
203 203 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
204 204 from IPython.utils import io
205 205 save_stderr = io.stderr
206 206 try:
207 207 # capture stderr
208 208 io.stderr = StringIO()
209 209 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
210 210 self.assertEquals(ip.custom_exceptions, (NameError,))
211 211 ip.run_cell(u'a=abracadabra')
212 212 self.assertEquals(ip.custom_exceptions, ())
213 213 self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
214 214 finally:
215 215 io.stderr = save_stderr
216 216
217 217 def test_drop_by_id(self):
218 218 myvars = {"a":object(), "b":object(), "c": object()}
219 219 ip.push(myvars, interactive=False)
220 220 for name in myvars:
221 221 assert name in ip.user_ns, name
222 222 assert name in ip.user_ns_hidden, name
223 223 ip.user_ns['b'] = 12
224 224 ip.drop_by_id(myvars)
225 225 for name in ["a", "c"]:
226 226 assert name not in ip.user_ns, name
227 227 assert name not in ip.user_ns_hidden, name
228 228 assert ip.user_ns['b'] == 12
229 229 ip.reset()
230 230
231 231 def test_var_expand(self):
232 232 ip.user_ns['f'] = u'Ca\xf1o'
233 233 self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
234 234 self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
235 235 self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
236 236 self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
237 237
238 238 ip.user_ns['f'] = b'Ca\xc3\xb1o'
239 239 # This should not raise any exception:
240 240 ip.var_expand(u'echo $f')
241 241
242 242 def test_bad_var_expand(self):
243 243 """var_expand on invalid formats shouldn't raise"""
244 244 # SyntaxError
245 245 self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
246 246 # NameError
247 247 self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
248 248 # ZeroDivisionError
249 249 self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
250 250
251 251 def test_silent_nopostexec(self):
252 252 """run_cell(silent=True) doesn't invoke post-exec funcs"""
253 253 d = dict(called=False)
254 254 def set_called():
255 255 d['called'] = True
256 256
257 257 ip.register_post_execute(set_called)
258 258 ip.run_cell("1", silent=True)
259 259 self.assertFalse(d['called'])
260 260 # double-check that non-silent exec did what we expected
261 261 # silent to avoid
262 262 ip.run_cell("1")
263 263 self.assertTrue(d['called'])
264 264 # remove post-exec
265 265 ip._post_execute.pop(set_called)
266 266
267 267 def test_silent_noadvance(self):
268 268 """run_cell(silent=True) doesn't advance execution_count"""
269 269 ec = ip.execution_count
270 270 # silent should force store_history=False
271 271 ip.run_cell("1", store_history=True, silent=True)
272 272
273 273 self.assertEquals(ec, ip.execution_count)
274 274 # double-check that non-silent exec did what we expected
275 275 # silent to avoid
276 276 ip.run_cell("1", store_history=True)
277 277 self.assertEquals(ec+1, ip.execution_count)
278 278
279 279 def test_silent_nodisplayhook(self):
280 280 """run_cell(silent=True) doesn't trigger displayhook"""
281 281 d = dict(called=False)
282 282
283 283 trap = ip.display_trap
284 284 save_hook = trap.hook
285 285
286 286 def failing_hook(*args, **kwargs):
287 287 d['called'] = True
288 288
289 289 try:
290 290 trap.hook = failing_hook
291 291 ip.run_cell("1", silent=True)
292 292 self.assertFalse(d['called'])
293 293 # double-check that non-silent exec did what we expected
294 294 # silent to avoid
295 295 ip.run_cell("1")
296 296 self.assertTrue(d['called'])
297 297 finally:
298 298 trap.hook = save_hook
299 299
300 300 @skipif(sys.version_info[0] >= 3, "softspace removed in py3")
301 301 def test_print_softspace(self):
302 302 """Verify that softspace is handled correctly when executing multiple
303 303 statements.
304 304
305 305 In [1]: print 1; print 2
306 306 1
307 307 2
308 308
309 309 In [2]: print 1,; print 2
310 310 1 2
311 311 """
312 312
313 313 def test_ofind_line_magic(self):
314 314 from IPython.core.magic import register_line_magic
315 315
316 316 @register_line_magic
317 317 def lmagic(line):
318 318 "A line magic"
319 319
320 320 # Get info on line magic
321 321 lfind = ip._ofind('lmagic')
322 322 info = dict(found=True, isalias=False, ismagic=True,
323 323 namespace = 'IPython internal', obj= lmagic.__wrapped__,
324 324 parent = None)
325 325 nt.assert_equal(lfind, info)
326 326
327 327 def test_ofind_cell_magic(self):
328 328 from IPython.core.magic import register_cell_magic
329 329
330 330 @register_cell_magic
331 331 def cmagic(line, cell):
332 332 "A cell magic"
333 333
334 334 # Get info on cell magic
335 335 find = ip._ofind('cmagic')
336 336 info = dict(found=True, isalias=False, ismagic=True,
337 337 namespace = 'IPython internal', obj= cmagic.__wrapped__,
338 338 parent = None)
339 339 nt.assert_equal(find, info)
340
341 def test_custom_exception(self):
342 called = []
343 def my_handler(shell, etype, value, tb, tb_offset=None):
344 called.append(etype)
345 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
346
347 ip.set_custom_exc((ValueError,), my_handler)
348 try:
349 ip.run_cell("raise ValueError('test')")
350 # Check that this was called, and only once.
351 self.assertEqual(called, [ValueError])
352 finally:
353 # Reset the custom exception hook
354 ip.set_custom_exc((), None)
340 355
341 356
342 357 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
343 358
344 359 def setUp(self):
345 360 self.BASETESTDIR = tempfile.mkdtemp()
346 361 self.TESTDIR = join(self.BASETESTDIR, u"åäö")
347 362 os.mkdir(self.TESTDIR)
348 363 with open(join(self.TESTDIR, u"åäötestscript.py"), "w") as sfile:
349 364 sfile.write("pass\n")
350 365 self.oldpath = os.getcwdu()
351 366 os.chdir(self.TESTDIR)
352 367 self.fname = u"åäötestscript.py"
353 368
354 369 def tearDown(self):
355 370 os.chdir(self.oldpath)
356 371 shutil.rmtree(self.BASETESTDIR)
357 372
358 373 def test_1(self):
359 374 """Test safe_execfile with non-ascii path
360 375 """
361 376 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
362 377
363 378
364 379 class TestSystemRaw(unittest.TestCase):
365 380 def test_1(self):
366 381 """Test system_raw with non-ascii cmd
367 382 """
368 383 cmd = ur'''python -c "'åäö'" '''
369 384 ip.system_raw(cmd)
370 385
371 386
372 387 def test__IPYTHON__():
373 388 # This shouldn't raise a NameError, that's all
374 389 __IPYTHON__
General Comments 0
You need to be logged in to leave comments. Login now