##// END OF EJS Templates
Merge pull request #11005 from ipython/auto-backport-of-pr-10993...
Thomas Kluyver -
r24142:5b6fe626 merge
parent child Browse files
Show More

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

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