##// END OF EJS Templates
rlmv - Added test for issue #2784...
Robert Marchman -
Show More
@@ -1,332 +1,339 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 from __future__ import absolute_import
10 from __future__ import absolute_import
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 import os
16 import os
17 import sys
17 import sys
18 import tempfile
18 import tempfile
19
19
20 import nose.tools as nt
20 import nose.tools as nt
21 from nose import SkipTest
21 from nose import SkipTest
22
22
23 from IPython.testing import decorators as dec
23 from IPython.testing import decorators as dec
24 from IPython.testing import tools as tt
24 from IPython.testing import tools as tt
25 from IPython.utils import py3compat
25 from IPython.utils import py3compat
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Test functions begin
28 # Test functions begin
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30
30
31 def doctest_refbug():
31 def doctest_refbug():
32 """Very nasty problem with references held by multiple runs of a script.
32 """Very nasty problem with references held by multiple runs of a script.
33 See: https://github.com/ipython/ipython/issues/141
33 See: https://github.com/ipython/ipython/issues/141
34
34
35 In [1]: _ip.clear_main_mod_cache()
35 In [1]: _ip.clear_main_mod_cache()
36 # random
36 # random
37
37
38 In [2]: %run refbug
38 In [2]: %run refbug
39
39
40 In [3]: call_f()
40 In [3]: call_f()
41 lowercased: hello
41 lowercased: hello
42
42
43 In [4]: %run refbug
43 In [4]: %run refbug
44
44
45 In [5]: call_f()
45 In [5]: call_f()
46 lowercased: hello
46 lowercased: hello
47 lowercased: hello
47 lowercased: hello
48 """
48 """
49
49
50
50
51 def doctest_run_builtins():
51 def doctest_run_builtins():
52 r"""Check that %run doesn't damage __builtins__.
52 r"""Check that %run doesn't damage __builtins__.
53
53
54 In [1]: import tempfile
54 In [1]: import tempfile
55
55
56 In [2]: bid1 = id(__builtins__)
56 In [2]: bid1 = id(__builtins__)
57
57
58 In [3]: fname = tempfile.mkstemp('.py')[1]
58 In [3]: fname = tempfile.mkstemp('.py')[1]
59
59
60 In [3]: f = open(fname,'w')
60 In [3]: f = open(fname,'w')
61
61
62 In [4]: dummy= f.write('pass\n')
62 In [4]: dummy= f.write('pass\n')
63
63
64 In [5]: f.flush()
64 In [5]: f.flush()
65
65
66 In [6]: t1 = type(__builtins__)
66 In [6]: t1 = type(__builtins__)
67
67
68 In [7]: %run $fname
68 In [7]: %run $fname
69
69
70 In [7]: f.close()
70 In [7]: f.close()
71
71
72 In [8]: bid2 = id(__builtins__)
72 In [8]: bid2 = id(__builtins__)
73
73
74 In [9]: t2 = type(__builtins__)
74 In [9]: t2 = type(__builtins__)
75
75
76 In [10]: t1 == t2
76 In [10]: t1 == t2
77 Out[10]: True
77 Out[10]: True
78
78
79 In [10]: bid1 == bid2
79 In [10]: bid1 == bid2
80 Out[10]: True
80 Out[10]: True
81
81
82 In [12]: try:
82 In [12]: try:
83 ....: os.unlink(fname)
83 ....: os.unlink(fname)
84 ....: except:
84 ....: except:
85 ....: pass
85 ....: pass
86 ....:
86 ....:
87 """
87 """
88
88
89
89
90 def doctest_run_option_parser():
90 def doctest_run_option_parser():
91 r"""Test option parser in %run.
91 r"""Test option parser in %run.
92
92
93 In [1]: %run print_argv.py
93 In [1]: %run print_argv.py
94 []
94 []
95
95
96 In [2]: %run print_argv.py print*.py
96 In [2]: %run print_argv.py print*.py
97 ['print_argv.py']
97 ['print_argv.py']
98
98
99 In [3]: %run -G print_argv.py print*.py
99 In [3]: %run -G print_argv.py print*.py
100 ['print*.py']
100 ['print*.py']
101
101
102 """
102 """
103
103
104
104
105 @dec.skip_win32
105 @dec.skip_win32
106 def doctest_run_option_parser_for_posix():
106 def doctest_run_option_parser_for_posix():
107 r"""Test option parser in %run (Linux/OSX specific).
107 r"""Test option parser in %run (Linux/OSX specific).
108
108
109 You need double quote to escape glob in POSIX systems:
109 You need double quote to escape glob in POSIX systems:
110
110
111 In [1]: %run print_argv.py print\\*.py
111 In [1]: %run print_argv.py print\\*.py
112 ['print*.py']
112 ['print*.py']
113
113
114 You can't use quote to escape glob in POSIX systems:
114 You can't use quote to escape glob in POSIX systems:
115
115
116 In [2]: %run print_argv.py 'print*.py'
116 In [2]: %run print_argv.py 'print*.py'
117 ['print_argv.py']
117 ['print_argv.py']
118
118
119 """
119 """
120
120
121
121
122 @dec.skip_if_not_win32
122 @dec.skip_if_not_win32
123 def doctest_run_option_parser_for_windows():
123 def doctest_run_option_parser_for_windows():
124 r"""Test option parser in %run (Windows specific).
124 r"""Test option parser in %run (Windows specific).
125
125
126 In Windows, you can't escape ``*` `by backslash:
126 In Windows, you can't escape ``*` `by backslash:
127
127
128 In [1]: %run print_argv.py print\\*.py
128 In [1]: %run print_argv.py print\\*.py
129 ['print\\*.py']
129 ['print\\*.py']
130
130
131 You can use quote to escape glob:
131 You can use quote to escape glob:
132
132
133 In [2]: %run print_argv.py 'print*.py'
133 In [2]: %run print_argv.py 'print*.py'
134 ['print*.py']
134 ['print*.py']
135
135
136 """
136 """
137
137
138
138
139 @py3compat.doctest_refactor_print
139 @py3compat.doctest_refactor_print
140 def doctest_reset_del():
140 def doctest_reset_del():
141 """Test that resetting doesn't cause errors in __del__ methods.
141 """Test that resetting doesn't cause errors in __del__ methods.
142
142
143 In [2]: class A(object):
143 In [2]: class A(object):
144 ...: def __del__(self):
144 ...: def __del__(self):
145 ...: print str("Hi")
145 ...: print str("Hi")
146 ...:
146 ...:
147
147
148 In [3]: a = A()
148 In [3]: a = A()
149
149
150 In [4]: get_ipython().reset()
150 In [4]: get_ipython().reset()
151 Hi
151 Hi
152
152
153 In [5]: 1+1
153 In [5]: 1+1
154 Out[5]: 2
154 Out[5]: 2
155 """
155 """
156
156
157 # For some tests, it will be handy to organize them in a class with a common
157 # For some tests, it will be handy to organize them in a class with a common
158 # setup that makes a temp file
158 # setup that makes a temp file
159
159
160 class TestMagicRunPass(tt.TempFileMixin):
160 class TestMagicRunPass(tt.TempFileMixin):
161
161
162 def setup(self):
162 def setup(self):
163 """Make a valid python temp file."""
163 """Make a valid python temp file."""
164 self.mktmp('pass\n')
164 self.mktmp('pass\n')
165
165
166 def run_tmpfile(self):
166 def run_tmpfile(self):
167 _ip = get_ipython()
167 _ip = get_ipython()
168 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
168 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
169 # See below and ticket https://bugs.launchpad.net/bugs/366353
169 # See below and ticket https://bugs.launchpad.net/bugs/366353
170 _ip.magic('run %s' % self.fname)
170 _ip.magic('run %s' % self.fname)
171
171
172 def run_tmpfile_p(self):
172 def run_tmpfile_p(self):
173 _ip = get_ipython()
173 _ip = get_ipython()
174 # 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.
175 # See below and ticket https://bugs.launchpad.net/bugs/366353
175 # See below and ticket https://bugs.launchpad.net/bugs/366353
176 _ip.magic('run -p %s' % self.fname)
176 _ip.magic('run -p %s' % self.fname)
177
177
178 def test_builtins_id(self):
178 def test_builtins_id(self):
179 """Check that %run doesn't damage __builtins__ """
179 """Check that %run doesn't damage __builtins__ """
180 _ip = get_ipython()
180 _ip = get_ipython()
181 # Test that the id of __builtins__ is not modified by %run
181 # Test that the id of __builtins__ is not modified by %run
182 bid1 = id(_ip.user_ns['__builtins__'])
182 bid1 = id(_ip.user_ns['__builtins__'])
183 self.run_tmpfile()
183 self.run_tmpfile()
184 bid2 = id(_ip.user_ns['__builtins__'])
184 bid2 = id(_ip.user_ns['__builtins__'])
185 nt.assert_equal(bid1, bid2)
185 nt.assert_equal(bid1, bid2)
186
186
187 def test_builtins_type(self):
187 def test_builtins_type(self):
188 """Check that the type of __builtins__ doesn't change with %run.
188 """Check that the type of __builtins__ doesn't change with %run.
189
189
190 However, the above could pass if __builtins__ was already modified to
190 However, the above could pass if __builtins__ was already modified to
191 be a dict (it should be a module) by a previous use of %run. So we
191 be a dict (it should be a module) by a previous use of %run. So we
192 also check explicitly that it really is a module:
192 also check explicitly that it really is a module:
193 """
193 """
194 _ip = get_ipython()
194 _ip = get_ipython()
195 self.run_tmpfile()
195 self.run_tmpfile()
196 nt.assert_equal(type(_ip.user_ns['__builtins__']),type(sys))
196 nt.assert_equal(type(_ip.user_ns['__builtins__']),type(sys))
197
197
198 def test_prompts(self):
198 def test_prompts(self):
199 """Test that prompts correctly generate after %run"""
199 """Test that prompts correctly generate after %run"""
200 self.run_tmpfile()
200 self.run_tmpfile()
201 _ip = get_ipython()
201 _ip = get_ipython()
202 p2 = _ip.prompt_manager.render('in2').strip()
202 p2 = _ip.prompt_manager.render('in2').strip()
203 nt.assert_equal(p2[:3], '...')
203 nt.assert_equal(p2[:3], '...')
204
204
205 def test_run_profile( self ):
205 def test_run_profile( self ):
206 """Test that the option -p, which invokes the profiler, do not
206 """Test that the option -p, which invokes the profiler, do not
207 crash by invoking execfile"""
207 crash by invoking execfile"""
208 _ip = get_ipython()
208 _ip = get_ipython()
209 self.run_tmpfile_p()
209 self.run_tmpfile_p()
210
210
211
211
212 class TestMagicRunSimple(tt.TempFileMixin):
212 class TestMagicRunSimple(tt.TempFileMixin):
213
213
214 def test_simpledef(self):
214 def test_simpledef(self):
215 """Test that simple class definitions work."""
215 """Test that simple class definitions work."""
216 src = ("class foo: pass\n"
216 src = ("class foo: pass\n"
217 "def f(): return foo()")
217 "def f(): return foo()")
218 self.mktmp(src)
218 self.mktmp(src)
219 _ip.magic('run %s' % self.fname)
219 _ip.magic('run %s' % self.fname)
220 _ip.run_cell('t = isinstance(f(), foo)')
220 _ip.run_cell('t = isinstance(f(), foo)')
221 nt.assert_true(_ip.user_ns['t'])
221 nt.assert_true(_ip.user_ns['t'])
222
222
223 def test_obj_del(self):
223 def test_obj_del(self):
224 """Test that object's __del__ methods are called on exit."""
224 """Test that object's __del__ methods are called on exit."""
225 if sys.platform == 'win32':
225 if sys.platform == 'win32':
226 try:
226 try:
227 import win32api
227 import win32api
228 except ImportError:
228 except ImportError:
229 raise SkipTest("Test requires pywin32")
229 raise SkipTest("Test requires pywin32")
230 src = ("class A(object):\n"
230 src = ("class A(object):\n"
231 " def __del__(self):\n"
231 " def __del__(self):\n"
232 " print 'object A deleted'\n"
232 " print 'object A deleted'\n"
233 "a = A()\n")
233 "a = A()\n")
234 self.mktmp(py3compat.doctest_refactor_print(src))
234 self.mktmp(py3compat.doctest_refactor_print(src))
235 if dec.module_not_available('sqlite3'):
235 if dec.module_not_available('sqlite3'):
236 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
236 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
237 else:
237 else:
238 err = None
238 err = None
239 tt.ipexec_validate(self.fname, 'object A deleted', err)
239 tt.ipexec_validate(self.fname, 'object A deleted', err)
240
240
241 @dec.skip_known_failure
241 @dec.skip_known_failure
242 def test_aggressive_namespace_cleanup(self):
242 def test_aggressive_namespace_cleanup(self):
243 """Test that namespace cleanup is not too aggressive GH-238
243 """Test that namespace cleanup is not too aggressive GH-238
244
244
245 Returning from another run magic deletes the namespace"""
245 Returning from another run magic deletes the namespace"""
246 # see ticket https://github.com/ipython/ipython/issues/238
246 # see ticket https://github.com/ipython/ipython/issues/238
247 class secondtmp(tt.TempFileMixin): pass
247 class secondtmp(tt.TempFileMixin): pass
248 empty = secondtmp()
248 empty = secondtmp()
249 empty.mktmp('')
249 empty.mktmp('')
250 src = ("ip = get_ipython()\n"
250 src = ("ip = get_ipython()\n"
251 "for i in range(5):\n"
251 "for i in range(5):\n"
252 " try:\n"
252 " try:\n"
253 " ip.magic('run %s')\n"
253 " ip.magic('run %s')\n"
254 " except NameError as e:\n"
254 " except NameError as e:\n"
255 " print i;break\n" % empty.fname)
255 " print i;break\n" % empty.fname)
256 self.mktmp(py3compat.doctest_refactor_print(src))
256 self.mktmp(py3compat.doctest_refactor_print(src))
257 _ip.magic('run %s' % self.fname)
257 _ip.magic('run %s' % self.fname)
258 _ip.run_cell('ip == get_ipython()')
258 _ip.run_cell('ip == get_ipython()')
259 nt.assert_equal(_ip.user_ns['i'], 5)
259 nt.assert_equal(_ip.user_ns['i'], 5)
260
260
261 @dec.skip_win32
261 @dec.skip_win32
262 def test_tclass(self):
262 def test_tclass(self):
263 mydir = os.path.dirname(__file__)
263 mydir = os.path.dirname(__file__)
264 tc = os.path.join(mydir, 'tclass')
264 tc = os.path.join(mydir, 'tclass')
265 src = ("%%run '%s' C-first\n"
265 src = ("%%run '%s' C-first\n"
266 "%%run '%s' C-second\n"
266 "%%run '%s' C-second\n"
267 "%%run '%s' C-third\n") % (tc, tc, tc)
267 "%%run '%s' C-third\n") % (tc, tc, tc)
268 self.mktmp(src, '.ipy')
268 self.mktmp(src, '.ipy')
269 out = """\
269 out = """\
270 ARGV 1-: ['C-first']
270 ARGV 1-: ['C-first']
271 ARGV 1-: ['C-second']
271 ARGV 1-: ['C-second']
272 tclass.py: deleting object: C-first
272 tclass.py: deleting object: C-first
273 ARGV 1-: ['C-third']
273 ARGV 1-: ['C-third']
274 tclass.py: deleting object: C-second
274 tclass.py: deleting object: C-second
275 tclass.py: deleting object: C-third
275 tclass.py: deleting object: C-third
276 """
276 """
277 if dec.module_not_available('sqlite3'):
277 if dec.module_not_available('sqlite3'):
278 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
278 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
279 else:
279 else:
280 err = None
280 err = None
281 tt.ipexec_validate(self.fname, out, err)
281 tt.ipexec_validate(self.fname, out, err)
282
282
283 def test_run_i_after_reset(self):
283 def test_run_i_after_reset(self):
284 """Check that %run -i still works after %reset (gh-693)"""
284 """Check that %run -i still works after %reset (gh-693)"""
285 src = "yy = zz\n"
285 src = "yy = zz\n"
286 self.mktmp(src)
286 self.mktmp(src)
287 _ip.run_cell("zz = 23")
287 _ip.run_cell("zz = 23")
288 _ip.magic('run -i %s' % self.fname)
288 _ip.magic('run -i %s' % self.fname)
289 nt.assert_equal(_ip.user_ns['yy'], 23)
289 nt.assert_equal(_ip.user_ns['yy'], 23)
290 _ip.magic('reset -f')
290 _ip.magic('reset -f')
291 _ip.run_cell("zz = 23")
291 _ip.run_cell("zz = 23")
292 _ip.magic('run -i %s' % self.fname)
292 _ip.magic('run -i %s' % self.fname)
293 nt.assert_equal(_ip.user_ns['yy'], 23)
293 nt.assert_equal(_ip.user_ns['yy'], 23)
294
294
295 def test_unicode(self):
295 def test_unicode(self):
296 """Check that files in odd encodings are accepted."""
296 """Check that files in odd encodings are accepted."""
297 mydir = os.path.dirname(__file__)
297 mydir = os.path.dirname(__file__)
298 na = os.path.join(mydir, 'nonascii.py')
298 na = os.path.join(mydir, 'nonascii.py')
299 _ip.magic('run "%s"' % na)
299 _ip.magic('run "%s"' % na)
300 nt.assert_equal(_ip.user_ns['u'], u'ΠŽΡ‚β„–Π€')
300 nt.assert_equal(_ip.user_ns['u'], u'ΠŽΡ‚β„–Π€')
301
301
302 def test_run_py_file_attribute(self):
302 def test_run_py_file_attribute(self):
303 """Test handling of `__file__` attribute in `%run <file>.py`."""
303 """Test handling of `__file__` attribute in `%run <file>.py`."""
304 src = "t = __file__\n"
304 src = "t = __file__\n"
305 self.mktmp(src)
305 self.mktmp(src)
306 _missing = object()
306 _missing = object()
307 file1 = _ip.user_ns.get('__file__', _missing)
307 file1 = _ip.user_ns.get('__file__', _missing)
308 _ip.magic('run %s' % self.fname)
308 _ip.magic('run %s' % self.fname)
309 file2 = _ip.user_ns.get('__file__', _missing)
309 file2 = _ip.user_ns.get('__file__', _missing)
310
310
311 # Check that __file__ was equal to the filename in the script's
311 # Check that __file__ was equal to the filename in the script's
312 # namespace.
312 # namespace.
313 nt.assert_equal(_ip.user_ns['t'], self.fname)
313 nt.assert_equal(_ip.user_ns['t'], self.fname)
314
314
315 # Check that __file__ was not leaked back into user_ns.
315 # Check that __file__ was not leaked back into user_ns.
316 nt.assert_equal(file1, file2)
316 nt.assert_equal(file1, file2)
317
317
318 def test_run_ipy_file_attribute(self):
318 def test_run_ipy_file_attribute(self):
319 """Test handling of `__file__` attribute in `%run <file.ipy>`."""
319 """Test handling of `__file__` attribute in `%run <file.ipy>`."""
320 src = "t = __file__\n"
320 src = "t = __file__\n"
321 self.mktmp(src, ext='.ipy')
321 self.mktmp(src, ext='.ipy')
322 _missing = object()
322 _missing = object()
323 file1 = _ip.user_ns.get('__file__', _missing)
323 file1 = _ip.user_ns.get('__file__', _missing)
324 _ip.magic('run %s' % self.fname)
324 _ip.magic('run %s' % self.fname)
325 file2 = _ip.user_ns.get('__file__', _missing)
325 file2 = _ip.user_ns.get('__file__', _missing)
326
326
327 # Check that __file__ was equal to the filename in the script's
327 # Check that __file__ was equal to the filename in the script's
328 # namespace.
328 # namespace.
329 nt.assert_equal(_ip.user_ns['t'], self.fname)
329 nt.assert_equal(_ip.user_ns['t'], self.fname)
330
330
331 # Check that __file__ was not leaked back into user_ns.
331 # Check that __file__ was not leaked back into user_ns.
332 nt.assert_equal(file1, file2)
332 nt.assert_equal(file1, file2)
333
334 def test_run_formatting(self):
335 """ Test that %run -t -N<N> does not raise a TypeError for N > 1."""
336 src = "pass"
337 self.mktmp(src)
338 _ip.magic('run -t -N 1 %s' % self.fname)
339 _ip.magic('run -t -N 10 %s' % self.fname)
General Comments 0
You need to be logged in to leave comments. Login now