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