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