##// END OF EJS Templates
Minor tweak to test for Python 3
Thomas Kluyver -
Show More
@@ -1,429 +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 def test_aggressive_namespace_cleanup(self):
247 def test_aggressive_namespace_cleanup(self):
248 """Test that namespace cleanup is not too aggressive GH-238
248 """Test that namespace cleanup is not too aggressive GH-238
249
249
250 Returning from another run magic deletes the namespace"""
250 Returning from another run magic deletes the namespace"""
251 # see ticket https://github.com/ipython/ipython/issues/238
251 # see ticket https://github.com/ipython/ipython/issues/238
252 class secondtmp(tt.TempFileMixin): pass
252 class secondtmp(tt.TempFileMixin): pass
253 empty = secondtmp()
253 empty = secondtmp()
254 empty.mktmp('')
254 empty.mktmp('')
255 src = ("ip = get_ipython()\n"
255 src = ("ip = get_ipython()\n"
256 "for i in range(5):\n"
256 "for i in range(5):\n"
257 " try:\n"
257 " try:\n"
258 " ip.magic('run %s')\n"
258 " ip.magic('run %s')\n"
259 " except NameError as e:\n"
259 " except NameError as e:\n"
260 " print i;break\n" % empty.fname)
260 " print(i)\n"
261 self.mktmp(py3compat.doctest_refactor_print(src))
261 " break\n" % empty.fname)
262 self.mktmp(src)
262 _ip.magic('run %s' % self.fname)
263 _ip.magic('run %s' % self.fname)
263 _ip.run_cell('ip == get_ipython()')
264 _ip.run_cell('ip == get_ipython()')
264 nt.assert_equal(_ip.user_ns['i'], 4)
265 nt.assert_equal(_ip.user_ns['i'], 4)
265
266
266 def test_run_second(self):
267 def test_run_second(self):
267 """Test that running a second file doesn't clobber the first, gh-3547
268 """Test that running a second file doesn't clobber the first, gh-3547
268 """
269 """
269 self.mktmp("avar = 1\n"
270 self.mktmp("avar = 1\n"
270 "def afunc():\n"
271 "def afunc():\n"
271 " return avar\n")
272 " return avar\n")
272
273
273 empty = tt.TempFileMixin()
274 empty = tt.TempFileMixin()
274 empty.mktmp("")
275 empty.mktmp("")
275
276
276 _ip.magic('run %s' % self.fname)
277 _ip.magic('run %s' % self.fname)
277 _ip.magic('run %s' % empty.fname)
278 _ip.magic('run %s' % empty.fname)
278 nt.assert_equal(_ip.user_ns['afunc'](), 1)
279 nt.assert_equal(_ip.user_ns['afunc'](), 1)
279
280
280 @dec.skip_win32
281 @dec.skip_win32
281 def test_tclass(self):
282 def test_tclass(self):
282 mydir = os.path.dirname(__file__)
283 mydir = os.path.dirname(__file__)
283 tc = os.path.join(mydir, 'tclass')
284 tc = os.path.join(mydir, 'tclass')
284 src = ("%%run '%s' C-first\n"
285 src = ("%%run '%s' C-first\n"
285 "%%run '%s' C-second\n"
286 "%%run '%s' C-second\n"
286 "%%run '%s' C-third\n") % (tc, tc, tc)
287 "%%run '%s' C-third\n") % (tc, tc, tc)
287 self.mktmp(src, '.ipy')
288 self.mktmp(src, '.ipy')
288 out = """\
289 out = """\
289 ARGV 1-: ['C-first']
290 ARGV 1-: ['C-first']
290 ARGV 1-: ['C-second']
291 ARGV 1-: ['C-second']
291 tclass.py: deleting object: C-first
292 tclass.py: deleting object: C-first
292 ARGV 1-: ['C-third']
293 ARGV 1-: ['C-third']
293 tclass.py: deleting object: C-second
294 tclass.py: deleting object: C-second
294 tclass.py: deleting object: C-third
295 tclass.py: deleting object: C-third
295 """
296 """
296 if dec.module_not_available('sqlite3'):
297 if dec.module_not_available('sqlite3'):
297 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'
298 else:
299 else:
299 err = None
300 err = None
300 tt.ipexec_validate(self.fname, out, err)
301 tt.ipexec_validate(self.fname, out, err)
301
302
302 def test_run_i_after_reset(self):
303 def test_run_i_after_reset(self):
303 """Check that %run -i still works after %reset (gh-693)"""
304 """Check that %run -i still works after %reset (gh-693)"""
304 src = "yy = zz\n"
305 src = "yy = zz\n"
305 self.mktmp(src)
306 self.mktmp(src)
306 _ip.run_cell("zz = 23")
307 _ip.run_cell("zz = 23")
307 _ip.magic('run -i %s' % self.fname)
308 _ip.magic('run -i %s' % self.fname)
308 nt.assert_equal(_ip.user_ns['yy'], 23)
309 nt.assert_equal(_ip.user_ns['yy'], 23)
309 _ip.magic('reset -f')
310 _ip.magic('reset -f')
310 _ip.run_cell("zz = 23")
311 _ip.run_cell("zz = 23")
311 _ip.magic('run -i %s' % self.fname)
312 _ip.magic('run -i %s' % self.fname)
312 nt.assert_equal(_ip.user_ns['yy'], 23)
313 nt.assert_equal(_ip.user_ns['yy'], 23)
313
314
314 def test_unicode(self):
315 def test_unicode(self):
315 """Check that files in odd encodings are accepted."""
316 """Check that files in odd encodings are accepted."""
316 mydir = os.path.dirname(__file__)
317 mydir = os.path.dirname(__file__)
317 na = os.path.join(mydir, 'nonascii.py')
318 na = os.path.join(mydir, 'nonascii.py')
318 _ip.magic('run "%s"' % na)
319 _ip.magic('run "%s"' % na)
319 nt.assert_equal(_ip.user_ns['u'], u'ΠŽΡ‚β„–Π€')
320 nt.assert_equal(_ip.user_ns['u'], u'ΠŽΡ‚β„–Π€')
320
321
321 def test_run_py_file_attribute(self):
322 def test_run_py_file_attribute(self):
322 """Test handling of `__file__` attribute in `%run <file>.py`."""
323 """Test handling of `__file__` attribute in `%run <file>.py`."""
323 src = "t = __file__\n"
324 src = "t = __file__\n"
324 self.mktmp(src)
325 self.mktmp(src)
325 _missing = object()
326 _missing = object()
326 file1 = _ip.user_ns.get('__file__', _missing)
327 file1 = _ip.user_ns.get('__file__', _missing)
327 _ip.magic('run %s' % self.fname)
328 _ip.magic('run %s' % self.fname)
328 file2 = _ip.user_ns.get('__file__', _missing)
329 file2 = _ip.user_ns.get('__file__', _missing)
329
330
330 # 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
331 # namespace.
332 # namespace.
332 nt.assert_equal(_ip.user_ns['t'], self.fname)
333 nt.assert_equal(_ip.user_ns['t'], self.fname)
333
334
334 # Check that __file__ was not leaked back into user_ns.
335 # Check that __file__ was not leaked back into user_ns.
335 nt.assert_equal(file1, file2)
336 nt.assert_equal(file1, file2)
336
337
337 def test_run_ipy_file_attribute(self):
338 def test_run_ipy_file_attribute(self):
338 """Test handling of `__file__` attribute in `%run <file.ipy>`."""
339 """Test handling of `__file__` attribute in `%run <file.ipy>`."""
339 src = "t = __file__\n"
340 src = "t = __file__\n"
340 self.mktmp(src, ext='.ipy')
341 self.mktmp(src, ext='.ipy')
341 _missing = object()
342 _missing = object()
342 file1 = _ip.user_ns.get('__file__', _missing)
343 file1 = _ip.user_ns.get('__file__', _missing)
343 _ip.magic('run %s' % self.fname)
344 _ip.magic('run %s' % self.fname)
344 file2 = _ip.user_ns.get('__file__', _missing)
345 file2 = _ip.user_ns.get('__file__', _missing)
345
346
346 # 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
347 # namespace.
348 # namespace.
348 nt.assert_equal(_ip.user_ns['t'], self.fname)
349 nt.assert_equal(_ip.user_ns['t'], self.fname)
349
350
350 # Check that __file__ was not leaked back into user_ns.
351 # Check that __file__ was not leaked back into user_ns.
351 nt.assert_equal(file1, file2)
352 nt.assert_equal(file1, file2)
352
353
353 def test_run_formatting(self):
354 def test_run_formatting(self):
354 """ 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."""
355 src = "pass"
356 src = "pass"
356 self.mktmp(src)
357 self.mktmp(src)
357 _ip.magic('run -t -N 1 %s' % self.fname)
358 _ip.magic('run -t -N 1 %s' % self.fname)
358 _ip.magic('run -t -N 10 %s' % self.fname)
359 _ip.magic('run -t -N 10 %s' % self.fname)
359
360
360
361
361 class TestMagicRunWithPackage(unittest.TestCase):
362 class TestMagicRunWithPackage(unittest.TestCase):
362
363
363 def writefile(self, name, content):
364 def writefile(self, name, content):
364 path = os.path.join(self.tempdir.name, name)
365 path = os.path.join(self.tempdir.name, name)
365 d = os.path.dirname(path)
366 d = os.path.dirname(path)
366 if not os.path.isdir(d):
367 if not os.path.isdir(d):
367 os.makedirs(d)
368 os.makedirs(d)
368 with open(path, 'w') as f:
369 with open(path, 'w') as f:
369 f.write(textwrap.dedent(content))
370 f.write(textwrap.dedent(content))
370
371
371 def setUp(self):
372 def setUp(self):
372 self.package = package = 'tmp{0}'.format(repr(random.random())[2:])
373 self.package = package = 'tmp{0}'.format(repr(random.random())[2:])
373 """Temporary valid python package name."""
374 """Temporary valid python package name."""
374
375
375 self.value = int(random.random() * 10000)
376 self.value = int(random.random() * 10000)
376
377
377 self.tempdir = TemporaryDirectory()
378 self.tempdir = TemporaryDirectory()
378 self.__orig_cwd = os.getcwdu()
379 self.__orig_cwd = os.getcwdu()
379 sys.path.insert(0, self.tempdir.name)
380 sys.path.insert(0, self.tempdir.name)
380
381
381 self.writefile(os.path.join(package, '__init__.py'), '')
382 self.writefile(os.path.join(package, '__init__.py'), '')
382 self.writefile(os.path.join(package, 'sub.py'), """
383 self.writefile(os.path.join(package, 'sub.py'), """
383 x = {0!r}
384 x = {0!r}
384 """.format(self.value))
385 """.format(self.value))
385 self.writefile(os.path.join(package, 'relative.py'), """
386 self.writefile(os.path.join(package, 'relative.py'), """
386 from .sub import x
387 from .sub import x
387 """)
388 """)
388 self.writefile(os.path.join(package, 'absolute.py'), """
389 self.writefile(os.path.join(package, 'absolute.py'), """
389 from {0}.sub import x
390 from {0}.sub import x
390 """.format(package))
391 """.format(package))
391
392
392 def tearDown(self):
393 def tearDown(self):
393 os.chdir(self.__orig_cwd)
394 os.chdir(self.__orig_cwd)
394 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]
395 self.tempdir.cleanup()
396 self.tempdir.cleanup()
396
397
397 def check_run_submodule(self, submodule, opts=''):
398 def check_run_submodule(self, submodule, opts=''):
398 _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))
399 self.assertEqual(_ip.user_ns['x'], self.value,
400 self.assertEqual(_ip.user_ns['x'], self.value,
400 'Variable `x` is not loaded from module `{0}`.'
401 'Variable `x` is not loaded from module `{0}`.'
401 .format(submodule))
402 .format(submodule))
402
403
403 def test_run_submodule_with_absolute_import(self):
404 def test_run_submodule_with_absolute_import(self):
404 self.check_run_submodule('absolute')
405 self.check_run_submodule('absolute')
405
406
406 def test_run_submodule_with_relative_import(self):
407 def test_run_submodule_with_relative_import(self):
407 """Run submodule that has a relative import statement (#2727)."""
408 """Run submodule that has a relative import statement (#2727)."""
408 self.check_run_submodule('relative')
409 self.check_run_submodule('relative')
409
410
410 def test_prun_submodule_with_absolute_import(self):
411 def test_prun_submodule_with_absolute_import(self):
411 self.check_run_submodule('absolute', '-p')
412 self.check_run_submodule('absolute', '-p')
412
413
413 def test_prun_submodule_with_relative_import(self):
414 def test_prun_submodule_with_relative_import(self):
414 self.check_run_submodule('relative', '-p')
415 self.check_run_submodule('relative', '-p')
415
416
416 def with_fake_debugger(func):
417 def with_fake_debugger(func):
417 @functools.wraps(func)
418 @functools.wraps(func)
418 def wrapper(*args, **kwds):
419 def wrapper(*args, **kwds):
419 with tt.monkeypatch(debugger.Pdb, 'run', staticmethod(eval)):
420 with tt.monkeypatch(debugger.Pdb, 'run', staticmethod(eval)):
420 return func(*args, **kwds)
421 return func(*args, **kwds)
421 return wrapper
422 return wrapper
422
423
423 @with_fake_debugger
424 @with_fake_debugger
424 def test_debug_run_submodule_with_absolute_import(self):
425 def test_debug_run_submodule_with_absolute_import(self):
425 self.check_run_submodule('absolute', '-d')
426 self.check_run_submodule('absolute', '-d')
426
427
427 @with_fake_debugger
428 @with_fake_debugger
428 def test_debug_run_submodule_with_relative_import(self):
429 def test_debug_run_submodule_with_relative_import(self):
429 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