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