##// END OF EJS Templates
Add test for gh-693 (%run -i after %reset).
Thomas Kluyver -
Show More
@@ -1,230 +1,242 b''
1 """Tests for code execution (%run and related), which is particularly tricky.
1 """Tests for code execution (%run and related), which is particularly tricky.
2
2
3 Because of how %run manages namespaces, and the fact that we are trying here to
3 Because of how %run manages namespaces, and the fact that we are trying here to
4 verify subtle object deletion and reference counting issues, the %run tests
4 verify subtle object deletion and reference counting issues, the %run tests
5 will be kept in this separate file. This makes it easier to aggregate in one
5 will be kept in this separate file. This makes it easier to aggregate in one
6 place the tricks needed to handle it; most other magics are much easier to test
6 place the tricks needed to handle it; most other magics are much easier to test
7 and we do so in a common test_magic file.
7 and we do so in a common test_magic file.
8 """
8 """
9 from __future__ import absolute_import
9 from __future__ import absolute_import
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 import os
15 import os
16 import sys
16 import sys
17 import tempfile
17 import tempfile
18
18
19 import nose.tools as nt
19 import nose.tools as nt
20 from nose import SkipTest
20 from nose import SkipTest
21
21
22 from IPython.testing import decorators as dec
22 from IPython.testing import decorators as dec
23 from IPython.testing import tools as tt
23 from IPython.testing import tools as tt
24 from IPython.utils import py3compat
24 from IPython.utils import py3compat
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Test functions begin
27 # Test functions begin
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 def doctest_refbug():
30 def doctest_refbug():
31 """Very nasty problem with references held by multiple runs of a script.
31 """Very nasty problem with references held by multiple runs of a script.
32 See: https://github.com/ipython/ipython/issues/141
32 See: https://github.com/ipython/ipython/issues/141
33
33
34 In [1]: _ip.clear_main_mod_cache()
34 In [1]: _ip.clear_main_mod_cache()
35 # random
35 # random
36
36
37 In [2]: %run refbug
37 In [2]: %run refbug
38
38
39 In [3]: call_f()
39 In [3]: call_f()
40 lowercased: hello
40 lowercased: hello
41
41
42 In [4]: %run refbug
42 In [4]: %run refbug
43
43
44 In [5]: call_f()
44 In [5]: call_f()
45 lowercased: hello
45 lowercased: hello
46 lowercased: hello
46 lowercased: hello
47 """
47 """
48
48
49
49
50 def doctest_run_builtins():
50 def doctest_run_builtins():
51 r"""Check that %run doesn't damage __builtins__.
51 r"""Check that %run doesn't damage __builtins__.
52
52
53 In [1]: import tempfile
53 In [1]: import tempfile
54
54
55 In [2]: bid1 = id(__builtins__)
55 In [2]: bid1 = id(__builtins__)
56
56
57 In [3]: fname = tempfile.mkstemp('.py')[1]
57 In [3]: fname = tempfile.mkstemp('.py')[1]
58
58
59 In [3]: f = open(fname,'w')
59 In [3]: f = open(fname,'w')
60
60
61 In [4]: dummy= f.write('pass\n')
61 In [4]: dummy= f.write('pass\n')
62
62
63 In [5]: f.flush()
63 In [5]: f.flush()
64
64
65 In [6]: t1 = type(__builtins__)
65 In [6]: t1 = type(__builtins__)
66
66
67 In [7]: %run $fname
67 In [7]: %run $fname
68
68
69 In [7]: f.close()
69 In [7]: f.close()
70
70
71 In [8]: bid2 = id(__builtins__)
71 In [8]: bid2 = id(__builtins__)
72
72
73 In [9]: t2 = type(__builtins__)
73 In [9]: t2 = type(__builtins__)
74
74
75 In [10]: t1 == t2
75 In [10]: t1 == t2
76 Out[10]: True
76 Out[10]: True
77
77
78 In [10]: bid1 == bid2
78 In [10]: bid1 == bid2
79 Out[10]: True
79 Out[10]: True
80
80
81 In [12]: try:
81 In [12]: try:
82 ....: os.unlink(fname)
82 ....: os.unlink(fname)
83 ....: except:
83 ....: except:
84 ....: pass
84 ....: pass
85 ....:
85 ....:
86 """
86 """
87
87
88 @py3compat.doctest_refactor_print
88 @py3compat.doctest_refactor_print
89 def doctest_reset_del():
89 def doctest_reset_del():
90 """Test that resetting doesn't cause errors in __del__ methods.
90 """Test that resetting doesn't cause errors in __del__ methods.
91
91
92 In [2]: class A(object):
92 In [2]: class A(object):
93 ...: def __del__(self):
93 ...: def __del__(self):
94 ...: print str("Hi")
94 ...: print str("Hi")
95 ...:
95 ...:
96
96
97 In [3]: a = A()
97 In [3]: a = A()
98
98
99 In [4]: get_ipython().reset()
99 In [4]: get_ipython().reset()
100 Hi
100 Hi
101
101
102 In [5]: 1+1
102 In [5]: 1+1
103 Out[5]: 2
103 Out[5]: 2
104 """
104 """
105
105
106 # For some tests, it will be handy to organize them in a class with a common
106 # For some tests, it will be handy to organize them in a class with a common
107 # setup that makes a temp file
107 # setup that makes a temp file
108
108
109 class TestMagicRunPass(tt.TempFileMixin):
109 class TestMagicRunPass(tt.TempFileMixin):
110
110
111 def setup(self):
111 def setup(self):
112 """Make a valid python temp file."""
112 """Make a valid python temp file."""
113 self.mktmp('pass\n')
113 self.mktmp('pass\n')
114
114
115 def run_tmpfile(self):
115 def run_tmpfile(self):
116 _ip = get_ipython()
116 _ip = get_ipython()
117 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
117 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
118 # See below and ticket https://bugs.launchpad.net/bugs/366353
118 # See below and ticket https://bugs.launchpad.net/bugs/366353
119 _ip.magic('run %s' % self.fname)
119 _ip.magic('run %s' % self.fname)
120
120
121 def run_tmpfile_p(self):
121 def run_tmpfile_p(self):
122 _ip = get_ipython()
122 _ip = get_ipython()
123 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
123 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
124 # See below and ticket https://bugs.launchpad.net/bugs/366353
124 # See below and ticket https://bugs.launchpad.net/bugs/366353
125 _ip.magic('run -p %s' % self.fname)
125 _ip.magic('run -p %s' % self.fname)
126
126
127 def test_builtins_id(self):
127 def test_builtins_id(self):
128 """Check that %run doesn't damage __builtins__ """
128 """Check that %run doesn't damage __builtins__ """
129 _ip = get_ipython()
129 _ip = get_ipython()
130 # Test that the id of __builtins__ is not modified by %run
130 # Test that the id of __builtins__ is not modified by %run
131 bid1 = id(_ip.user_ns['__builtins__'])
131 bid1 = id(_ip.user_ns['__builtins__'])
132 self.run_tmpfile()
132 self.run_tmpfile()
133 bid2 = id(_ip.user_ns['__builtins__'])
133 bid2 = id(_ip.user_ns['__builtins__'])
134 tt.assert_equals(bid1, bid2)
134 tt.assert_equals(bid1, bid2)
135
135
136 def test_builtins_type(self):
136 def test_builtins_type(self):
137 """Check that the type of __builtins__ doesn't change with %run.
137 """Check that the type of __builtins__ doesn't change with %run.
138
138
139 However, the above could pass if __builtins__ was already modified to
139 However, the above could pass if __builtins__ was already modified to
140 be a dict (it should be a module) by a previous use of %run. So we
140 be a dict (it should be a module) by a previous use of %run. So we
141 also check explicitly that it really is a module:
141 also check explicitly that it really is a module:
142 """
142 """
143 _ip = get_ipython()
143 _ip = get_ipython()
144 self.run_tmpfile()
144 self.run_tmpfile()
145 tt.assert_equals(type(_ip.user_ns['__builtins__']),type(sys))
145 tt.assert_equals(type(_ip.user_ns['__builtins__']),type(sys))
146
146
147 def test_prompts(self):
147 def test_prompts(self):
148 """Test that prompts correctly generate after %run"""
148 """Test that prompts correctly generate after %run"""
149 self.run_tmpfile()
149 self.run_tmpfile()
150 _ip = get_ipython()
150 _ip = get_ipython()
151 p2 = str(_ip.displayhook.prompt2).strip()
151 p2 = str(_ip.displayhook.prompt2).strip()
152 nt.assert_equals(p2[:3], '...')
152 nt.assert_equals(p2[:3], '...')
153
153
154 def test_run_profile( self ):
154 def test_run_profile( self ):
155 """Test that the option -p, which invokes the profiler, do not
155 """Test that the option -p, which invokes the profiler, do not
156 crash by invoking execfile"""
156 crash by invoking execfile"""
157 _ip = get_ipython()
157 _ip = get_ipython()
158 self.run_tmpfile_p()
158 self.run_tmpfile_p()
159
159
160
160
161 class TestMagicRunSimple(tt.TempFileMixin):
161 class TestMagicRunSimple(tt.TempFileMixin):
162
162
163 def test_simpledef(self):
163 def test_simpledef(self):
164 """Test that simple class definitions work."""
164 """Test that simple class definitions work."""
165 src = ("class foo: pass\n"
165 src = ("class foo: pass\n"
166 "def f(): return foo()")
166 "def f(): return foo()")
167 self.mktmp(src)
167 self.mktmp(src)
168 _ip.magic('run %s' % self.fname)
168 _ip.magic('run %s' % self.fname)
169 _ip.run_cell('t = isinstance(f(), foo)')
169 _ip.run_cell('t = isinstance(f(), foo)')
170 nt.assert_true(_ip.user_ns['t'])
170 nt.assert_true(_ip.user_ns['t'])
171
171
172 def test_obj_del(self):
172 def test_obj_del(self):
173 """Test that object's __del__ methods are called on exit."""
173 """Test that object's __del__ methods are called on exit."""
174 if sys.platform == 'win32':
174 if sys.platform == 'win32':
175 try:
175 try:
176 import win32api
176 import win32api
177 except ImportError:
177 except ImportError:
178 raise SkipTest("Test requires pywin32")
178 raise SkipTest("Test requires pywin32")
179 src = ("class A(object):\n"
179 src = ("class A(object):\n"
180 " def __del__(self):\n"
180 " def __del__(self):\n"
181 " print 'object A deleted'\n"
181 " print 'object A deleted'\n"
182 "a = A()\n")
182 "a = A()\n")
183 self.mktmp(py3compat.doctest_refactor_print(src))
183 self.mktmp(py3compat.doctest_refactor_print(src))
184 if dec.module_not_available('sqlite3'):
184 if dec.module_not_available('sqlite3'):
185 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
185 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
186 else:
186 else:
187 err = None
187 err = None
188 tt.ipexec_validate(self.fname, 'object A deleted', err)
188 tt.ipexec_validate(self.fname, 'object A deleted', err)
189
189
190 @dec.skip_known_failure
190 @dec.skip_known_failure
191 def test_aggressive_namespace_cleanup(self):
191 def test_aggressive_namespace_cleanup(self):
192 """Test that namespace cleanup is not too aggressive GH-238
192 """Test that namespace cleanup is not too aggressive GH-238
193
193
194 Returning from another run magic deletes the namespace"""
194 Returning from another run magic deletes the namespace"""
195 # see ticket https://github.com/ipython/ipython/issues/238
195 # see ticket https://github.com/ipython/ipython/issues/238
196 class secondtmp(tt.TempFileMixin): pass
196 class secondtmp(tt.TempFileMixin): pass
197 empty = secondtmp()
197 empty = secondtmp()
198 empty.mktmp('')
198 empty.mktmp('')
199 src = ("ip = get_ipython()\n"
199 src = ("ip = get_ipython()\n"
200 "for i in range(5):\n"
200 "for i in range(5):\n"
201 " try:\n"
201 " try:\n"
202 " ip.magic('run %s')\n"
202 " ip.magic('run %s')\n"
203 " except NameError, e:\n"
203 " except NameError, e:\n"
204 " print i;break\n" % empty.fname)
204 " print i;break\n" % empty.fname)
205 self.mktmp(py3compat.doctest_refactor_print(src))
205 self.mktmp(py3compat.doctest_refactor_print(src))
206 _ip.magic('run %s' % self.fname)
206 _ip.magic('run %s' % self.fname)
207 _ip.run_cell('ip == get_ipython()')
207 _ip.run_cell('ip == get_ipython()')
208 tt.assert_equals(_ip.user_ns['i'], 5)
208 tt.assert_equals(_ip.user_ns['i'], 5)
209
209
210 @dec.skip_win32
210 @dec.skip_win32
211 def test_tclass(self):
211 def test_tclass(self):
212 mydir = os.path.dirname(__file__)
212 mydir = os.path.dirname(__file__)
213 tc = os.path.join(mydir, 'tclass')
213 tc = os.path.join(mydir, 'tclass')
214 src = ("%%run '%s' C-first\n"
214 src = ("%%run '%s' C-first\n"
215 "%%run '%s' C-second\n"
215 "%%run '%s' C-second\n"
216 "%%run '%s' C-third\n") % (tc, tc, tc)
216 "%%run '%s' C-third\n") % (tc, tc, tc)
217 self.mktmp(src, '.ipy')
217 self.mktmp(src, '.ipy')
218 out = """\
218 out = """\
219 ARGV 1-: ['C-first']
219 ARGV 1-: ['C-first']
220 ARGV 1-: ['C-second']
220 ARGV 1-: ['C-second']
221 tclass.py: deleting object: C-first
221 tclass.py: deleting object: C-first
222 ARGV 1-: ['C-third']
222 ARGV 1-: ['C-third']
223 tclass.py: deleting object: C-second
223 tclass.py: deleting object: C-second
224 tclass.py: deleting object: C-third
224 tclass.py: deleting object: C-third
225 """
225 """
226 if dec.module_not_available('sqlite3'):
226 if dec.module_not_available('sqlite3'):
227 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
227 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
228 else:
228 else:
229 err = None
229 err = None
230 tt.ipexec_validate(self.fname, out, err)
230 tt.ipexec_validate(self.fname, out, err)
231
232 def test_run_i_after_reset(self):
233 """Check that %run -i still works after %reset (gh-693)"""
234 src = "yy = zz\n"
235 self.mktmp(src)
236 _ip.run_cell("zz = 23")
237 _ip.magic('run -i %s' % self.fname)
238 tt.assert_equals(_ip.user_ns['yy'], 23)
239 _ip.magic('reset -f')
240 _ip.run_cell("zz = 23")
241 _ip.magic('run -i %s' % self.fname)
242 tt.assert_equals(_ip.user_ns['yy'], 23)
General Comments 0
You need to be logged in to leave comments. Login now