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