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