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