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