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