##// END OF EJS Templates
Added a text cell in the notebook to test run_nb.
damianavila -
Show More
@@ -1,475 +1,476 b''
1 1 # encoding: utf-8
2 2 """Tests for code execution (%run and related), which is particularly tricky.
3 3
4 4 Because of how %run manages namespaces, and the fact that we are trying here to
5 5 verify subtle object deletion and reference counting issues, the %run tests
6 6 will be kept in this separate file. This makes it easier to aggregate in one
7 7 place the tricks needed to handle it; most other magics are much easier to test
8 8 and we do so in a common test_magic file.
9 9 """
10 10 from __future__ import absolute_import
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 15
16 16 import functools
17 17 import os
18 18 from os.path import join as pjoin
19 19 import random
20 20 import sys
21 21 import tempfile
22 22 import textwrap
23 23 import unittest
24 24
25 25 import nose.tools as nt
26 26 from nose import SkipTest
27 27
28 28 from IPython.testing import decorators as dec
29 29 from IPython.testing import tools as tt
30 30 from IPython.utils import py3compat
31 31 from IPython.utils.tempdir import TemporaryDirectory
32 32 from IPython.core import debugger
33 33
34 34 #-----------------------------------------------------------------------------
35 35 # Test functions begin
36 36 #-----------------------------------------------------------------------------
37 37
38 38 def doctest_refbug():
39 39 """Very nasty problem with references held by multiple runs of a script.
40 40 See: https://github.com/ipython/ipython/issues/141
41 41
42 42 In [1]: _ip.clear_main_mod_cache()
43 43 # random
44 44
45 45 In [2]: %run refbug
46 46
47 47 In [3]: call_f()
48 48 lowercased: hello
49 49
50 50 In [4]: %run refbug
51 51
52 52 In [5]: call_f()
53 53 lowercased: hello
54 54 lowercased: hello
55 55 """
56 56
57 57
58 58 def doctest_run_builtins():
59 59 r"""Check that %run doesn't damage __builtins__.
60 60
61 61 In [1]: import tempfile
62 62
63 63 In [2]: bid1 = id(__builtins__)
64 64
65 65 In [3]: fname = tempfile.mkstemp('.py')[1]
66 66
67 67 In [3]: f = open(fname,'w')
68 68
69 69 In [4]: dummy= f.write('pass\n')
70 70
71 71 In [5]: f.flush()
72 72
73 73 In [6]: t1 = type(__builtins__)
74 74
75 75 In [7]: %run $fname
76 76
77 77 In [7]: f.close()
78 78
79 79 In [8]: bid2 = id(__builtins__)
80 80
81 81 In [9]: t2 = type(__builtins__)
82 82
83 83 In [10]: t1 == t2
84 84 Out[10]: True
85 85
86 86 In [10]: bid1 == bid2
87 87 Out[10]: True
88 88
89 89 In [12]: try:
90 90 ....: os.unlink(fname)
91 91 ....: except:
92 92 ....: pass
93 93 ....:
94 94 """
95 95
96 96
97 97 def doctest_run_option_parser():
98 98 r"""Test option parser in %run.
99 99
100 100 In [1]: %run print_argv.py
101 101 []
102 102
103 103 In [2]: %run print_argv.py print*.py
104 104 ['print_argv.py']
105 105
106 106 In [3]: %run -G print_argv.py print*.py
107 107 ['print*.py']
108 108
109 109 """
110 110
111 111
112 112 @dec.skip_win32
113 113 def doctest_run_option_parser_for_posix():
114 114 r"""Test option parser in %run (Linux/OSX specific).
115 115
116 116 You need double quote to escape glob in POSIX systems:
117 117
118 118 In [1]: %run print_argv.py print\\*.py
119 119 ['print*.py']
120 120
121 121 You can't use quote to escape glob in POSIX systems:
122 122
123 123 In [2]: %run print_argv.py 'print*.py'
124 124 ['print_argv.py']
125 125
126 126 """
127 127
128 128
129 129 @dec.skip_if_not_win32
130 130 def doctest_run_option_parser_for_windows():
131 131 r"""Test option parser in %run (Windows specific).
132 132
133 133 In Windows, you can't escape ``*` `by backslash:
134 134
135 135 In [1]: %run print_argv.py print\\*.py
136 136 ['print\\*.py']
137 137
138 138 You can use quote to escape glob:
139 139
140 140 In [2]: %run print_argv.py 'print*.py'
141 141 ['print*.py']
142 142
143 143 """
144 144
145 145
146 146 @py3compat.doctest_refactor_print
147 147 def doctest_reset_del():
148 148 """Test that resetting doesn't cause errors in __del__ methods.
149 149
150 150 In [2]: class A(object):
151 151 ...: def __del__(self):
152 152 ...: print str("Hi")
153 153 ...:
154 154
155 155 In [3]: a = A()
156 156
157 157 In [4]: get_ipython().reset()
158 158 Hi
159 159
160 160 In [5]: 1+1
161 161 Out[5]: 2
162 162 """
163 163
164 164 # For some tests, it will be handy to organize them in a class with a common
165 165 # setup that makes a temp file
166 166
167 167 class TestMagicRunPass(tt.TempFileMixin):
168 168
169 169 def setup(self):
170 170 """Make a valid python temp file."""
171 171 self.mktmp('pass\n')
172 172
173 173 def run_tmpfile(self):
174 174 _ip = get_ipython()
175 175 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
176 176 # See below and ticket https://bugs.launchpad.net/bugs/366353
177 177 _ip.magic('run %s' % self.fname)
178 178
179 179 def run_tmpfile_p(self):
180 180 _ip = get_ipython()
181 181 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
182 182 # See below and ticket https://bugs.launchpad.net/bugs/366353
183 183 _ip.magic('run -p %s' % self.fname)
184 184
185 185 def test_builtins_id(self):
186 186 """Check that %run doesn't damage __builtins__ """
187 187 _ip = get_ipython()
188 188 # Test that the id of __builtins__ is not modified by %run
189 189 bid1 = id(_ip.user_ns['__builtins__'])
190 190 self.run_tmpfile()
191 191 bid2 = id(_ip.user_ns['__builtins__'])
192 192 nt.assert_equal(bid1, bid2)
193 193
194 194 def test_builtins_type(self):
195 195 """Check that the type of __builtins__ doesn't change with %run.
196 196
197 197 However, the above could pass if __builtins__ was already modified to
198 198 be a dict (it should be a module) by a previous use of %run. So we
199 199 also check explicitly that it really is a module:
200 200 """
201 201 _ip = get_ipython()
202 202 self.run_tmpfile()
203 203 nt.assert_equal(type(_ip.user_ns['__builtins__']),type(sys))
204 204
205 205 def test_prompts(self):
206 206 """Test that prompts correctly generate after %run"""
207 207 self.run_tmpfile()
208 208 _ip = get_ipython()
209 209 p2 = _ip.prompt_manager.render('in2').strip()
210 210 nt.assert_equal(p2[:3], '...')
211 211
212 212 def test_run_profile( self ):
213 213 """Test that the option -p, which invokes the profiler, do not
214 214 crash by invoking execfile"""
215 215 _ip = get_ipython()
216 216 self.run_tmpfile_p()
217 217
218 218
219 219 class TestMagicRunSimple(tt.TempFileMixin):
220 220
221 221 def test_simpledef(self):
222 222 """Test that simple class definitions work."""
223 223 src = ("class foo: pass\n"
224 224 "def f(): return foo()")
225 225 self.mktmp(src)
226 226 _ip.magic('run %s' % self.fname)
227 227 _ip.run_cell('t = isinstance(f(), foo)')
228 228 nt.assert_true(_ip.user_ns['t'])
229 229
230 230 def test_obj_del(self):
231 231 """Test that object's __del__ methods are called on exit."""
232 232 if sys.platform == 'win32':
233 233 try:
234 234 import win32api
235 235 except ImportError:
236 236 raise SkipTest("Test requires pywin32")
237 237 src = ("class A(object):\n"
238 238 " def __del__(self):\n"
239 239 " print 'object A deleted'\n"
240 240 "a = A()\n")
241 241 self.mktmp(py3compat.doctest_refactor_print(src))
242 242 if dec.module_not_available('sqlite3'):
243 243 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
244 244 else:
245 245 err = None
246 246 tt.ipexec_validate(self.fname, 'object A deleted', err)
247 247
248 248 def test_aggressive_namespace_cleanup(self):
249 249 """Test that namespace cleanup is not too aggressive GH-238
250 250
251 251 Returning from another run magic deletes the namespace"""
252 252 # see ticket https://github.com/ipython/ipython/issues/238
253 253 class secondtmp(tt.TempFileMixin): pass
254 254 empty = secondtmp()
255 255 empty.mktmp('')
256 256 # On Windows, the filename will have \users in it, so we need to use the
257 257 # repr so that the \u becomes \\u.
258 258 src = ("ip = get_ipython()\n"
259 259 "for i in range(5):\n"
260 260 " try:\n"
261 261 " ip.magic(%r)\n"
262 262 " except NameError as e:\n"
263 263 " print(i)\n"
264 264 " break\n" % ('run ' + empty.fname))
265 265 self.mktmp(src)
266 266 _ip.magic('run %s' % self.fname)
267 267 _ip.run_cell('ip == get_ipython()')
268 268 nt.assert_equal(_ip.user_ns['i'], 4)
269 269
270 270 def test_run_second(self):
271 271 """Test that running a second file doesn't clobber the first, gh-3547
272 272 """
273 273 self.mktmp("avar = 1\n"
274 274 "def afunc():\n"
275 275 " return avar\n")
276 276
277 277 empty = tt.TempFileMixin()
278 278 empty.mktmp("")
279 279
280 280 _ip.magic('run %s' % self.fname)
281 281 _ip.magic('run %s' % empty.fname)
282 282 nt.assert_equal(_ip.user_ns['afunc'](), 1)
283 283
284 284 @dec.skip_win32
285 285 def test_tclass(self):
286 286 mydir = os.path.dirname(__file__)
287 287 tc = os.path.join(mydir, 'tclass')
288 288 src = ("%%run '%s' C-first\n"
289 289 "%%run '%s' C-second\n"
290 290 "%%run '%s' C-third\n") % (tc, tc, tc)
291 291 self.mktmp(src, '.ipy')
292 292 out = """\
293 293 ARGV 1-: ['C-first']
294 294 ARGV 1-: ['C-second']
295 295 tclass.py: deleting object: C-first
296 296 ARGV 1-: ['C-third']
297 297 tclass.py: deleting object: C-second
298 298 tclass.py: deleting object: C-third
299 299 """
300 300 if dec.module_not_available('sqlite3'):
301 301 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
302 302 else:
303 303 err = None
304 304 tt.ipexec_validate(self.fname, out, err)
305 305
306 306 def test_run_i_after_reset(self):
307 307 """Check that %run -i still works after %reset (gh-693)"""
308 308 src = "yy = zz\n"
309 309 self.mktmp(src)
310 310 _ip.run_cell("zz = 23")
311 311 _ip.magic('run -i %s' % self.fname)
312 312 nt.assert_equal(_ip.user_ns['yy'], 23)
313 313 _ip.magic('reset -f')
314 314 _ip.run_cell("zz = 23")
315 315 _ip.magic('run -i %s' % self.fname)
316 316 nt.assert_equal(_ip.user_ns['yy'], 23)
317 317
318 318 def test_unicode(self):
319 319 """Check that files in odd encodings are accepted."""
320 320 mydir = os.path.dirname(__file__)
321 321 na = os.path.join(mydir, 'nonascii.py')
322 322 _ip.magic('run "%s"' % na)
323 323 nt.assert_equal(_ip.user_ns['u'], u'ΠŽΡ‚β„–Π€')
324 324
325 325 def test_run_py_file_attribute(self):
326 326 """Test handling of `__file__` attribute in `%run <file>.py`."""
327 327 src = "t = __file__\n"
328 328 self.mktmp(src)
329 329 _missing = object()
330 330 file1 = _ip.user_ns.get('__file__', _missing)
331 331 _ip.magic('run %s' % self.fname)
332 332 file2 = _ip.user_ns.get('__file__', _missing)
333 333
334 334 # Check that __file__ was equal to the filename in the script's
335 335 # namespace.
336 336 nt.assert_equal(_ip.user_ns['t'], self.fname)
337 337
338 338 # Check that __file__ was not leaked back into user_ns.
339 339 nt.assert_equal(file1, file2)
340 340
341 341 def test_run_ipy_file_attribute(self):
342 342 """Test handling of `__file__` attribute in `%run <file.ipy>`."""
343 343 src = "t = __file__\n"
344 344 self.mktmp(src, ext='.ipy')
345 345 _missing = object()
346 346 file1 = _ip.user_ns.get('__file__', _missing)
347 347 _ip.magic('run %s' % self.fname)
348 348 file2 = _ip.user_ns.get('__file__', _missing)
349 349
350 350 # Check that __file__ was equal to the filename in the script's
351 351 # namespace.
352 352 nt.assert_equal(_ip.user_ns['t'], self.fname)
353 353
354 354 # Check that __file__ was not leaked back into user_ns.
355 355 nt.assert_equal(file1, file2)
356 356
357 357 def test_run_formatting(self):
358 358 """ Test that %run -t -N<N> does not raise a TypeError for N > 1."""
359 359 src = "pass"
360 360 self.mktmp(src)
361 361 _ip.magic('run -t -N 1 %s' % self.fname)
362 362 _ip.magic('run -t -N 10 %s' % self.fname)
363 363
364 364 def test_ignore_sys_exit(self):
365 365 """Test the -e option to ignore sys.exit()"""
366 366 src = "import sys; sys.exit(1)"
367 367 self.mktmp(src)
368 368 with tt.AssertPrints('SystemExit'):
369 369 _ip.magic('run %s' % self.fname)
370 370
371 371 with tt.AssertNotPrints('SystemExit'):
372 372 _ip.magic('run -e %s' % self.fname)
373 373
374 374 def test_run_nb(self):
375 375 """Test %run notebook.ipynb"""
376 376 from IPython.nbformat import current
377 377 nb = current.new_notebook(
378 378 worksheets=[
379 379 current.new_worksheet(cells=[
380 current.new_text_cell("The Ultimate Question of Everything"),
380 381 current.new_code_cell("answer=42")
381 382 ])
382 383 ]
383 384 )
384 385 src = current.writes(nb, 'json')
385 386 self.mktmp(src, ext='.ipynb')
386 387
387 388 _ip.magic("run %s" % self.fname)
388 389
389 390 nt.assert_equal(_ip.user_ns['answer'], 42)
390 391
391 392
392 393
393 394 class TestMagicRunWithPackage(unittest.TestCase):
394 395
395 396 def writefile(self, name, content):
396 397 path = os.path.join(self.tempdir.name, name)
397 398 d = os.path.dirname(path)
398 399 if not os.path.isdir(d):
399 400 os.makedirs(d)
400 401 with open(path, 'w') as f:
401 402 f.write(textwrap.dedent(content))
402 403
403 404 def setUp(self):
404 405 self.package = package = 'tmp{0}'.format(repr(random.random())[2:])
405 406 """Temporary valid python package name."""
406 407
407 408 self.value = int(random.random() * 10000)
408 409
409 410 self.tempdir = TemporaryDirectory()
410 411 self.__orig_cwd = py3compat.getcwd()
411 412 sys.path.insert(0, self.tempdir.name)
412 413
413 414 self.writefile(os.path.join(package, '__init__.py'), '')
414 415 self.writefile(os.path.join(package, 'sub.py'), """
415 416 x = {0!r}
416 417 """.format(self.value))
417 418 self.writefile(os.path.join(package, 'relative.py'), """
418 419 from .sub import x
419 420 """)
420 421 self.writefile(os.path.join(package, 'absolute.py'), """
421 422 from {0}.sub import x
422 423 """.format(package))
423 424
424 425 def tearDown(self):
425 426 os.chdir(self.__orig_cwd)
426 427 sys.path[:] = [p for p in sys.path if p != self.tempdir.name]
427 428 self.tempdir.cleanup()
428 429
429 430 def check_run_submodule(self, submodule, opts=''):
430 431 _ip.user_ns.pop('x', None)
431 432 _ip.magic('run {2} -m {0}.{1}'.format(self.package, submodule, opts))
432 433 self.assertEqual(_ip.user_ns['x'], self.value,
433 434 'Variable `x` is not loaded from module `{0}`.'
434 435 .format(submodule))
435 436
436 437 def test_run_submodule_with_absolute_import(self):
437 438 self.check_run_submodule('absolute')
438 439
439 440 def test_run_submodule_with_relative_import(self):
440 441 """Run submodule that has a relative import statement (#2727)."""
441 442 self.check_run_submodule('relative')
442 443
443 444 def test_prun_submodule_with_absolute_import(self):
444 445 self.check_run_submodule('absolute', '-p')
445 446
446 447 def test_prun_submodule_with_relative_import(self):
447 448 self.check_run_submodule('relative', '-p')
448 449
449 450 def with_fake_debugger(func):
450 451 @functools.wraps(func)
451 452 def wrapper(*args, **kwds):
452 453 with tt.monkeypatch(debugger.Pdb, 'run', staticmethod(eval)):
453 454 return func(*args, **kwds)
454 455 return wrapper
455 456
456 457 @with_fake_debugger
457 458 def test_debug_run_submodule_with_absolute_import(self):
458 459 self.check_run_submodule('absolute', '-d')
459 460
460 461 @with_fake_debugger
461 462 def test_debug_run_submodule_with_relative_import(self):
462 463 self.check_run_submodule('relative', '-d')
463 464
464 465 def test_run__name__():
465 466 with TemporaryDirectory() as td:
466 467 path = pjoin(td, 'foo.py')
467 468 with open(path, 'w') as f:
468 469 f.write("q = __name__")
469 470
470 471 _ip.user_ns.pop('q', None)
471 472 _ip.magic('run {}'.format(path))
472 473 nt.assert_equal(_ip.user_ns.pop('q'), '__main__')
473 474
474 475 _ip.magic('run -n {}'.format(path))
475 476 nt.assert_equal(_ip.user_ns.pop('q'), 'foo')
General Comments 0
You need to be logged in to leave comments. Login now