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