##// END OF EJS Templates
test for GH-238 %run's aggressive name cleaning
Paul Ivanov -
Show More
@@ -1,186 +1,205 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
20
21 from IPython.testing import decorators as dec
21 from IPython.testing import decorators as dec
22 from IPython.testing import tools as tt
22 from IPython.testing import tools as tt
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Test functions begin
25 # Test functions begin
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 def doctest_refbug():
28 def doctest_refbug():
29 """Very nasty problem with references held by multiple runs of a script.
29 """Very nasty problem with references held by multiple runs of a script.
30 See: https://bugs.launchpad.net/ipython/+bug/269966
30 See: https://bugs.launchpad.net/ipython/+bug/269966
31
31
32 In [1]: _ip.clear_main_mod_cache()
32 In [1]: _ip.clear_main_mod_cache()
33 # random
33 # random
34
34
35 In [2]: %run refbug
35 In [2]: %run refbug
36
36
37 In [3]: call_f()
37 In [3]: call_f()
38 lowercased: hello
38 lowercased: hello
39
39
40 In [4]: %run refbug
40 In [4]: %run refbug
41
41
42 In [5]: call_f()
42 In [5]: call_f()
43 lowercased: hello
43 lowercased: hello
44 lowercased: hello
44 lowercased: hello
45 """
45 """
46
46
47
47
48 def doctest_run_builtins():
48 def doctest_run_builtins():
49 r"""Check that %run doesn't damage __builtins__.
49 r"""Check that %run doesn't damage __builtins__.
50
50
51 In [1]: import tempfile
51 In [1]: import tempfile
52
52
53 In [2]: bid1 = id(__builtins__)
53 In [2]: bid1 = id(__builtins__)
54
54
55 In [3]: fname = tempfile.mkstemp('.py')[1]
55 In [3]: fname = tempfile.mkstemp('.py')[1]
56
56
57 In [3]: f = open(fname,'w')
57 In [3]: f = open(fname,'w')
58
58
59 In [4]: f.write('pass\n')
59 In [4]: f.write('pass\n')
60
60
61 In [5]: f.flush()
61 In [5]: f.flush()
62
62
63 In [6]: t1 = type(__builtins__)
63 In [6]: t1 = type(__builtins__)
64
64
65 In [7]: %run $fname
65 In [7]: %run $fname
66
66
67 In [7]: f.close()
67 In [7]: f.close()
68
68
69 In [8]: bid2 = id(__builtins__)
69 In [8]: bid2 = id(__builtins__)
70
70
71 In [9]: t2 = type(__builtins__)
71 In [9]: t2 = type(__builtins__)
72
72
73 In [10]: t1 == t2
73 In [10]: t1 == t2
74 Out[10]: True
74 Out[10]: True
75
75
76 In [10]: bid1 == bid2
76 In [10]: bid1 == bid2
77 Out[10]: True
77 Out[10]: True
78
78
79 In [12]: try:
79 In [12]: try:
80 ....: os.unlink(fname)
80 ....: os.unlink(fname)
81 ....: except:
81 ....: except:
82 ....: pass
82 ....: pass
83 ....:
83 ....:
84 """
84 """
85
85
86 def doctest_reset_del():
86 def doctest_reset_del():
87 """Test that resetting doesn't cause errors in __del__ methods.
87 """Test that resetting doesn't cause errors in __del__ methods.
88
88
89 In [2]: class A(object):
89 In [2]: class A(object):
90 ...: def __del__(self):
90 ...: def __del__(self):
91 ...: print str("Hi")
91 ...: print str("Hi")
92 ...:
92 ...:
93
93
94 In [3]: a = A()
94 In [3]: a = A()
95
95
96 In [4]: get_ipython().reset()
96 In [4]: get_ipython().reset()
97 Hi
97 Hi
98
98
99 In [5]: 1+1
99 In [5]: 1+1
100 Out[5]: 2
100 Out[5]: 2
101 """
101 """
102
102
103 # For some tests, it will be handy to organize them in a class with a common
103 # For some tests, it will be handy to organize them in a class with a common
104 # setup that makes a temp file
104 # setup that makes a temp file
105
105
106 class TestMagicRunPass(tt.TempFileMixin):
106 class TestMagicRunPass(tt.TempFileMixin):
107
107
108 def setup(self):
108 def setup(self):
109 """Make a valid python temp file."""
109 """Make a valid python temp file."""
110 self.mktmp('pass\n')
110 self.mktmp('pass\n')
111
111
112 def run_tmpfile(self):
112 def run_tmpfile(self):
113 _ip = get_ipython()
113 _ip = get_ipython()
114 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
114 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
115 # See below and ticket https://bugs.launchpad.net/bugs/366353
115 # See below and ticket https://bugs.launchpad.net/bugs/366353
116 _ip.magic('run %s' % self.fname)
116 _ip.magic('run %s' % self.fname)
117
117
118 def test_builtins_id(self):
118 def test_builtins_id(self):
119 """Check that %run doesn't damage __builtins__ """
119 """Check that %run doesn't damage __builtins__ """
120 _ip = get_ipython()
120 _ip = get_ipython()
121 # Test that the id of __builtins__ is not modified by %run
121 # Test that the id of __builtins__ is not modified by %run
122 bid1 = id(_ip.user_ns['__builtins__'])
122 bid1 = id(_ip.user_ns['__builtins__'])
123 self.run_tmpfile()
123 self.run_tmpfile()
124 bid2 = id(_ip.user_ns['__builtins__'])
124 bid2 = id(_ip.user_ns['__builtins__'])
125 tt.assert_equals(bid1, bid2)
125 tt.assert_equals(bid1, bid2)
126
126
127 def test_builtins_type(self):
127 def test_builtins_type(self):
128 """Check that the type of __builtins__ doesn't change with %run.
128 """Check that the type of __builtins__ doesn't change with %run.
129
129
130 However, the above could pass if __builtins__ was already modified to
130 However, the above could pass if __builtins__ was already modified to
131 be a dict (it should be a module) by a previous use of %run. So we
131 be a dict (it should be a module) by a previous use of %run. So we
132 also check explicitly that it really is a module:
132 also check explicitly that it really is a module:
133 """
133 """
134 _ip = get_ipython()
134 _ip = get_ipython()
135 self.run_tmpfile()
135 self.run_tmpfile()
136 tt.assert_equals(type(_ip.user_ns['__builtins__']),type(sys))
136 tt.assert_equals(type(_ip.user_ns['__builtins__']),type(sys))
137
137
138 def test_prompts(self):
138 def test_prompts(self):
139 """Test that prompts correctly generate after %run"""
139 """Test that prompts correctly generate after %run"""
140 self.run_tmpfile()
140 self.run_tmpfile()
141 _ip = get_ipython()
141 _ip = get_ipython()
142 p2 = str(_ip.displayhook.prompt2).strip()
142 p2 = str(_ip.displayhook.prompt2).strip()
143 nt.assert_equals(p2[:3], '...')
143 nt.assert_equals(p2[:3], '...')
144
144
145
145
146 class TestMagicRunSimple(tt.TempFileMixin):
146 class TestMagicRunSimple(tt.TempFileMixin):
147
147
148 def test_simpledef(self):
148 def test_simpledef(self):
149 """Test that simple class definitions work."""
149 """Test that simple class definitions work."""
150 src = ("class foo: pass\n"
150 src = ("class foo: pass\n"
151 "def f(): return foo()")
151 "def f(): return foo()")
152 self.mktmp(src)
152 self.mktmp(src)
153 _ip.magic('run %s' % self.fname)
153 _ip.magic('run %s' % self.fname)
154 _ip.runlines('t = isinstance(f(), foo)')
154 _ip.runlines('t = isinstance(f(), foo)')
155 nt.assert_true(_ip.user_ns['t'])
155 nt.assert_true(_ip.user_ns['t'])
156
156
157 # We have to skip these in win32 because getoutputerr() crashes,
157 # We have to skip these in win32 because getoutputerr() crashes,
158 # due to the fact that subprocess does not support close_fds when
158 # due to the fact that subprocess does not support close_fds when
159 # redirecting stdout/err. So unless someone who knows more tells us how to
159 # redirecting stdout/err. So unless someone who knows more tells us how to
160 # implement getoutputerr() in win32, we're stuck avoiding these.
160 # implement getoutputerr() in win32, we're stuck avoiding these.
161 @dec.skip_win32
161 @dec.skip_win32
162 def test_obj_del(self):
162 def test_obj_del(self):
163 """Test that object's __del__ methods are called on exit."""
163 """Test that object's __del__ methods are called on exit."""
164
164
165 # This test is known to fail on win32.
165 # This test is known to fail on win32.
166 # See ticket https://bugs.launchpad.net/bugs/366334
166 # See ticket https://bugs.launchpad.net/bugs/366334
167 src = ("class A(object):\n"
167 src = ("class A(object):\n"
168 " def __del__(self):\n"
168 " def __del__(self):\n"
169 " print 'object A deleted'\n"
169 " print 'object A deleted'\n"
170 "a = A()\n")
170 "a = A()\n")
171 self.mktmp(src)
171 self.mktmp(src)
172 tt.ipexec_validate(self.fname, 'object A deleted')
172 tt.ipexec_validate(self.fname, 'object A deleted')
173
173
174 def test_aggressive_namespace_cleanup(self):
175 """Test that namespace cleanup is not too aggressive GH-238
176
177 returning from another run magic deletes the namespace"""
178 # see ticket https://github.com/ipython/ipython/issues/238
179 class secondtmp(tt.TempFileMixin): pass
180 empty = secondtmp()
181 empty.mktmp('')
182 src = ("ip = get_ipython()\n"
183 "for i in range(5):\n"
184 " try:\n"
185 " ip.magic('run %s')\n"
186 " except NameError, e:\n"
187 " print i;break\n" % empty.fname)
188 self.mktmp(src)
189 _ip.magic('run %s' % self.fname)
190 _ip.runlines('ip == get_ipython()')
191 tt.assert_equals(_ip.user_ns['i'], 5)
192
174 @dec.skip_win32
193 @dec.skip_win32
175 def test_tclass(self):
194 def test_tclass(self):
176 mydir = os.path.dirname(__file__)
195 mydir = os.path.dirname(__file__)
177 tc = os.path.join(mydir, 'tclass')
196 tc = os.path.join(mydir, 'tclass')
178 src = ("%%run '%s' C-first\n"
197 src = ("%%run '%s' C-first\n"
179 "%%run '%s' C-second\n") % (tc, tc)
198 "%%run '%s' C-second\n") % (tc, tc)
180 self.mktmp(src, '.ipy')
199 self.mktmp(src, '.ipy')
181 out = """\
200 out = """\
182 ARGV 1-: [u'C-first']
201 ARGV 1-: [u'C-first']
183 ARGV 1-: [u'C-second']
202 ARGV 1-: [u'C-second']
184 tclass.py: deleting object: C-first
203 tclass.py: deleting object: C-first
185 """
204 """
186 tt.ipexec_validate(self.fname, out)
205 tt.ipexec_validate(self.fname, out)
General Comments 0
You need to be logged in to leave comments. Login now