##// END OF EJS Templates
TEST: Fix invalid ast transformer in test....
Scott Sanderson -
Show More
@@ -1,806 +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 475 def test_new_main_mod(self):
476 476 # Smoketest to check that this accepts a unicode module name
477 477 name = u'jiefmw'
478 478 mod = ip.new_main_mod(u'%s.py' % name, name)
479 479 self.assertEqual(mod.__name__, name)
480 480
481 481 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
482 482
483 483 @onlyif_unicode_paths
484 484 def setUp(self):
485 485 self.BASETESTDIR = tempfile.mkdtemp()
486 486 self.TESTDIR = join(self.BASETESTDIR, u"Γ₯Àâ")
487 487 os.mkdir(self.TESTDIR)
488 488 with open(join(self.TESTDIR, u"Γ₯Àâtestscript.py"), "w") as sfile:
489 489 sfile.write("pass\n")
490 490 self.oldpath = py3compat.getcwd()
491 491 os.chdir(self.TESTDIR)
492 492 self.fname = u"Γ₯Àâtestscript.py"
493 493
494 494 def tearDown(self):
495 495 os.chdir(self.oldpath)
496 496 shutil.rmtree(self.BASETESTDIR)
497 497
498 498 @onlyif_unicode_paths
499 499 def test_1(self):
500 500 """Test safe_execfile with non-ascii path
501 501 """
502 502 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
503 503
504 504 class ExitCodeChecks(tt.TempFileMixin):
505 505 def test_exit_code_ok(self):
506 506 self.system('exit 0')
507 507 self.assertEqual(ip.user_ns['_exit_code'], 0)
508 508
509 509 def test_exit_code_error(self):
510 510 self.system('exit 1')
511 511 self.assertEqual(ip.user_ns['_exit_code'], 1)
512 512
513 513 @skipif(not hasattr(signal, 'SIGALRM'))
514 514 def test_exit_code_signal(self):
515 515 self.mktmp("import signal, time\n"
516 516 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
517 517 "time.sleep(1)\n")
518 518 self.system("%s %s" % (sys.executable, self.fname))
519 519 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
520 520
521 521 @onlyif_cmds_exist("csh")
522 522 def test_exit_code_signal_csh(self):
523 523 SHELL = os.environ.get('SHELL', None)
524 524 os.environ['SHELL'] = find_cmd("csh")
525 525 try:
526 526 self.test_exit_code_signal()
527 527 finally:
528 528 if SHELL is not None:
529 529 os.environ['SHELL'] = SHELL
530 530 else:
531 531 del os.environ['SHELL']
532 532
533 533 class TestSystemRaw(unittest.TestCase, ExitCodeChecks):
534 534 system = ip.system_raw
535 535
536 536 @onlyif_unicode_paths
537 537 def test_1(self):
538 538 """Test system_raw with non-ascii cmd
539 539 """
540 540 cmd = u'''python -c "'Γ₯Àâ'" '''
541 541 ip.system_raw(cmd)
542 542
543 543 # TODO: Exit codes are currently ignored on Windows.
544 544 class TestSystemPipedExitCode(unittest.TestCase, ExitCodeChecks):
545 545 system = ip.system_piped
546 546
547 547 @skip_win32
548 548 def test_exit_code_ok(self):
549 549 ExitCodeChecks.test_exit_code_ok(self)
550 550
551 551 @skip_win32
552 552 def test_exit_code_error(self):
553 553 ExitCodeChecks.test_exit_code_error(self)
554 554
555 555 @skip_win32
556 556 def test_exit_code_signal(self):
557 557 ExitCodeChecks.test_exit_code_signal(self)
558 558
559 559 class TestModules(unittest.TestCase, tt.TempFileMixin):
560 560 def test_extraneous_loads(self):
561 561 """Test we're not loading modules on startup that we shouldn't.
562 562 """
563 563 self.mktmp("import sys\n"
564 564 "print('numpy' in sys.modules)\n"
565 565 "print('IPython.parallel' in sys.modules)\n"
566 566 "print('IPython.kernel.zmq' in sys.modules)\n"
567 567 )
568 568 out = "False\nFalse\nFalse\n"
569 569 tt.ipexec_validate(self.fname, out)
570 570
571 571 class Negator(ast.NodeTransformer):
572 572 """Negates all number literals in an AST."""
573 573 def visit_Num(self, node):
574 574 node.n = -node.n
575 575 return node
576 576
577 577 class TestAstTransform(unittest.TestCase):
578 578 def setUp(self):
579 579 self.negator = Negator()
580 580 ip.ast_transformers.append(self.negator)
581 581
582 582 def tearDown(self):
583 583 ip.ast_transformers.remove(self.negator)
584 584
585 585 def test_run_cell(self):
586 586 with tt.AssertPrints('-34'):
587 587 ip.run_cell('print (12 + 22)')
588 588
589 589 # A named reference to a number shouldn't be transformed.
590 590 ip.user_ns['n'] = 55
591 591 with tt.AssertNotPrints('-55'):
592 592 ip.run_cell('print (n)')
593 593
594 594 def test_timeit(self):
595 595 called = set()
596 596 def f(x):
597 597 called.add(x)
598 598 ip.push({'f':f})
599 599
600 600 with tt.AssertPrints("best of "):
601 601 ip.run_line_magic("timeit", "-n1 f(1)")
602 602 self.assertEqual(called, set([-1]))
603 603 called.clear()
604 604
605 605 with tt.AssertPrints("best of "):
606 606 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
607 607 self.assertEqual(called, set([-2, -3]))
608 608
609 609 def test_time(self):
610 610 called = []
611 611 def f(x):
612 612 called.append(x)
613 613 ip.push({'f':f})
614 614
615 615 # Test with an expression
616 616 with tt.AssertPrints("Wall time: "):
617 617 ip.run_line_magic("time", "f(5+9)")
618 618 self.assertEqual(called, [-14])
619 619 called[:] = []
620 620
621 621 # Test with a statement (different code path)
622 622 with tt.AssertPrints("Wall time: "):
623 623 ip.run_line_magic("time", "a = f(-3 + -2)")
624 624 self.assertEqual(called, [5])
625 625
626 626 def test_macro(self):
627 627 ip.push({'a':10})
628 628 # The AST transformation makes this do a+=-1
629 629 ip.define_macro("amacro", "a+=1\nprint(a)")
630 630
631 631 with tt.AssertPrints("9"):
632 632 ip.run_cell("amacro")
633 633 with tt.AssertPrints("8"):
634 634 ip.run_cell("amacro")
635 635
636 636 class IntegerWrapper(ast.NodeTransformer):
637 637 """Wraps all integers in a call to Integer()"""
638 638 def visit_Num(self, node):
639 639 if isinstance(node.n, int):
640 640 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
641 641 args=[node], keywords=[])
642 642 return node
643 643
644 644 class TestAstTransform2(unittest.TestCase):
645 645 def setUp(self):
646 646 self.intwrapper = IntegerWrapper()
647 647 ip.ast_transformers.append(self.intwrapper)
648 648
649 649 self.calls = []
650 650 def Integer(*args):
651 651 self.calls.append(args)
652 652 return args
653 653 ip.push({"Integer": Integer})
654 654
655 655 def tearDown(self):
656 656 ip.ast_transformers.remove(self.intwrapper)
657 657 del ip.user_ns['Integer']
658 658
659 659 def test_run_cell(self):
660 660 ip.run_cell("n = 2")
661 661 self.assertEqual(self.calls, [(2,)])
662 662
663 663 # This shouldn't throw an error
664 664 ip.run_cell("o = 2.0")
665 665 self.assertEqual(ip.user_ns['o'], 2.0)
666 666
667 667 def test_timeit(self):
668 668 called = set()
669 669 def f(x):
670 670 called.add(x)
671 671 ip.push({'f':f})
672 672
673 673 with tt.AssertPrints("best of "):
674 674 ip.run_line_magic("timeit", "-n1 f(1)")
675 675 self.assertEqual(called, set([(1,)]))
676 676 called.clear()
677 677
678 678 with tt.AssertPrints("best of "):
679 679 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
680 680 self.assertEqual(called, set([(2,), (3,)]))
681 681
682 682 class ErrorTransformer(ast.NodeTransformer):
683 683 """Throws an error when it sees a number."""
684 def visit_Num(self):
684 def visit_Num(self, node):
685 685 raise ValueError("test")
686 686
687 687 class TestAstTransformError(unittest.TestCase):
688 688 def test_unregistering(self):
689 689 err_transformer = ErrorTransformer()
690 690 ip.ast_transformers.append(err_transformer)
691 691
692 692 with tt.AssertPrints("unregister", channel='stderr'):
693 693 ip.run_cell("1 + 2")
694 694
695 695 # This should have been removed.
696 696 nt.assert_not_in(err_transformer, ip.ast_transformers)
697 697
698 698 def test__IPYTHON__():
699 699 # This shouldn't raise a NameError, that's all
700 700 __IPYTHON__
701 701
702 702
703 703 class DummyRepr(object):
704 704 def __repr__(self):
705 705 return "DummyRepr"
706 706
707 707 def _repr_html_(self):
708 708 return "<b>dummy</b>"
709 709
710 710 def _repr_javascript_(self):
711 711 return "console.log('hi');", {'key': 'value'}
712 712
713 713
714 714 def test_user_variables():
715 715 # enable all formatters
716 716 ip.display_formatter.active_types = ip.display_formatter.format_types
717 717
718 718 ip.user_ns['dummy'] = d = DummyRepr()
719 719 keys = set(['dummy', 'doesnotexist'])
720 720 r = ip.user_expressions({ key:key for key in keys})
721 721
722 722 nt.assert_equal(keys, set(r.keys()))
723 723 dummy = r['dummy']
724 724 nt.assert_equal(set(['status', 'data', 'metadata']), set(dummy.keys()))
725 725 nt.assert_equal(dummy['status'], 'ok')
726 726 data = dummy['data']
727 727 metadata = dummy['metadata']
728 728 nt.assert_equal(data.get('text/html'), d._repr_html_())
729 729 js, jsmd = d._repr_javascript_()
730 730 nt.assert_equal(data.get('application/javascript'), js)
731 731 nt.assert_equal(metadata.get('application/javascript'), jsmd)
732 732
733 733 dne = r['doesnotexist']
734 734 nt.assert_equal(dne['status'], 'error')
735 735 nt.assert_equal(dne['ename'], 'NameError')
736 736
737 737 # back to text only
738 738 ip.display_formatter.active_types = ['text/plain']
739 739
740 740 def test_user_expression():
741 741 # enable all formatters
742 742 ip.display_formatter.active_types = ip.display_formatter.format_types
743 743 query = {
744 744 'a' : '1 + 2',
745 745 'b' : '1/0',
746 746 }
747 747 r = ip.user_expressions(query)
748 748 import pprint
749 749 pprint.pprint(r)
750 750 nt.assert_equal(set(r.keys()), set(query.keys()))
751 751 a = r['a']
752 752 nt.assert_equal(set(['status', 'data', 'metadata']), set(a.keys()))
753 753 nt.assert_equal(a['status'], 'ok')
754 754 data = a['data']
755 755 metadata = a['metadata']
756 756 nt.assert_equal(data.get('text/plain'), '3')
757 757
758 758 b = r['b']
759 759 nt.assert_equal(b['status'], 'error')
760 760 nt.assert_equal(b['ename'], 'ZeroDivisionError')
761 761
762 762 # back to text only
763 763 ip.display_formatter.active_types = ['text/plain']
764 764
765 765
766 766
767 767
768 768
769 769 class TestSyntaxErrorTransformer(unittest.TestCase):
770 770 """Check that SyntaxError raised by an input transformer is handled by run_cell()"""
771 771
772 772 class SyntaxErrorTransformer(InputTransformer):
773 773
774 774 def push(self, line):
775 775 pos = line.find('syntaxerror')
776 776 if pos >= 0:
777 777 e = SyntaxError('input contains "syntaxerror"')
778 778 e.text = line
779 779 e.offset = pos + 1
780 780 raise e
781 781 return line
782 782
783 783 def reset(self):
784 784 pass
785 785
786 786 def setUp(self):
787 787 self.transformer = TestSyntaxErrorTransformer.SyntaxErrorTransformer()
788 788 ip.input_splitter.python_line_transforms.append(self.transformer)
789 789 ip.input_transformer_manager.python_line_transforms.append(self.transformer)
790 790
791 791 def tearDown(self):
792 792 ip.input_splitter.python_line_transforms.remove(self.transformer)
793 793 ip.input_transformer_manager.python_line_transforms.remove(self.transformer)
794 794
795 795 def test_syntaxerror_input_transformer(self):
796 796 with tt.AssertPrints('1234'):
797 797 ip.run_cell('1234')
798 798 with tt.AssertPrints('SyntaxError: invalid syntax'):
799 799 ip.run_cell('1 2 3') # plain python syntax error
800 800 with tt.AssertPrints('SyntaxError: input contains "syntaxerror"'):
801 801 ip.run_cell('2345 # syntaxerror') # input transformer syntax error
802 802 with tt.AssertPrints('3456'):
803 803 ip.run_cell('3456')
804 804
805 805
806 806
General Comments 0
You need to be logged in to leave comments. Login now