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