##// END OF EJS Templates
Add failing test for gh-3547
Thomas Kluyver -
Show More
@@ -1,416 +1,430 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 functools
16 import functools
17 import os
17 import os
18 import random
18 import random
19 import sys
19 import sys
20 import tempfile
20 import tempfile
21 import textwrap
21 import textwrap
22 import unittest
22 import unittest
23
23
24 import nose.tools as nt
24 import nose.tools as nt
25 from nose import SkipTest
25 from nose import SkipTest
26
26
27 from IPython.testing import decorators as dec
27 from IPython.testing import decorators as dec
28 from IPython.testing import tools as tt
28 from IPython.testing import tools as tt
29 from IPython.utils import py3compat
29 from IPython.utils import py3compat
30 from IPython.utils.tempdir import TemporaryDirectory
30 from IPython.utils.tempdir import TemporaryDirectory
31 from IPython.core import debugger
31 from IPython.core import debugger
32
32
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34 # Test functions begin
34 # Test functions begin
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36
36
37 def doctest_refbug():
37 def doctest_refbug():
38 """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.
39 See: https://github.com/ipython/ipython/issues/141
39 See: https://github.com/ipython/ipython/issues/141
40
40
41 In [1]: _ip.clear_main_mod_cache()
41 In [1]: _ip.clear_main_mod_cache()
42 # random
42 # random
43
43
44 In [2]: %run refbug
44 In [2]: %run refbug
45
45
46 In [3]: call_f()
46 In [3]: call_f()
47 lowercased: hello
47 lowercased: hello
48
48
49 In [4]: %run refbug
49 In [4]: %run refbug
50
50
51 In [5]: call_f()
51 In [5]: call_f()
52 lowercased: hello
52 lowercased: hello
53 lowercased: hello
53 lowercased: hello
54 """
54 """
55
55
56
56
57 def doctest_run_builtins():
57 def doctest_run_builtins():
58 r"""Check that %run doesn't damage __builtins__.
58 r"""Check that %run doesn't damage __builtins__.
59
59
60 In [1]: import tempfile
60 In [1]: import tempfile
61
61
62 In [2]: bid1 = id(__builtins__)
62 In [2]: bid1 = id(__builtins__)
63
63
64 In [3]: fname = tempfile.mkstemp('.py')[1]
64 In [3]: fname = tempfile.mkstemp('.py')[1]
65
65
66 In [3]: f = open(fname,'w')
66 In [3]: f = open(fname,'w')
67
67
68 In [4]: dummy= f.write('pass\n')
68 In [4]: dummy= f.write('pass\n')
69
69
70 In [5]: f.flush()
70 In [5]: f.flush()
71
71
72 In [6]: t1 = type(__builtins__)
72 In [6]: t1 = type(__builtins__)
73
73
74 In [7]: %run $fname
74 In [7]: %run $fname
75
75
76 In [7]: f.close()
76 In [7]: f.close()
77
77
78 In [8]: bid2 = id(__builtins__)
78 In [8]: bid2 = id(__builtins__)
79
79
80 In [9]: t2 = type(__builtins__)
80 In [9]: t2 = type(__builtins__)
81
81
82 In [10]: t1 == t2
82 In [10]: t1 == t2
83 Out[10]: True
83 Out[10]: True
84
84
85 In [10]: bid1 == bid2
85 In [10]: bid1 == bid2
86 Out[10]: True
86 Out[10]: True
87
87
88 In [12]: try:
88 In [12]: try:
89 ....: os.unlink(fname)
89 ....: os.unlink(fname)
90 ....: except:
90 ....: except:
91 ....: pass
91 ....: pass
92 ....:
92 ....:
93 """
93 """
94
94
95
95
96 def doctest_run_option_parser():
96 def doctest_run_option_parser():
97 r"""Test option parser in %run.
97 r"""Test option parser in %run.
98
98
99 In [1]: %run print_argv.py
99 In [1]: %run print_argv.py
100 []
100 []
101
101
102 In [2]: %run print_argv.py print*.py
102 In [2]: %run print_argv.py print*.py
103 ['print_argv.py']
103 ['print_argv.py']
104
104
105 In [3]: %run -G print_argv.py print*.py
105 In [3]: %run -G print_argv.py print*.py
106 ['print*.py']
106 ['print*.py']
107
107
108 """
108 """
109
109
110
110
111 @dec.skip_win32
111 @dec.skip_win32
112 def doctest_run_option_parser_for_posix():
112 def doctest_run_option_parser_for_posix():
113 r"""Test option parser in %run (Linux/OSX specific).
113 r"""Test option parser in %run (Linux/OSX specific).
114
114
115 You need double quote to escape glob in POSIX systems:
115 You need double quote to escape glob in POSIX systems:
116
116
117 In [1]: %run print_argv.py print\\*.py
117 In [1]: %run print_argv.py print\\*.py
118 ['print*.py']
118 ['print*.py']
119
119
120 You can't use quote to escape glob in POSIX systems:
120 You can't use quote to escape glob in POSIX systems:
121
121
122 In [2]: %run print_argv.py 'print*.py'
122 In [2]: %run print_argv.py 'print*.py'
123 ['print_argv.py']
123 ['print_argv.py']
124
124
125 """
125 """
126
126
127
127
128 @dec.skip_if_not_win32
128 @dec.skip_if_not_win32
129 def doctest_run_option_parser_for_windows():
129 def doctest_run_option_parser_for_windows():
130 r"""Test option parser in %run (Windows specific).
130 r"""Test option parser in %run (Windows specific).
131
131
132 In Windows, you can't escape ``*` `by backslash:
132 In Windows, you can't escape ``*` `by backslash:
133
133
134 In [1]: %run print_argv.py print\\*.py
134 In [1]: %run print_argv.py print\\*.py
135 ['print\\*.py']
135 ['print\\*.py']
136
136
137 You can use quote to escape glob:
137 You can use quote to escape glob:
138
138
139 In [2]: %run print_argv.py 'print*.py'
139 In [2]: %run print_argv.py 'print*.py'
140 ['print*.py']
140 ['print*.py']
141
141
142 """
142 """
143
143
144
144
145 @py3compat.doctest_refactor_print
145 @py3compat.doctest_refactor_print
146 def doctest_reset_del():
146 def doctest_reset_del():
147 """Test that resetting doesn't cause errors in __del__ methods.
147 """Test that resetting doesn't cause errors in __del__ methods.
148
148
149 In [2]: class A(object):
149 In [2]: class A(object):
150 ...: def __del__(self):
150 ...: def __del__(self):
151 ...: print str("Hi")
151 ...: print str("Hi")
152 ...:
152 ...:
153
153
154 In [3]: a = A()
154 In [3]: a = A()
155
155
156 In [4]: get_ipython().reset()
156 In [4]: get_ipython().reset()
157 Hi
157 Hi
158
158
159 In [5]: 1+1
159 In [5]: 1+1
160 Out[5]: 2
160 Out[5]: 2
161 """
161 """
162
162
163 # 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
164 # setup that makes a temp file
164 # setup that makes a temp file
165
165
166 class TestMagicRunPass(tt.TempFileMixin):
166 class TestMagicRunPass(tt.TempFileMixin):
167
167
168 def setup(self):
168 def setup(self):
169 """Make a valid python temp file."""
169 """Make a valid python temp file."""
170 self.mktmp('pass\n')
170 self.mktmp('pass\n')
171
171
172 def run_tmpfile(self):
172 def run_tmpfile(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 %s' % self.fname)
176 _ip.magic('run %s' % self.fname)
177
177
178 def run_tmpfile_p(self):
178 def run_tmpfile_p(self):
179 _ip = get_ipython()
179 _ip = get_ipython()
180 # 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.
181 # See below and ticket https://bugs.launchpad.net/bugs/366353
181 # See below and ticket https://bugs.launchpad.net/bugs/366353
182 _ip.magic('run -p %s' % self.fname)
182 _ip.magic('run -p %s' % self.fname)
183
183
184 def test_builtins_id(self):
184 def test_builtins_id(self):
185 """Check that %run doesn't damage __builtins__ """
185 """Check that %run doesn't damage __builtins__ """
186 _ip = get_ipython()
186 _ip = get_ipython()
187 # Test that the id of __builtins__ is not modified by %run
187 # Test that the id of __builtins__ is not modified by %run
188 bid1 = id(_ip.user_ns['__builtins__'])
188 bid1 = id(_ip.user_ns['__builtins__'])
189 self.run_tmpfile()
189 self.run_tmpfile()
190 bid2 = id(_ip.user_ns['__builtins__'])
190 bid2 = id(_ip.user_ns['__builtins__'])
191 nt.assert_equal(bid1, bid2)
191 nt.assert_equal(bid1, bid2)
192
192
193 def test_builtins_type(self):
193 def test_builtins_type(self):
194 """Check that the type of __builtins__ doesn't change with %run.
194 """Check that the type of __builtins__ doesn't change with %run.
195
195
196 However, the above could pass if __builtins__ was already modified to
196 However, the above could pass if __builtins__ was already modified to
197 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
198 also check explicitly that it really is a module:
198 also check explicitly that it really is a module:
199 """
199 """
200 _ip = get_ipython()
200 _ip = get_ipython()
201 self.run_tmpfile()
201 self.run_tmpfile()
202 nt.assert_equal(type(_ip.user_ns['__builtins__']),type(sys))
202 nt.assert_equal(type(_ip.user_ns['__builtins__']),type(sys))
203
203
204 def test_prompts(self):
204 def test_prompts(self):
205 """Test that prompts correctly generate after %run"""
205 """Test that prompts correctly generate after %run"""
206 self.run_tmpfile()
206 self.run_tmpfile()
207 _ip = get_ipython()
207 _ip = get_ipython()
208 p2 = _ip.prompt_manager.render('in2').strip()
208 p2 = _ip.prompt_manager.render('in2').strip()
209 nt.assert_equal(p2[:3], '...')
209 nt.assert_equal(p2[:3], '...')
210
210
211 def test_run_profile( self ):
211 def test_run_profile( self ):
212 """Test that the option -p, which invokes the profiler, do not
212 """Test that the option -p, which invokes the profiler, do not
213 crash by invoking execfile"""
213 crash by invoking execfile"""
214 _ip = get_ipython()
214 _ip = get_ipython()
215 self.run_tmpfile_p()
215 self.run_tmpfile_p()
216
216
217
217
218 class TestMagicRunSimple(tt.TempFileMixin):
218 class TestMagicRunSimple(tt.TempFileMixin):
219
219
220 def test_simpledef(self):
220 def test_simpledef(self):
221 """Test that simple class definitions work."""
221 """Test that simple class definitions work."""
222 src = ("class foo: pass\n"
222 src = ("class foo: pass\n"
223 "def f(): return foo()")
223 "def f(): return foo()")
224 self.mktmp(src)
224 self.mktmp(src)
225 _ip.magic('run %s' % self.fname)
225 _ip.magic('run %s' % self.fname)
226 _ip.run_cell('t = isinstance(f(), foo)')
226 _ip.run_cell('t = isinstance(f(), foo)')
227 nt.assert_true(_ip.user_ns['t'])
227 nt.assert_true(_ip.user_ns['t'])
228
228
229 def test_obj_del(self):
229 def test_obj_del(self):
230 """Test that object's __del__ methods are called on exit."""
230 """Test that object's __del__ methods are called on exit."""
231 if sys.platform == 'win32':
231 if sys.platform == 'win32':
232 try:
232 try:
233 import win32api
233 import win32api
234 except ImportError:
234 except ImportError:
235 raise SkipTest("Test requires pywin32")
235 raise SkipTest("Test requires pywin32")
236 src = ("class A(object):\n"
236 src = ("class A(object):\n"
237 " def __del__(self):\n"
237 " def __del__(self):\n"
238 " print 'object A deleted'\n"
238 " print 'object A deleted'\n"
239 "a = A()\n")
239 "a = A()\n")
240 self.mktmp(py3compat.doctest_refactor_print(src))
240 self.mktmp(py3compat.doctest_refactor_print(src))
241 if dec.module_not_available('sqlite3'):
241 if dec.module_not_available('sqlite3'):
242 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
242 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
243 else:
243 else:
244 err = None
244 err = None
245 tt.ipexec_validate(self.fname, 'object A deleted', err)
245 tt.ipexec_validate(self.fname, 'object A deleted', err)
246
246
247 @dec.skip_known_failure
247 @dec.skip_known_failure
248 def test_aggressive_namespace_cleanup(self):
248 def test_aggressive_namespace_cleanup(self):
249 """Test that namespace cleanup is not too aggressive GH-238
249 """Test that namespace cleanup is not too aggressive GH-238
250
250
251 Returning from another run magic deletes the namespace"""
251 Returning from another run magic deletes the namespace"""
252 # see ticket https://github.com/ipython/ipython/issues/238
252 # see ticket https://github.com/ipython/ipython/issues/238
253 class secondtmp(tt.TempFileMixin): pass
253 class secondtmp(tt.TempFileMixin): pass
254 empty = secondtmp()
254 empty = secondtmp()
255 empty.mktmp('')
255 empty.mktmp('')
256 src = ("ip = get_ipython()\n"
256 src = ("ip = get_ipython()\n"
257 "for i in range(5):\n"
257 "for i in range(5):\n"
258 " try:\n"
258 " try:\n"
259 " ip.magic('run %s')\n"
259 " ip.magic('run %s')\n"
260 " except NameError as e:\n"
260 " except NameError as e:\n"
261 " print i;break\n" % empty.fname)
261 " print i;break\n" % empty.fname)
262 self.mktmp(py3compat.doctest_refactor_print(src))
262 self.mktmp(py3compat.doctest_refactor_print(src))
263 _ip.magic('run %s' % self.fname)
263 _ip.magic('run %s' % self.fname)
264 _ip.run_cell('ip == get_ipython()')
264 _ip.run_cell('ip == get_ipython()')
265 nt.assert_equal(_ip.user_ns['i'], 5)
265 nt.assert_equal(_ip.user_ns['i'], 5)
266
267 def test_run_second(self):
268 """Test that running a second file doesn't clobber the first, gh-3547
269 """
270 self.mktmp("avar = 1\n"
271 "def afunc():\n"
272 " return avar\n")
273
274 empty = tt.TempFileMixin()
275 empty.mktmp("")
276
277 _ip.magic('run %s' % self.fname)
278 _ip.magic('run %s' % empty.fname)
279 nt.assert_equal(_ip.user_ns['afunc'](), 1)
266
280
267 @dec.skip_win32
281 @dec.skip_win32
268 def test_tclass(self):
282 def test_tclass(self):
269 mydir = os.path.dirname(__file__)
283 mydir = os.path.dirname(__file__)
270 tc = os.path.join(mydir, 'tclass')
284 tc = os.path.join(mydir, 'tclass')
271 src = ("%%run '%s' C-first\n"
285 src = ("%%run '%s' C-first\n"
272 "%%run '%s' C-second\n"
286 "%%run '%s' C-second\n"
273 "%%run '%s' C-third\n") % (tc, tc, tc)
287 "%%run '%s' C-third\n") % (tc, tc, tc)
274 self.mktmp(src, '.ipy')
288 self.mktmp(src, '.ipy')
275 out = """\
289 out = """\
276 ARGV 1-: ['C-first']
290 ARGV 1-: ['C-first']
277 ARGV 1-: ['C-second']
291 ARGV 1-: ['C-second']
278 tclass.py: deleting object: C-first
292 tclass.py: deleting object: C-first
279 ARGV 1-: ['C-third']
293 ARGV 1-: ['C-third']
280 tclass.py: deleting object: C-second
294 tclass.py: deleting object: C-second
281 tclass.py: deleting object: C-third
295 tclass.py: deleting object: C-third
282 """
296 """
283 if dec.module_not_available('sqlite3'):
297 if dec.module_not_available('sqlite3'):
284 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
298 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
285 else:
299 else:
286 err = None
300 err = None
287 tt.ipexec_validate(self.fname, out, err)
301 tt.ipexec_validate(self.fname, out, err)
288
302
289 def test_run_i_after_reset(self):
303 def test_run_i_after_reset(self):
290 """Check that %run -i still works after %reset (gh-693)"""
304 """Check that %run -i still works after %reset (gh-693)"""
291 src = "yy = zz\n"
305 src = "yy = zz\n"
292 self.mktmp(src)
306 self.mktmp(src)
293 _ip.run_cell("zz = 23")
307 _ip.run_cell("zz = 23")
294 _ip.magic('run -i %s' % self.fname)
308 _ip.magic('run -i %s' % self.fname)
295 nt.assert_equal(_ip.user_ns['yy'], 23)
309 nt.assert_equal(_ip.user_ns['yy'], 23)
296 _ip.magic('reset -f')
310 _ip.magic('reset -f')
297 _ip.run_cell("zz = 23")
311 _ip.run_cell("zz = 23")
298 _ip.magic('run -i %s' % self.fname)
312 _ip.magic('run -i %s' % self.fname)
299 nt.assert_equal(_ip.user_ns['yy'], 23)
313 nt.assert_equal(_ip.user_ns['yy'], 23)
300
314
301 def test_unicode(self):
315 def test_unicode(self):
302 """Check that files in odd encodings are accepted."""
316 """Check that files in odd encodings are accepted."""
303 mydir = os.path.dirname(__file__)
317 mydir = os.path.dirname(__file__)
304 na = os.path.join(mydir, 'nonascii.py')
318 na = os.path.join(mydir, 'nonascii.py')
305 _ip.magic('run "%s"' % na)
319 _ip.magic('run "%s"' % na)
306 nt.assert_equal(_ip.user_ns['u'], u'ΠŽΡ‚β„–Π€')
320 nt.assert_equal(_ip.user_ns['u'], u'ΠŽΡ‚β„–Π€')
307
321
308 def test_run_py_file_attribute(self):
322 def test_run_py_file_attribute(self):
309 """Test handling of `__file__` attribute in `%run <file>.py`."""
323 """Test handling of `__file__` attribute in `%run <file>.py`."""
310 src = "t = __file__\n"
324 src = "t = __file__\n"
311 self.mktmp(src)
325 self.mktmp(src)
312 _missing = object()
326 _missing = object()
313 file1 = _ip.user_ns.get('__file__', _missing)
327 file1 = _ip.user_ns.get('__file__', _missing)
314 _ip.magic('run %s' % self.fname)
328 _ip.magic('run %s' % self.fname)
315 file2 = _ip.user_ns.get('__file__', _missing)
329 file2 = _ip.user_ns.get('__file__', _missing)
316
330
317 # Check that __file__ was equal to the filename in the script's
331 # Check that __file__ was equal to the filename in the script's
318 # namespace.
332 # namespace.
319 nt.assert_equal(_ip.user_ns['t'], self.fname)
333 nt.assert_equal(_ip.user_ns['t'], self.fname)
320
334
321 # Check that __file__ was not leaked back into user_ns.
335 # Check that __file__ was not leaked back into user_ns.
322 nt.assert_equal(file1, file2)
336 nt.assert_equal(file1, file2)
323
337
324 def test_run_ipy_file_attribute(self):
338 def test_run_ipy_file_attribute(self):
325 """Test handling of `__file__` attribute in `%run <file.ipy>`."""
339 """Test handling of `__file__` attribute in `%run <file.ipy>`."""
326 src = "t = __file__\n"
340 src = "t = __file__\n"
327 self.mktmp(src, ext='.ipy')
341 self.mktmp(src, ext='.ipy')
328 _missing = object()
342 _missing = object()
329 file1 = _ip.user_ns.get('__file__', _missing)
343 file1 = _ip.user_ns.get('__file__', _missing)
330 _ip.magic('run %s' % self.fname)
344 _ip.magic('run %s' % self.fname)
331 file2 = _ip.user_ns.get('__file__', _missing)
345 file2 = _ip.user_ns.get('__file__', _missing)
332
346
333 # Check that __file__ was equal to the filename in the script's
347 # Check that __file__ was equal to the filename in the script's
334 # namespace.
348 # namespace.
335 nt.assert_equal(_ip.user_ns['t'], self.fname)
349 nt.assert_equal(_ip.user_ns['t'], self.fname)
336
350
337 # Check that __file__ was not leaked back into user_ns.
351 # Check that __file__ was not leaked back into user_ns.
338 nt.assert_equal(file1, file2)
352 nt.assert_equal(file1, file2)
339
353
340 def test_run_formatting(self):
354 def test_run_formatting(self):
341 """ Test that %run -t -N<N> does not raise a TypeError for N > 1."""
355 """ Test that %run -t -N<N> does not raise a TypeError for N > 1."""
342 src = "pass"
356 src = "pass"
343 self.mktmp(src)
357 self.mktmp(src)
344 _ip.magic('run -t -N 1 %s' % self.fname)
358 _ip.magic('run -t -N 1 %s' % self.fname)
345 _ip.magic('run -t -N 10 %s' % self.fname)
359 _ip.magic('run -t -N 10 %s' % self.fname)
346
360
347
361
348 class TestMagicRunWithPackage(unittest.TestCase):
362 class TestMagicRunWithPackage(unittest.TestCase):
349
363
350 def writefile(self, name, content):
364 def writefile(self, name, content):
351 path = os.path.join(self.tempdir.name, name)
365 path = os.path.join(self.tempdir.name, name)
352 d = os.path.dirname(path)
366 d = os.path.dirname(path)
353 if not os.path.isdir(d):
367 if not os.path.isdir(d):
354 os.makedirs(d)
368 os.makedirs(d)
355 with open(path, 'w') as f:
369 with open(path, 'w') as f:
356 f.write(textwrap.dedent(content))
370 f.write(textwrap.dedent(content))
357
371
358 def setUp(self):
372 def setUp(self):
359 self.package = package = 'tmp{0}'.format(repr(random.random())[2:])
373 self.package = package = 'tmp{0}'.format(repr(random.random())[2:])
360 """Temporary valid python package name."""
374 """Temporary valid python package name."""
361
375
362 self.value = int(random.random() * 10000)
376 self.value = int(random.random() * 10000)
363
377
364 self.tempdir = TemporaryDirectory()
378 self.tempdir = TemporaryDirectory()
365 self.__orig_cwd = os.getcwdu()
379 self.__orig_cwd = os.getcwdu()
366 sys.path.insert(0, self.tempdir.name)
380 sys.path.insert(0, self.tempdir.name)
367
381
368 self.writefile(os.path.join(package, '__init__.py'), '')
382 self.writefile(os.path.join(package, '__init__.py'), '')
369 self.writefile(os.path.join(package, 'sub.py'), """
383 self.writefile(os.path.join(package, 'sub.py'), """
370 x = {0!r}
384 x = {0!r}
371 """.format(self.value))
385 """.format(self.value))
372 self.writefile(os.path.join(package, 'relative.py'), """
386 self.writefile(os.path.join(package, 'relative.py'), """
373 from .sub import x
387 from .sub import x
374 """)
388 """)
375 self.writefile(os.path.join(package, 'absolute.py'), """
389 self.writefile(os.path.join(package, 'absolute.py'), """
376 from {0}.sub import x
390 from {0}.sub import x
377 """.format(package))
391 """.format(package))
378
392
379 def tearDown(self):
393 def tearDown(self):
380 os.chdir(self.__orig_cwd)
394 os.chdir(self.__orig_cwd)
381 sys.path[:] = [p for p in sys.path if p != self.tempdir.name]
395 sys.path[:] = [p for p in sys.path if p != self.tempdir.name]
382 self.tempdir.cleanup()
396 self.tempdir.cleanup()
383
397
384 def check_run_submodule(self, submodule, opts=''):
398 def check_run_submodule(self, submodule, opts=''):
385 _ip.magic('run {2} -m {0}.{1}'.format(self.package, submodule, opts))
399 _ip.magic('run {2} -m {0}.{1}'.format(self.package, submodule, opts))
386 self.assertEqual(_ip.user_ns['x'], self.value,
400 self.assertEqual(_ip.user_ns['x'], self.value,
387 'Variable `x` is not loaded from module `{0}`.'
401 'Variable `x` is not loaded from module `{0}`.'
388 .format(submodule))
402 .format(submodule))
389
403
390 def test_run_submodule_with_absolute_import(self):
404 def test_run_submodule_with_absolute_import(self):
391 self.check_run_submodule('absolute')
405 self.check_run_submodule('absolute')
392
406
393 def test_run_submodule_with_relative_import(self):
407 def test_run_submodule_with_relative_import(self):
394 """Run submodule that has a relative import statement (#2727)."""
408 """Run submodule that has a relative import statement (#2727)."""
395 self.check_run_submodule('relative')
409 self.check_run_submodule('relative')
396
410
397 def test_prun_submodule_with_absolute_import(self):
411 def test_prun_submodule_with_absolute_import(self):
398 self.check_run_submodule('absolute', '-p')
412 self.check_run_submodule('absolute', '-p')
399
413
400 def test_prun_submodule_with_relative_import(self):
414 def test_prun_submodule_with_relative_import(self):
401 self.check_run_submodule('relative', '-p')
415 self.check_run_submodule('relative', '-p')
402
416
403 def with_fake_debugger(func):
417 def with_fake_debugger(func):
404 @functools.wraps(func)
418 @functools.wraps(func)
405 def wrapper(*args, **kwds):
419 def wrapper(*args, **kwds):
406 with tt.monkeypatch(debugger.Pdb, 'run', staticmethod(eval)):
420 with tt.monkeypatch(debugger.Pdb, 'run', staticmethod(eval)):
407 return func(*args, **kwds)
421 return func(*args, **kwds)
408 return wrapper
422 return wrapper
409
423
410 @with_fake_debugger
424 @with_fake_debugger
411 def test_debug_run_submodule_with_absolute_import(self):
425 def test_debug_run_submodule_with_absolute_import(self):
412 self.check_run_submodule('absolute', '-d')
426 self.check_run_submodule('absolute', '-d')
413
427
414 @with_fake_debugger
428 @with_fake_debugger
415 def test_debug_run_submodule_with_relative_import(self):
429 def test_debug_run_submodule_with_relative_import(self):
416 self.check_run_submodule('relative', '-d')
430 self.check_run_submodule('relative', '-d')
General Comments 0
You need to be logged in to leave comments. Login now