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