##// END OF EJS Templates
revert fialing on windows
Matthias Bussonnier -
Show More
@@ -1,626 +1,626 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 import platform
21 import platform
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 os.path import join as pjoin
27 from os.path import join as pjoin
28 from unittest.mock import patch
28 from unittest.mock import patch
29
29
30 import pytest
30 import pytest
31 from tempfile import TemporaryDirectory
31 from tempfile import TemporaryDirectory
32
32
33 from IPython.core import debugger
33 from IPython.core import debugger
34 from IPython.testing import decorators as dec
34 from IPython.testing import decorators as dec
35 from IPython.testing import tools as tt
35 from IPython.testing import tools as tt
36 from IPython.utils.io import capture_output
36 from IPython.utils.io import capture_output
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', encoding='utf-8')
68 In [3]: f = open(fname, 'w', encoding='utf-8')
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 doctest_run_option_parser_for_posix.__skip_doctest__ = sys.platform == "win32"
130 doctest_run_option_parser_for_posix.__skip_doctest__ = sys.platform == "win32"
131
131
132
132
133 @dec.skip_if_not_win32
133 @dec.skip_if_not_win32
134 def doctest_run_option_parser_for_windows():
134 def doctest_run_option_parser_for_windows():
135 r"""Test option parser in %run (Windows specific).
135 r"""Test option parser in %run (Windows specific).
136
136
137 In Windows, you can't escape ``*` `by backslash:
137 In Windows, you can't escape ``*` `by backslash:
138
138
139 In [1]: %run print_argv.py print\\*.py
139 In [1]: %run print_argv.py print\\*.py
140 ['print\\\\*.py']
140 ['print\\\\*.py']
141
141
142 You can use quote to escape glob:
142 You can use quote to escape glob:
143
143
144 In [2]: %run print_argv.py 'print*.py'
144 In [2]: %run print_argv.py 'print*.py'
145 ["'print*.py'"]
145 ["'print*.py'"]
146
146
147 """
147 """
148
148
149
149
150 doctest_run_option_parser_for_windows.__skip_doctest__ = sys.platform != "win32"
150 doctest_run_option_parser_for_windows.__skip_doctest__ = sys.platform != "win32"
151
151
152
152
153 def doctest_reset_del():
153 def doctest_reset_del():
154 """Test that resetting doesn't cause errors in __del__ methods.
154 """Test that resetting doesn't cause errors in __del__ methods.
155
155
156 In [2]: class A(object):
156 In [2]: class A(object):
157 ...: def __del__(self):
157 ...: def __del__(self):
158 ...: print(str("Hi"))
158 ...: print(str("Hi"))
159 ...:
159 ...:
160
160
161 In [3]: a = A()
161 In [3]: a = A()
162
162
163 In [4]: get_ipython().reset(); import gc; x = gc.collect(0)
163 In [4]: get_ipython().reset(); import gc; x = gc.collect(0)
164 Hi
164 Hi
165
165
166 In [5]: 1+1
166 In [5]: 1+1
167 Out[5]: 2
167 Out[5]: 2
168 """
168 """
169
169
170 # For some tests, it will be handy to organize them in a class with a common
170 # For some tests, it will be handy to organize them in a class with a common
171 # setup that makes a temp file
171 # setup that makes a temp file
172
172
173 class TestMagicRunPass(tt.TempFileMixin):
173 class TestMagicRunPass(tt.TempFileMixin):
174
174
175 def setUp(self):
175 def setUp(self):
176 content = "a = [1,2,3]\nb = 1"
176 content = "a = [1,2,3]\nb = 1"
177 self.mktmp(content)
177 self.mktmp(content)
178
178
179 def run_tmpfile(self):
179 def run_tmpfile(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.run_line_magic("run", self.fname)
183 _ip.run_line_magic("run", self.fname)
184
184
185 def run_tmpfile_p(self):
185 def run_tmpfile_p(self):
186 _ip = get_ipython()
186 _ip = get_ipython()
187 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
187 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
188 # See below and ticket https://bugs.launchpad.net/bugs/366353
188 # See below and ticket https://bugs.launchpad.net/bugs/366353
189 _ip.run_line_magic("run", "-p %s" % self.fname)
189 _ip.run_line_magic("run", "-p %s" % self.fname)
190
190
191 def test_builtins_id(self):
191 def test_builtins_id(self):
192 """Check that %run doesn't damage __builtins__ """
192 """Check that %run doesn't damage __builtins__ """
193 _ip = get_ipython()
193 _ip = get_ipython()
194 # Test that the id of __builtins__ is not modified by %run
194 # Test that the id of __builtins__ is not modified by %run
195 bid1 = id(_ip.user_ns['__builtins__'])
195 bid1 = id(_ip.user_ns['__builtins__'])
196 self.run_tmpfile()
196 self.run_tmpfile()
197 bid2 = id(_ip.user_ns['__builtins__'])
197 bid2 = id(_ip.user_ns['__builtins__'])
198 assert bid1 == bid2
198 assert bid1 == bid2
199
199
200 def test_builtins_type(self):
200 def test_builtins_type(self):
201 """Check that the type of __builtins__ doesn't change with %run.
201 """Check that the type of __builtins__ doesn't change with %run.
202
202
203 However, the above could pass if __builtins__ was already modified to
203 However, the above could pass if __builtins__ was already modified to
204 be a dict (it should be a module) by a previous use of %run. So we
204 be a dict (it should be a module) by a previous use of %run. So we
205 also check explicitly that it really is a module:
205 also check explicitly that it really is a module:
206 """
206 """
207 _ip = get_ipython()
207 _ip = get_ipython()
208 self.run_tmpfile()
208 self.run_tmpfile()
209 assert type(_ip.user_ns["__builtins__"]) == type(sys)
209 assert type(_ip.user_ns["__builtins__"]) == type(sys)
210
210
211 def test_run_profile(self):
211 def test_run_profile(self):
212 """Test that the option -p, which invokes the profiler, do not
212 """Test that the option -p, which invokes the profiler, do not
213 crash by invoking execfile"""
213 crash by invoking execfile"""
214 self.run_tmpfile_p()
214 self.run_tmpfile_p()
215
215
216 def test_run_debug_twice(self):
216 def test_run_debug_twice(self):
217 # https://github.com/ipython/ipython/issues/10028
217 # https://github.com/ipython/ipython/issues/10028
218 _ip = get_ipython()
218 _ip = get_ipython()
219 with tt.fake_input(["c"]):
219 with tt.fake_input(["c"]):
220 _ip.run_line_magic("run", "-d %s" % self.fname)
220 _ip.run_line_magic("run", "-d %s" % self.fname)
221 with tt.fake_input(["c"]):
221 with tt.fake_input(["c"]):
222 _ip.run_line_magic("run", "-d %s" % self.fname)
222 _ip.run_line_magic("run", "-d %s" % self.fname)
223
223
224 def test_run_debug_twice_with_breakpoint(self):
224 def test_run_debug_twice_with_breakpoint(self):
225 """Make a valid python temp file."""
225 """Make a valid python temp file."""
226 _ip = get_ipython()
226 _ip = get_ipython()
227 with tt.fake_input(["b 2", "c", "c"]):
227 with tt.fake_input(["b 2", "c", "c"]):
228 _ip.run_line_magic("run", "-d %s" % self.fname)
228 _ip.run_line_magic("run", "-d %s" % self.fname)
229
229
230 with tt.fake_input(["c"]):
230 with tt.fake_input(["c"]):
231 with tt.AssertNotPrints("KeyError"):
231 with tt.AssertNotPrints("KeyError"):
232 _ip.run_line_magic("run", "-d %s" % self.fname)
232 _ip.run_line_magic("run", "-d %s" % self.fname)
233
233
234
234
235 class TestMagicRunSimple(tt.TempFileMixin):
235 class TestMagicRunSimple(tt.TempFileMixin):
236
236
237 def test_simpledef(self):
237 def test_simpledef(self):
238 """Test that simple class definitions work."""
238 """Test that simple class definitions work."""
239 src = ("class foo: pass\n"
239 src = ("class foo: pass\n"
240 "def f(): return foo()")
240 "def f(): return foo()")
241 self.mktmp(src)
241 self.mktmp(src)
242 _ip.run_line_magic("run", str(self.fname))
242 _ip.run_line_magic("run", str(self.fname))
243 _ip.run_cell("t = isinstance(f(), foo)")
243 _ip.run_cell("t = isinstance(f(), foo)")
244 assert _ip.user_ns["t"] is True
244 assert _ip.user_ns["t"] is True
245
245
246 @pytest.mark.xfail(
246 @pytest.mark.xfail(
247 platform.python_implementation() == "PyPy",
247 platform.python_implementation() == "PyPy",
248 reason="expecting __del__ call on exit is unreliable and doesn't happen on PyPy",
248 reason="expecting __del__ call on exit is unreliable and doesn't happen on PyPy",
249 )
249 )
250 def test_obj_del(self):
250 def test_obj_del(self):
251 """Test that object's __del__ methods are called on exit."""
251 """Test that object's __del__ methods are called on exit."""
252 src = ("class A(object):\n"
252 src = ("class A(object):\n"
253 " def __del__(self):\n"
253 " def __del__(self):\n"
254 " print('object A deleted')\n"
254 " print('object A deleted')\n"
255 "a = A()\n")
255 "a = A()\n")
256 self.mktmp(src)
256 self.mktmp(src)
257 err = None
257 err = None
258 tt.ipexec_validate(self.fname, 'object A deleted', err)
258 tt.ipexec_validate(self.fname, 'object A deleted', err)
259
259
260 def test_aggressive_namespace_cleanup(self):
260 def test_aggressive_namespace_cleanup(self):
261 """Test that namespace cleanup is not too aggressive GH-238
261 """Test that namespace cleanup is not too aggressive GH-238
262
262
263 Returning from another run magic deletes the namespace"""
263 Returning from another run magic deletes the namespace"""
264 # see ticket https://github.com/ipython/ipython/issues/238
264 # see ticket https://github.com/ipython/ipython/issues/238
265
265
266 with tt.TempFileMixin() as empty:
266 with tt.TempFileMixin() as empty:
267 empty.mktmp("")
267 empty.mktmp("")
268 # 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
269 # repr so that the \u becomes \\u.
269 # repr so that the \u becomes \\u.
270 src = (
270 src = (
271 "ip = get_ipython()\n"
271 "ip = get_ipython()\n"
272 "for i in range(5):\n"
272 "for i in range(5):\n"
273 " try:\n"
273 " try:\n"
274 " ip.magic(%r)\n"
274 " ip.magic(%r)\n"
275 " except NameError as e:\n"
275 " except NameError as e:\n"
276 " print(i)\n"
276 " print(i)\n"
277 " break\n" % ("run " + empty.fname)
277 " break\n" % ("run " + empty.fname)
278 )
278 )
279 self.mktmp(src)
279 self.mktmp(src)
280 _ip.run_line_magic("run", str(self.fname))
280 _ip.run_line_magic("run", str(self.fname))
281 _ip.run_cell("ip == get_ipython()")
281 _ip.run_cell("ip == get_ipython()")
282 assert _ip.user_ns["i"] == 4
282 assert _ip.user_ns["i"] == 4
283
283
284 def test_run_second(self):
284 def test_run_second(self):
285 """Test that running a second file doesn't clobber the first, gh-3547"""
285 """Test that running a second file doesn't clobber the first, gh-3547"""
286 self.mktmp("avar = 1\n" "def afunc():\n" " return avar\n")
286 self.mktmp("avar = 1\n" "def afunc():\n" " return avar\n")
287
287
288 with tt.TempFileMixin() as empty:
288 with tt.TempFileMixin() as empty:
289 empty.mktmp("")
289 empty.mktmp("")
290
290
291 _ip.run_line_magic("run", self.fname)
291 _ip.run_line_magic("run", self.fname)
292 _ip.run_line_magic("run", empty.fname)
292 _ip.run_line_magic("run", empty.fname)
293 assert _ip.user_ns["afunc"]() == 1
293 assert _ip.user_ns["afunc"]() == 1
294
294
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 = f"""\
298 src = f"""\
299 import gc
299 import gc
300 %run "{tc}" C-first
300 %run "{tc}" C-first
301 gc.collect(0)
301 gc.collect(0)
302 %run "{tc}" C-second
302 %run "{tc}" C-second
303 gc.collect(0)
303 gc.collect(0)
304 %run "{tc}" C-third
304 %run "{tc}" C-third
305 gc.collect(0)
305 gc.collect(0)
306 %reset -f
306 %reset -f
307 """
307 """
308 self.mktmp(src, ".ipy")
308 self.mktmp(src, ".ipy")
309 out = """\
309 out = """\
310 ARGV 1-: ['C-first']
310 ARGV 1-: ['C-first']
311 ARGV 1-: ['C-second']
311 ARGV 1-: ['C-second']
312 tclass.py: deleting object: C-first
312 tclass.py: deleting object: C-first
313 ARGV 1-: ['C-third']
313 ARGV 1-: ['C-third']
314 tclass.py: deleting object: C-second
314 tclass.py: deleting object: C-second
315 tclass.py: deleting object: C-third
315 tclass.py: deleting object: C-third
316 """
316 """
317 err = None
317 err = None
318 tt.ipexec_validate(self.fname, out, err)
318 tt.ipexec_validate(self.fname, out, err)
319
319
320 def test_run_i_after_reset(self):
320 def test_run_i_after_reset(self):
321 """Check that %run -i still works after %reset (gh-693)"""
321 """Check that %run -i still works after %reset (gh-693)"""
322 src = "yy = zz\n"
322 src = "yy = zz\n"
323 self.mktmp(src)
323 self.mktmp(src)
324 _ip.run_cell("zz = 23")
324 _ip.run_cell("zz = 23")
325 try:
325 try:
326 _ip.run_line_magic("run", "-i %s" % self.fname)
326 _ip.run_line_magic("run", "-i %s" % self.fname)
327 assert _ip.user_ns["yy"] == 23
327 assert _ip.user_ns["yy"] == 23
328 finally:
328 finally:
329 _ip.run_line_magic("reset", "-f")
329 _ip.run_line_magic("reset", "-f")
330
330
331 _ip.run_cell("zz = 23")
331 _ip.run_cell("zz = 23")
332 try:
332 try:
333 _ip.run_line_magic("run", "-i %s" % self.fname)
333 _ip.run_line_magic("run", "-i %s" % self.fname)
334 assert _ip.user_ns["yy"] == 23
334 assert _ip.user_ns["yy"] == 23
335 finally:
335 finally:
336 _ip.run_line_magic("reset", "-f")
336 _ip.run_line_magic("reset", "-f")
337
337
338 def test_unicode(self):
338 def test_unicode(self):
339 """Check that files in odd encodings are accepted."""
339 """Check that files in odd encodings are accepted."""
340 mydir = os.path.dirname(__file__)
340 mydir = os.path.dirname(__file__)
341 na = os.path.join(mydir, "nonascii.py")
341 na = os.path.join(mydir, "nonascii.py")
342 _ip.run_line_magic("run", "%r" % na)
342 _ip.magic('run "%s"' % na)
343 assert _ip.user_ns["u"] == "ΠŽΡ‚β„–Π€"
343 assert _ip.user_ns["u"] == "ΠŽΡ‚β„–Π€"
344
344
345 def test_run_py_file_attribute(self):
345 def test_run_py_file_attribute(self):
346 """Test handling of `__file__` attribute in `%run <file>.py`."""
346 """Test handling of `__file__` attribute in `%run <file>.py`."""
347 src = "t = __file__\n"
347 src = "t = __file__\n"
348 self.mktmp(src)
348 self.mktmp(src)
349 _missing = object()
349 _missing = object()
350 file1 = _ip.user_ns.get("__file__", _missing)
350 file1 = _ip.user_ns.get("__file__", _missing)
351 _ip.run_line_magic("run", self.fname)
351 _ip.run_line_magic("run", self.fname)
352 file2 = _ip.user_ns.get("__file__", _missing)
352 file2 = _ip.user_ns.get("__file__", _missing)
353
353
354 # Check that __file__ was equal to the filename in the script's
354 # Check that __file__ was equal to the filename in the script's
355 # namespace.
355 # namespace.
356 assert _ip.user_ns["t"] == self.fname
356 assert _ip.user_ns["t"] == self.fname
357
357
358 # Check that __file__ was not leaked back into user_ns.
358 # Check that __file__ was not leaked back into user_ns.
359 assert file1 == file2
359 assert file1 == file2
360
360
361 def test_run_ipy_file_attribute(self):
361 def test_run_ipy_file_attribute(self):
362 """Test handling of `__file__` attribute in `%run <file.ipy>`."""
362 """Test handling of `__file__` attribute in `%run <file.ipy>`."""
363 src = "t = __file__\n"
363 src = "t = __file__\n"
364 self.mktmp(src, ext='.ipy')
364 self.mktmp(src, ext='.ipy')
365 _missing = object()
365 _missing = object()
366 file1 = _ip.user_ns.get("__file__", _missing)
366 file1 = _ip.user_ns.get("__file__", _missing)
367 _ip.run_line_magic("run", self.fname)
367 _ip.run_line_magic("run", self.fname)
368 file2 = _ip.user_ns.get("__file__", _missing)
368 file2 = _ip.user_ns.get("__file__", _missing)
369
369
370 # Check that __file__ was equal to the filename in the script's
370 # Check that __file__ was equal to the filename in the script's
371 # namespace.
371 # namespace.
372 assert _ip.user_ns["t"] == self.fname
372 assert _ip.user_ns["t"] == self.fname
373
373
374 # Check that __file__ was not leaked back into user_ns.
374 # Check that __file__ was not leaked back into user_ns.
375 assert file1 == file2
375 assert file1 == file2
376
376
377 def test_run_formatting(self):
377 def test_run_formatting(self):
378 """ Test that %run -t -N<N> does not raise a TypeError for N > 1."""
378 """ Test that %run -t -N<N> does not raise a TypeError for N > 1."""
379 src = "pass"
379 src = "pass"
380 self.mktmp(src)
380 self.mktmp(src)
381 _ip.run_line_magic("run", "-t -N 1 %s" % self.fname)
381 _ip.run_line_magic("run", "-t -N 1 %s" % self.fname)
382 _ip.run_line_magic("run", "-t -N 10 %s" % self.fname)
382 _ip.run_line_magic("run", "-t -N 10 %s" % self.fname)
383
383
384 def test_ignore_sys_exit(self):
384 def test_ignore_sys_exit(self):
385 """Test the -e option to ignore sys.exit()"""
385 """Test the -e option to ignore sys.exit()"""
386 src = "import sys; sys.exit(1)"
386 src = "import sys; sys.exit(1)"
387 self.mktmp(src)
387 self.mktmp(src)
388 with tt.AssertPrints("SystemExit"):
388 with tt.AssertPrints("SystemExit"):
389 _ip.run_line_magic("run", self.fname)
389 _ip.run_line_magic("run", self.fname)
390
390
391 with tt.AssertNotPrints("SystemExit"):
391 with tt.AssertNotPrints("SystemExit"):
392 _ip.run_line_magic("run", "-e %s" % self.fname)
392 _ip.run_line_magic("run", "-e %s" % self.fname)
393
393
394 def test_run_nb(self):
394 def test_run_nb(self):
395 """Test %run notebook.ipynb"""
395 """Test %run notebook.ipynb"""
396 pytest.importorskip("nbformat")
396 pytest.importorskip("nbformat")
397 from nbformat import v4, writes
397 from nbformat import v4, writes
398 nb = v4.new_notebook(
398 nb = v4.new_notebook(
399 cells=[
399 cells=[
400 v4.new_markdown_cell("The Ultimate Question of Everything"),
400 v4.new_markdown_cell("The Ultimate Question of Everything"),
401 v4.new_code_cell("answer=42")
401 v4.new_code_cell("answer=42")
402 ]
402 ]
403 )
403 )
404 src = writes(nb, version=4)
404 src = writes(nb, version=4)
405 self.mktmp(src, ext='.ipynb')
405 self.mktmp(src, ext='.ipynb')
406
406
407 _ip.run_line_magic("run", self.fname)
407 _ip.run_line_magic("run", self.fname)
408
408
409 assert _ip.user_ns["answer"] == 42
409 assert _ip.user_ns["answer"] == 42
410
410
411 def test_run_nb_error(self):
411 def test_run_nb_error(self):
412 """Test %run notebook.ipynb error"""
412 """Test %run notebook.ipynb error"""
413 pytest.importorskip("nbformat")
413 pytest.importorskip("nbformat")
414 from nbformat import v4, writes
414 from nbformat import v4, writes
415
415
416 # %run when a file name isn't provided
416 # %run when a file name isn't provided
417 pytest.raises(Exception, _ip.magic, "run")
417 pytest.raises(Exception, _ip.magic, "run")
418
418
419 # %run when a file doesn't exist
419 # %run when a file doesn't exist
420 pytest.raises(Exception, _ip.magic, "run foobar.ipynb")
420 pytest.raises(Exception, _ip.magic, "run foobar.ipynb")
421
421
422 # %run on a notebook with an error
422 # %run on a notebook with an error
423 nb = v4.new_notebook(
423 nb = v4.new_notebook(
424 cells=[
424 cells=[
425 v4.new_code_cell("0/0")
425 v4.new_code_cell("0/0")
426 ]
426 ]
427 )
427 )
428 src = writes(nb, version=4)
428 src = writes(nb, version=4)
429 self.mktmp(src, ext='.ipynb')
429 self.mktmp(src, ext='.ipynb')
430 pytest.raises(Exception, _ip.magic, "run %s" % self.fname)
430 pytest.raises(Exception, _ip.magic, "run %s" % self.fname)
431
431
432 def test_file_options(self):
432 def test_file_options(self):
433 src = ('import sys\n'
433 src = ('import sys\n'
434 'a = " ".join(sys.argv[1:])\n')
434 'a = " ".join(sys.argv[1:])\n')
435 self.mktmp(src)
435 self.mktmp(src)
436 test_opts = "-x 3 --verbose"
436 test_opts = "-x 3 --verbose"
437 _ip.run_line_magic("run", "{0} {1}".format(self.fname, test_opts))
437 _ip.run_line_magic("run", "{0} {1}".format(self.fname, test_opts))
438 assert _ip.user_ns["a"] == test_opts
438 assert _ip.user_ns["a"] == test_opts
439
439
440
440
441 class TestMagicRunWithPackage(unittest.TestCase):
441 class TestMagicRunWithPackage(unittest.TestCase):
442
442
443 def writefile(self, name, content):
443 def writefile(self, name, content):
444 path = os.path.join(self.tempdir.name, name)
444 path = os.path.join(self.tempdir.name, name)
445 d = os.path.dirname(path)
445 d = os.path.dirname(path)
446 if not os.path.isdir(d):
446 if not os.path.isdir(d):
447 os.makedirs(d)
447 os.makedirs(d)
448 with open(path, "w", encoding="utf-8") as f:
448 with open(path, "w", encoding="utf-8") as f:
449 f.write(textwrap.dedent(content))
449 f.write(textwrap.dedent(content))
450
450
451 def setUp(self):
451 def setUp(self):
452 self.package = package = 'tmp{0}'.format(''.join([random.choice(string.ascii_letters) for i in range(10)]))
452 self.package = package = 'tmp{0}'.format(''.join([random.choice(string.ascii_letters) for i in range(10)]))
453 """Temporary (probably) valid python package name."""
453 """Temporary (probably) valid python package name."""
454
454
455 self.value = int(random.random() * 10000)
455 self.value = int(random.random() * 10000)
456
456
457 self.tempdir = TemporaryDirectory()
457 self.tempdir = TemporaryDirectory()
458 self.__orig_cwd = os.getcwd()
458 self.__orig_cwd = os.getcwd()
459 sys.path.insert(0, self.tempdir.name)
459 sys.path.insert(0, self.tempdir.name)
460
460
461 self.writefile(os.path.join(package, '__init__.py'), '')
461 self.writefile(os.path.join(package, '__init__.py'), '')
462 self.writefile(os.path.join(package, 'sub.py'), """
462 self.writefile(os.path.join(package, 'sub.py'), """
463 x = {0!r}
463 x = {0!r}
464 """.format(self.value))
464 """.format(self.value))
465 self.writefile(os.path.join(package, 'relative.py'), """
465 self.writefile(os.path.join(package, 'relative.py'), """
466 from .sub import x
466 from .sub import x
467 """)
467 """)
468 self.writefile(os.path.join(package, 'absolute.py'), """
468 self.writefile(os.path.join(package, 'absolute.py'), """
469 from {0}.sub import x
469 from {0}.sub import x
470 """.format(package))
470 """.format(package))
471 self.writefile(os.path.join(package, 'args.py'), """
471 self.writefile(os.path.join(package, 'args.py'), """
472 import sys
472 import sys
473 a = " ".join(sys.argv[1:])
473 a = " ".join(sys.argv[1:])
474 """.format(package))
474 """.format(package))
475
475
476 def tearDown(self):
476 def tearDown(self):
477 os.chdir(self.__orig_cwd)
477 os.chdir(self.__orig_cwd)
478 sys.path[:] = [p for p in sys.path if p != self.tempdir.name]
478 sys.path[:] = [p for p in sys.path if p != self.tempdir.name]
479 self.tempdir.cleanup()
479 self.tempdir.cleanup()
480
480
481 def check_run_submodule(self, submodule, opts=""):
481 def check_run_submodule(self, submodule, opts=""):
482 _ip.user_ns.pop("x", None)
482 _ip.user_ns.pop("x", None)
483 _ip.run_line_magic(
483 _ip.run_line_magic(
484 "run", "{2} -m {0}.{1}".format(self.package, submodule, opts)
484 "run", "{2} -m {0}.{1}".format(self.package, submodule, opts)
485 )
485 )
486 self.assertEqual(
486 self.assertEqual(
487 _ip.user_ns["x"],
487 _ip.user_ns["x"],
488 self.value,
488 self.value,
489 "Variable `x` is not loaded from module `{0}`.".format(submodule),
489 "Variable `x` is not loaded from module `{0}`.".format(submodule),
490 )
490 )
491
491
492 def test_run_submodule_with_absolute_import(self):
492 def test_run_submodule_with_absolute_import(self):
493 self.check_run_submodule('absolute')
493 self.check_run_submodule('absolute')
494
494
495 def test_run_submodule_with_relative_import(self):
495 def test_run_submodule_with_relative_import(self):
496 """Run submodule that has a relative import statement (#2727)."""
496 """Run submodule that has a relative import statement (#2727)."""
497 self.check_run_submodule('relative')
497 self.check_run_submodule('relative')
498
498
499 def test_prun_submodule_with_absolute_import(self):
499 def test_prun_submodule_with_absolute_import(self):
500 self.check_run_submodule('absolute', '-p')
500 self.check_run_submodule('absolute', '-p')
501
501
502 def test_prun_submodule_with_relative_import(self):
502 def test_prun_submodule_with_relative_import(self):
503 self.check_run_submodule('relative', '-p')
503 self.check_run_submodule('relative', '-p')
504
504
505 def with_fake_debugger(func):
505 def with_fake_debugger(func):
506 @functools.wraps(func)
506 @functools.wraps(func)
507 def wrapper(*args, **kwds):
507 def wrapper(*args, **kwds):
508 with patch.object(debugger.Pdb, 'run', staticmethod(eval)):
508 with patch.object(debugger.Pdb, 'run', staticmethod(eval)):
509 return func(*args, **kwds)
509 return func(*args, **kwds)
510 return wrapper
510 return wrapper
511
511
512 @with_fake_debugger
512 @with_fake_debugger
513 def test_debug_run_submodule_with_absolute_import(self):
513 def test_debug_run_submodule_with_absolute_import(self):
514 self.check_run_submodule('absolute', '-d')
514 self.check_run_submodule('absolute', '-d')
515
515
516 @with_fake_debugger
516 @with_fake_debugger
517 def test_debug_run_submodule_with_relative_import(self):
517 def test_debug_run_submodule_with_relative_import(self):
518 self.check_run_submodule('relative', '-d')
518 self.check_run_submodule('relative', '-d')
519
519
520 def test_module_options(self):
520 def test_module_options(self):
521 _ip.user_ns.pop("a", None)
521 _ip.user_ns.pop("a", None)
522 test_opts = "-x abc -m test"
522 test_opts = "-x abc -m test"
523 _ip.run_line_magic("run", "-m {0}.args {1}".format(self.package, test_opts))
523 _ip.run_line_magic("run", "-m {0}.args {1}".format(self.package, test_opts))
524 assert _ip.user_ns["a"] == test_opts
524 assert _ip.user_ns["a"] == test_opts
525
525
526 def test_module_options_with_separator(self):
526 def test_module_options_with_separator(self):
527 _ip.user_ns.pop("a", None)
527 _ip.user_ns.pop("a", None)
528 test_opts = "-x abc -m test"
528 test_opts = "-x abc -m test"
529 _ip.run_line_magic("run", "-m {0}.args -- {1}".format(self.package, test_opts))
529 _ip.run_line_magic("run", "-m {0}.args -- {1}".format(self.package, test_opts))
530 assert _ip.user_ns["a"] == test_opts
530 assert _ip.user_ns["a"] == test_opts
531
531
532
532
533 def test_run__name__():
533 def test_run__name__():
534 with TemporaryDirectory() as td:
534 with TemporaryDirectory() as td:
535 path = pjoin(td, "foo.py")
535 path = pjoin(td, "foo.py")
536 with open(path, "w", encoding="utf-8") as f:
536 with open(path, "w", encoding="utf-8") as f:
537 f.write("q = __name__")
537 f.write("q = __name__")
538
538
539 _ip.user_ns.pop("q", None)
539 _ip.user_ns.pop("q", None)
540 _ip.run_line_magic("run", "{}".format(path))
540 _ip.run_line_magic("run", "{}".format(path))
541 assert _ip.user_ns.pop("q") == "__main__"
541 assert _ip.user_ns.pop("q") == "__main__"
542
542
543 _ip.run_line_magic("run", "-n {}".format(path))
543 _ip.run_line_magic("run", "-n {}".format(path))
544 assert _ip.user_ns.pop("q") == "foo"
544 assert _ip.user_ns.pop("q") == "foo"
545
545
546 try:
546 try:
547 _ip.run_line_magic("run", "-i -n {}".format(path))
547 _ip.run_line_magic("run", "-i -n {}".format(path))
548 assert _ip.user_ns.pop("q") == "foo"
548 assert _ip.user_ns.pop("q") == "foo"
549 finally:
549 finally:
550 _ip.run_line_magic("reset", "-f")
550 _ip.run_line_magic("reset", "-f")
551
551
552
552
553 def test_run_tb():
553 def test_run_tb():
554 """Test traceback offset in %run"""
554 """Test traceback offset in %run"""
555 with TemporaryDirectory() as td:
555 with TemporaryDirectory() as td:
556 path = pjoin(td, "foo.py")
556 path = pjoin(td, "foo.py")
557 with open(path, "w", encoding="utf-8") as f:
557 with open(path, "w", encoding="utf-8") as f:
558 f.write(
558 f.write(
559 "\n".join(
559 "\n".join(
560 [
560 [
561 "def foo():",
561 "def foo():",
562 " return bar()",
562 " return bar()",
563 "def bar():",
563 "def bar():",
564 " raise RuntimeError('hello!')",
564 " raise RuntimeError('hello!')",
565 "foo()",
565 "foo()",
566 ]
566 ]
567 )
567 )
568 )
568 )
569 with capture_output() as io:
569 with capture_output() as io:
570 _ip.run_line_magic("run", "{}".format(path))
570 _ip.run_line_magic("run", "{}".format(path))
571 out = io.stdout
571 out = io.stdout
572 assert "execfile" not in out
572 assert "execfile" not in out
573 assert "RuntimeError" in out
573 assert "RuntimeError" in out
574 assert out.count("---->") == 3
574 assert out.count("---->") == 3
575 del ip.user_ns['bar']
575 del ip.user_ns['bar']
576 del ip.user_ns['foo']
576 del ip.user_ns['foo']
577
577
578
578
579 def test_multiprocessing_run():
579 def test_multiprocessing_run():
580 """Set we can run mutiprocesgin without messing up up main namespace
580 """Set we can run mutiprocesgin without messing up up main namespace
581
581
582 Note that import `nose.tools as nt` mdify the value s
582 Note that import `nose.tools as nt` mdify the value s
583 sys.module['__mp_main__'] so we need to temporarily set it to None to test
583 sys.module['__mp_main__'] so we need to temporarily set it to None to test
584 the issue.
584 the issue.
585 """
585 """
586 with TemporaryDirectory() as td:
586 with TemporaryDirectory() as td:
587 mpm = sys.modules.get('__mp_main__')
587 mpm = sys.modules.get('__mp_main__')
588 sys.modules['__mp_main__'] = None
588 sys.modules['__mp_main__'] = None
589 try:
589 try:
590 path = pjoin(td, "test.py")
590 path = pjoin(td, "test.py")
591 with open(path, "w", encoding="utf-8") as f:
591 with open(path, "w", encoding="utf-8") as f:
592 f.write("import multiprocessing\nprint('hoy')")
592 f.write("import multiprocessing\nprint('hoy')")
593 with capture_output() as io:
593 with capture_output() as io:
594 _ip.run_line_magic('run', path)
594 _ip.run_line_magic('run', path)
595 _ip.run_cell("i_m_undefined")
595 _ip.run_cell("i_m_undefined")
596 out = io.stdout
596 out = io.stdout
597 assert "hoy" in out
597 assert "hoy" in out
598 assert "AttributeError" not in out
598 assert "AttributeError" not in out
599 assert "NameError" in out
599 assert "NameError" in out
600 assert out.count("---->") == 1
600 assert out.count("---->") == 1
601 except:
601 except:
602 raise
602 raise
603 finally:
603 finally:
604 sys.modules['__mp_main__'] = mpm
604 sys.modules['__mp_main__'] = mpm
605
605
606
606
607 def test_script_tb():
607 def test_script_tb():
608 """Test traceback offset in `ipython script.py`"""
608 """Test traceback offset in `ipython script.py`"""
609 with TemporaryDirectory() as td:
609 with TemporaryDirectory() as td:
610 path = pjoin(td, "foo.py")
610 path = pjoin(td, "foo.py")
611 with open(path, "w", encoding="utf-8") as f:
611 with open(path, "w", encoding="utf-8") as f:
612 f.write(
612 f.write(
613 "\n".join(
613 "\n".join(
614 [
614 [
615 "def foo():",
615 "def foo():",
616 " return bar()",
616 " return bar()",
617 "def bar():",
617 "def bar():",
618 " raise RuntimeError('hello!')",
618 " raise RuntimeError('hello!')",
619 "foo()",
619 "foo()",
620 ]
620 ]
621 )
621 )
622 )
622 )
623 out, err = tt.ipexec(path)
623 out, err = tt.ipexec(path)
624 assert "execfile" not in out
624 assert "execfile" not in out
625 assert "RuntimeError" in out
625 assert "RuntimeError" in out
626 assert out.count("---->") == 3
626 assert out.count("---->") == 3
General Comments 0
You need to be logged in to leave comments. Login now