##// END OF EJS Templates
Cleanup some of the skip-if decorators....
Matthias Bussonnier -
Show More
@@ -1,510 +1,508 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
10
11 # Copyright (c) IPython Development Team.
11 # Copyright (c) IPython Development Team.
12 # Distributed under the terms of the Modified BSD License.
12 # Distributed under the terms of the Modified BSD License.
13
13
14 from __future__ import absolute_import
14 from __future__ import absolute_import
15
15
16
16
17 import functools
17 import functools
18 import os
18 import os
19 from os.path import join as pjoin
19 from os.path import join as pjoin
20 import random
20 import random
21 import sys
21 import sys
22 import tempfile
23 import textwrap
22 import textwrap
24 import unittest
23 import unittest
25
24
26 try:
25 try:
27 from unittest.mock import patch
26 from unittest.mock import patch
28 except ImportError:
27 except ImportError:
29 from mock import patch
28 from mock import patch
30
29
31 import nose.tools as nt
30 import nose.tools as nt
32 from nose import SkipTest
31 from nose import SkipTest
33
32
34 from IPython.testing import decorators as dec
33 from IPython.testing import decorators as dec
35 from IPython.testing import tools as tt
34 from IPython.testing import tools as tt
36 from IPython.utils import py3compat
35 from IPython.utils import py3compat
37 from IPython.utils.io import capture_output
36 from IPython.utils.io import capture_output
38 from IPython.utils.tempdir import TemporaryDirectory
37 from IPython.utils.tempdir import TemporaryDirectory
39 from IPython.core import debugger
38 from IPython.core import debugger
40
39
41
40
42 def doctest_refbug():
41 def doctest_refbug():
43 """Very nasty problem with references held by multiple runs of a script.
42 """Very nasty problem with references held by multiple runs of a script.
44 See: https://github.com/ipython/ipython/issues/141
43 See: https://github.com/ipython/ipython/issues/141
45
44
46 In [1]: _ip.clear_main_mod_cache()
45 In [1]: _ip.clear_main_mod_cache()
47 # random
46 # random
48
47
49 In [2]: %run refbug
48 In [2]: %run refbug
50
49
51 In [3]: call_f()
50 In [3]: call_f()
52 lowercased: hello
51 lowercased: hello
53
52
54 In [4]: %run refbug
53 In [4]: %run refbug
55
54
56 In [5]: call_f()
55 In [5]: call_f()
57 lowercased: hello
56 lowercased: hello
58 lowercased: hello
57 lowercased: hello
59 """
58 """
60
59
61
60
62 def doctest_run_builtins():
61 def doctest_run_builtins():
63 r"""Check that %run doesn't damage __builtins__.
62 r"""Check that %run doesn't damage __builtins__.
64
63
65 In [1]: import tempfile
64 In [1]: import tempfile
66
65
67 In [2]: bid1 = id(__builtins__)
66 In [2]: bid1 = id(__builtins__)
68
67
69 In [3]: fname = tempfile.mkstemp('.py')[1]
68 In [3]: fname = tempfile.mkstemp('.py')[1]
70
69
71 In [3]: f = open(fname,'w')
70 In [3]: f = open(fname,'w')
72
71
73 In [4]: dummy= f.write('pass\n')
72 In [4]: dummy= f.write('pass\n')
74
73
75 In [5]: f.flush()
74 In [5]: f.flush()
76
75
77 In [6]: t1 = type(__builtins__)
76 In [6]: t1 = type(__builtins__)
78
77
79 In [7]: %run $fname
78 In [7]: %run $fname
80
79
81 In [7]: f.close()
80 In [7]: f.close()
82
81
83 In [8]: bid2 = id(__builtins__)
82 In [8]: bid2 = id(__builtins__)
84
83
85 In [9]: t2 = type(__builtins__)
84 In [9]: t2 = type(__builtins__)
86
85
87 In [10]: t1 == t2
86 In [10]: t1 == t2
88 Out[10]: True
87 Out[10]: True
89
88
90 In [10]: bid1 == bid2
89 In [10]: bid1 == bid2
91 Out[10]: True
90 Out[10]: True
92
91
93 In [12]: try:
92 In [12]: try:
94 ....: os.unlink(fname)
93 ....: os.unlink(fname)
95 ....: except:
94 ....: except:
96 ....: pass
95 ....: pass
97 ....:
96 ....:
98 """
97 """
99
98
100
99
101 def doctest_run_option_parser():
100 def doctest_run_option_parser():
102 r"""Test option parser in %run.
101 r"""Test option parser in %run.
103
102
104 In [1]: %run print_argv.py
103 In [1]: %run print_argv.py
105 []
104 []
106
105
107 In [2]: %run print_argv.py print*.py
106 In [2]: %run print_argv.py print*.py
108 ['print_argv.py']
107 ['print_argv.py']
109
108
110 In [3]: %run -G print_argv.py print*.py
109 In [3]: %run -G print_argv.py print*.py
111 ['print*.py']
110 ['print*.py']
112
111
113 """
112 """
114
113
115
114
116 @dec.skip_win32
115 @dec.skip_win32
117 def doctest_run_option_parser_for_posix():
116 def doctest_run_option_parser_for_posix():
118 r"""Test option parser in %run (Linux/OSX specific).
117 r"""Test option parser in %run (Linux/OSX specific).
119
118
120 You need double quote to escape glob in POSIX systems:
119 You need double quote to escape glob in POSIX systems:
121
120
122 In [1]: %run print_argv.py print\\*.py
121 In [1]: %run print_argv.py print\\*.py
123 ['print*.py']
122 ['print*.py']
124
123
125 You can't use quote to escape glob in POSIX systems:
124 You can't use quote to escape glob in POSIX systems:
126
125
127 In [2]: %run print_argv.py 'print*.py'
126 In [2]: %run print_argv.py 'print*.py'
128 ['print_argv.py']
127 ['print_argv.py']
129
128
130 """
129 """
131
130
132
131
133 @dec.skip_if_not_win32
132 @dec.skip_if_not_win32
134 def doctest_run_option_parser_for_windows():
133 def doctest_run_option_parser_for_windows():
135 r"""Test option parser in %run (Windows specific).
134 r"""Test option parser in %run (Windows specific).
136
135
137 In Windows, you can't escape ``*` `by backslash:
136 In Windows, you can't escape ``*` `by backslash:
138
137
139 In [1]: %run print_argv.py print\\*.py
138 In [1]: %run print_argv.py print\\*.py
140 ['print\\*.py']
139 ['print\\*.py']
141
140
142 You can use quote to escape glob:
141 You can use quote to escape glob:
143
142
144 In [2]: %run print_argv.py 'print*.py'
143 In [2]: %run print_argv.py 'print*.py'
145 ['print*.py']
144 ['print*.py']
146
145
147 """
146 """
148
147
149
148
150 @py3compat.doctest_refactor_print
149 @py3compat.doctest_refactor_print
151 def doctest_reset_del():
150 def doctest_reset_del():
152 """Test that resetting doesn't cause errors in __del__ methods.
151 """Test that resetting doesn't cause errors in __del__ methods.
153
152
154 In [2]: class A(object):
153 In [2]: class A(object):
155 ...: def __del__(self):
154 ...: def __del__(self):
156 ...: print str("Hi")
155 ...: print str("Hi")
157 ...:
156 ...:
158
157
159 In [3]: a = A()
158 In [3]: a = A()
160
159
161 In [4]: get_ipython().reset()
160 In [4]: get_ipython().reset()
162 Hi
161 Hi
163
162
164 In [5]: 1+1
163 In [5]: 1+1
165 Out[5]: 2
164 Out[5]: 2
166 """
165 """
167
166
168 # For some tests, it will be handy to organize them in a class with a common
167 # For some tests, it will be handy to organize them in a class with a common
169 # setup that makes a temp file
168 # setup that makes a temp file
170
169
171 class TestMagicRunPass(tt.TempFileMixin):
170 class TestMagicRunPass(tt.TempFileMixin):
172
171
173 def setup(self):
172 def setup(self):
174 """Make a valid python temp file."""
173 """Make a valid python temp file."""
175 self.mktmp('pass\n')
174 self.mktmp('pass\n')
176
175
177 def run_tmpfile(self):
176 def run_tmpfile(self):
178 _ip = get_ipython()
177 _ip = get_ipython()
179 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
178 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
180 # See below and ticket https://bugs.launchpad.net/bugs/366353
179 # See below and ticket https://bugs.launchpad.net/bugs/366353
181 _ip.magic('run %s' % self.fname)
180 _ip.magic('run %s' % self.fname)
182
181
183 def run_tmpfile_p(self):
182 def run_tmpfile_p(self):
184 _ip = get_ipython()
183 _ip = get_ipython()
185 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
184 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
186 # See below and ticket https://bugs.launchpad.net/bugs/366353
185 # See below and ticket https://bugs.launchpad.net/bugs/366353
187 _ip.magic('run -p %s' % self.fname)
186 _ip.magic('run -p %s' % self.fname)
188
187
189 def test_builtins_id(self):
188 def test_builtins_id(self):
190 """Check that %run doesn't damage __builtins__ """
189 """Check that %run doesn't damage __builtins__ """
191 _ip = get_ipython()
190 _ip = get_ipython()
192 # Test that the id of __builtins__ is not modified by %run
191 # Test that the id of __builtins__ is not modified by %run
193 bid1 = id(_ip.user_ns['__builtins__'])
192 bid1 = id(_ip.user_ns['__builtins__'])
194 self.run_tmpfile()
193 self.run_tmpfile()
195 bid2 = id(_ip.user_ns['__builtins__'])
194 bid2 = id(_ip.user_ns['__builtins__'])
196 nt.assert_equal(bid1, bid2)
195 nt.assert_equal(bid1, bid2)
197
196
198 def test_builtins_type(self):
197 def test_builtins_type(self):
199 """Check that the type of __builtins__ doesn't change with %run.
198 """Check that the type of __builtins__ doesn't change with %run.
200
199
201 However, the above could pass if __builtins__ was already modified to
200 However, the above could pass if __builtins__ was already modified to
202 be a dict (it should be a module) by a previous use of %run. So we
201 be a dict (it should be a module) by a previous use of %run. So we
203 also check explicitly that it really is a module:
202 also check explicitly that it really is a module:
204 """
203 """
205 _ip = get_ipython()
204 _ip = get_ipython()
206 self.run_tmpfile()
205 self.run_tmpfile()
207 nt.assert_equal(type(_ip.user_ns['__builtins__']),type(sys))
206 nt.assert_equal(type(_ip.user_ns['__builtins__']),type(sys))
208
207
209 def test_run_profile( self ):
208 def test_run_profile( self ):
210 """Test that the option -p, which invokes the profiler, do not
209 """Test that the option -p, which invokes the profiler, do not
211 crash by invoking execfile"""
210 crash by invoking execfile"""
212 _ip = get_ipython()
211 get_ipython()
213 self.run_tmpfile_p()
212 self.run_tmpfile_p()
214
213
215
214
216 class TestMagicRunSimple(tt.TempFileMixin):
215 class TestMagicRunSimple(tt.TempFileMixin):
217
216
218 def test_simpledef(self):
217 def test_simpledef(self):
219 """Test that simple class definitions work."""
218 """Test that simple class definitions work."""
220 src = ("class foo: pass\n"
219 src = ("class foo: pass\n"
221 "def f(): return foo()")
220 "def f(): return foo()")
222 self.mktmp(src)
221 self.mktmp(src)
223 _ip.magic('run %s' % self.fname)
222 _ip.magic('run %s' % self.fname)
224 _ip.run_cell('t = isinstance(f(), foo)')
223 _ip.run_cell('t = isinstance(f(), foo)')
225 nt.assert_true(_ip.user_ns['t'])
224 nt.assert_true(_ip.user_ns['t'])
226
225
227 def test_obj_del(self):
226 def test_obj_del(self):
228 """Test that object's __del__ methods are called on exit."""
227 """Test that object's __del__ methods are called on exit."""
229 if sys.platform == 'win32':
228 if sys.platform == 'win32':
230 try:
229 try:
231 import win32api
230 import win32api
232 except ImportError:
231 except ImportError:
233 raise SkipTest("Test requires pywin32")
232 raise SkipTest("Test requires pywin32")
234 src = ("class A(object):\n"
233 src = ("class A(object):\n"
235 " def __del__(self):\n"
234 " def __del__(self):\n"
236 " print 'object A deleted'\n"
235 " print 'object A deleted'\n"
237 "a = A()\n")
236 "a = A()\n")
238 self.mktmp(py3compat.doctest_refactor_print(src))
237 self.mktmp(py3compat.doctest_refactor_print(src))
239 if dec.module_not_available('sqlite3'):
238 if dec.module_not_available('sqlite3'):
240 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
239 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
241 else:
240 else:
242 err = None
241 err = None
243 tt.ipexec_validate(self.fname, 'object A deleted', err)
242 tt.ipexec_validate(self.fname, 'object A deleted', err)
244
243
245 def test_aggressive_namespace_cleanup(self):
244 def test_aggressive_namespace_cleanup(self):
246 """Test that namespace cleanup is not too aggressive GH-238
245 """Test that namespace cleanup is not too aggressive GH-238
247
246
248 Returning from another run magic deletes the namespace"""
247 Returning from another run magic deletes the namespace"""
249 # see ticket https://github.com/ipython/ipython/issues/238
248 # see ticket https://github.com/ipython/ipython/issues/238
250
249
251 with tt.TempFileMixin() as empty:
250 with tt.TempFileMixin() as empty:
252 empty.mktmp('')
251 empty.mktmp('')
253 # On Windows, the filename will have \users in it, so we need to use the
252 # On Windows, the filename will have \users in it, so we need to use the
254 # repr so that the \u becomes \\u.
253 # repr so that the \u becomes \\u.
255 src = ("ip = get_ipython()\n"
254 src = ("ip = get_ipython()\n"
256 "for i in range(5):\n"
255 "for i in range(5):\n"
257 " try:\n"
256 " try:\n"
258 " ip.magic(%r)\n"
257 " ip.magic(%r)\n"
259 " except NameError as e:\n"
258 " except NameError as e:\n"
260 " print(i)\n"
259 " print(i)\n"
261 " break\n" % ('run ' + empty.fname))
260 " break\n" % ('run ' + empty.fname))
262 self.mktmp(src)
261 self.mktmp(src)
263 _ip.magic('run %s' % self.fname)
262 _ip.magic('run %s' % self.fname)
264 _ip.run_cell('ip == get_ipython()')
263 _ip.run_cell('ip == get_ipython()')
265 nt.assert_equal(_ip.user_ns['i'], 4)
264 nt.assert_equal(_ip.user_ns['i'], 4)
266
265
267 def test_run_second(self):
266 def test_run_second(self):
268 """Test that running a second file doesn't clobber the first, gh-3547
267 """Test that running a second file doesn't clobber the first, gh-3547
269 """
268 """
270 self.mktmp("avar = 1\n"
269 self.mktmp("avar = 1\n"
271 "def afunc():\n"
270 "def afunc():\n"
272 " return avar\n")
271 " return avar\n")
273
272
274 with tt.TempFileMixin() as empty:
273 with tt.TempFileMixin() as empty:
275 empty.mktmp("")
274 empty.mktmp("")
276
275
277 _ip.magic('run %s' % self.fname)
276 _ip.magic('run %s' % self.fname)
278 _ip.magic('run %s' % empty.fname)
277 _ip.magic('run %s' % empty.fname)
279 nt.assert_equal(_ip.user_ns['afunc'](), 1)
278 nt.assert_equal(_ip.user_ns['afunc'](), 1)
280
279
281 @dec.skip_win32
280 @dec.skip_win32
282 def test_tclass(self):
281 def test_tclass(self):
283 mydir = os.path.dirname(__file__)
282 mydir = os.path.dirname(__file__)
284 tc = os.path.join(mydir, 'tclass')
283 tc = os.path.join(mydir, 'tclass')
285 src = ("%%run '%s' C-first\n"
284 src = ("%%run '%s' C-first\n"
286 "%%run '%s' C-second\n"
285 "%%run '%s' C-second\n"
287 "%%run '%s' C-third\n") % (tc, tc, tc)
286 "%%run '%s' C-third\n") % (tc, tc, tc)
288 self.mktmp(src, '.ipy')
287 self.mktmp(src, '.ipy')
289 out = """\
288 out = """\
290 ARGV 1-: ['C-first']
289 ARGV 1-: ['C-first']
291 ARGV 1-: ['C-second']
290 ARGV 1-: ['C-second']
292 tclass.py: deleting object: C-first
291 tclass.py: deleting object: C-first
293 ARGV 1-: ['C-third']
292 ARGV 1-: ['C-third']
294 tclass.py: deleting object: C-second
293 tclass.py: deleting object: C-second
295 tclass.py: deleting object: C-third
294 tclass.py: deleting object: C-third
296 """
295 """
297 if dec.module_not_available('sqlite3'):
296 if dec.module_not_available('sqlite3'):
298 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
297 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
299 else:
298 else:
300 err = None
299 err = None
301 tt.ipexec_validate(self.fname, out, err)
300 tt.ipexec_validate(self.fname, out, err)
302
301
303 def test_run_i_after_reset(self):
302 def test_run_i_after_reset(self):
304 """Check that %run -i still works after %reset (gh-693)"""
303 """Check that %run -i still works after %reset (gh-693)"""
305 src = "yy = zz\n"
304 src = "yy = zz\n"
306 self.mktmp(src)
305 self.mktmp(src)
307 _ip.run_cell("zz = 23")
306 _ip.run_cell("zz = 23")
308 _ip.magic('run -i %s' % self.fname)
307 _ip.magic('run -i %s' % self.fname)
309 nt.assert_equal(_ip.user_ns['yy'], 23)
308 nt.assert_equal(_ip.user_ns['yy'], 23)
310 _ip.magic('reset -f')
309 _ip.magic('reset -f')
311 _ip.run_cell("zz = 23")
310 _ip.run_cell("zz = 23")
312 _ip.magic('run -i %s' % self.fname)
311 _ip.magic('run -i %s' % self.fname)
313 nt.assert_equal(_ip.user_ns['yy'], 23)
312 nt.assert_equal(_ip.user_ns['yy'], 23)
314
313
315 def test_unicode(self):
314 def test_unicode(self):
316 """Check that files in odd encodings are accepted."""
315 """Check that files in odd encodings are accepted."""
317 mydir = os.path.dirname(__file__)
316 mydir = os.path.dirname(__file__)
318 na = os.path.join(mydir, 'nonascii.py')
317 na = os.path.join(mydir, 'nonascii.py')
319 _ip.magic('run "%s"' % na)
318 _ip.magic('run "%s"' % na)
320 nt.assert_equal(_ip.user_ns['u'], u'ΠŽΡ‚β„–Π€')
319 nt.assert_equal(_ip.user_ns['u'], u'ΠŽΡ‚β„–Π€')
321
320
322 def test_run_py_file_attribute(self):
321 def test_run_py_file_attribute(self):
323 """Test handling of `__file__` attribute in `%run <file>.py`."""
322 """Test handling of `__file__` attribute in `%run <file>.py`."""
324 src = "t = __file__\n"
323 src = "t = __file__\n"
325 self.mktmp(src)
324 self.mktmp(src)
326 _missing = object()
325 _missing = object()
327 file1 = _ip.user_ns.get('__file__', _missing)
326 file1 = _ip.user_ns.get('__file__', _missing)
328 _ip.magic('run %s' % self.fname)
327 _ip.magic('run %s' % self.fname)
329 file2 = _ip.user_ns.get('__file__', _missing)
328 file2 = _ip.user_ns.get('__file__', _missing)
330
329
331 # Check that __file__ was equal to the filename in the script's
330 # Check that __file__ was equal to the filename in the script's
332 # namespace.
331 # namespace.
333 nt.assert_equal(_ip.user_ns['t'], self.fname)
332 nt.assert_equal(_ip.user_ns['t'], self.fname)
334
333
335 # Check that __file__ was not leaked back into user_ns.
334 # Check that __file__ was not leaked back into user_ns.
336 nt.assert_equal(file1, file2)
335 nt.assert_equal(file1, file2)
337
336
338 def test_run_ipy_file_attribute(self):
337 def test_run_ipy_file_attribute(self):
339 """Test handling of `__file__` attribute in `%run <file.ipy>`."""
338 """Test handling of `__file__` attribute in `%run <file.ipy>`."""
340 src = "t = __file__\n"
339 src = "t = __file__\n"
341 self.mktmp(src, ext='.ipy')
340 self.mktmp(src, ext='.ipy')
342 _missing = object()
341 _missing = object()
343 file1 = _ip.user_ns.get('__file__', _missing)
342 file1 = _ip.user_ns.get('__file__', _missing)
344 _ip.magic('run %s' % self.fname)
343 _ip.magic('run %s' % self.fname)
345 file2 = _ip.user_ns.get('__file__', _missing)
344 file2 = _ip.user_ns.get('__file__', _missing)
346
345
347 # Check that __file__ was equal to the filename in the script's
346 # Check that __file__ was equal to the filename in the script's
348 # namespace.
347 # namespace.
349 nt.assert_equal(_ip.user_ns['t'], self.fname)
348 nt.assert_equal(_ip.user_ns['t'], self.fname)
350
349
351 # Check that __file__ was not leaked back into user_ns.
350 # Check that __file__ was not leaked back into user_ns.
352 nt.assert_equal(file1, file2)
351 nt.assert_equal(file1, file2)
353
352
354 def test_run_formatting(self):
353 def test_run_formatting(self):
355 """ Test that %run -t -N<N> does not raise a TypeError for N > 1."""
354 """ Test that %run -t -N<N> does not raise a TypeError for N > 1."""
356 src = "pass"
355 src = "pass"
357 self.mktmp(src)
356 self.mktmp(src)
358 _ip.magic('run -t -N 1 %s' % self.fname)
357 _ip.magic('run -t -N 1 %s' % self.fname)
359 _ip.magic('run -t -N 10 %s' % self.fname)
358 _ip.magic('run -t -N 10 %s' % self.fname)
360
359
361 def test_ignore_sys_exit(self):
360 def test_ignore_sys_exit(self):
362 """Test the -e option to ignore sys.exit()"""
361 """Test the -e option to ignore sys.exit()"""
363 src = "import sys; sys.exit(1)"
362 src = "import sys; sys.exit(1)"
364 self.mktmp(src)
363 self.mktmp(src)
365 with tt.AssertPrints('SystemExit'):
364 with tt.AssertPrints('SystemExit'):
366 _ip.magic('run %s' % self.fname)
365 _ip.magic('run %s' % self.fname)
367
366
368 with tt.AssertNotPrints('SystemExit'):
367 with tt.AssertNotPrints('SystemExit'):
369 _ip.magic('run -e %s' % self.fname)
368 _ip.magic('run -e %s' % self.fname)
370
369
371 @dec.skip_without('nbformat') # Requires jsonschema
372 def test_run_nb(self):
370 def test_run_nb(self):
373 """Test %run notebook.ipynb"""
371 """Test %run notebook.ipynb"""
374 from nbformat import v4, writes
372 from nbformat import v4, writes
375 nb = v4.new_notebook(
373 nb = v4.new_notebook(
376 cells=[
374 cells=[
377 v4.new_markdown_cell("The Ultimate Question of Everything"),
375 v4.new_markdown_cell("The Ultimate Question of Everything"),
378 v4.new_code_cell("answer=42")
376 v4.new_code_cell("answer=42")
379 ]
377 ]
380 )
378 )
381 src = writes(nb, version=4)
379 src = writes(nb, version=4)
382 self.mktmp(src, ext='.ipynb')
380 self.mktmp(src, ext='.ipynb')
383
381
384 _ip.magic("run %s" % self.fname)
382 _ip.magic("run %s" % self.fname)
385
383
386 nt.assert_equal(_ip.user_ns['answer'], 42)
384 nt.assert_equal(_ip.user_ns['answer'], 42)
387
385
388
386
389
387
390 class TestMagicRunWithPackage(unittest.TestCase):
388 class TestMagicRunWithPackage(unittest.TestCase):
391
389
392 def writefile(self, name, content):
390 def writefile(self, name, content):
393 path = os.path.join(self.tempdir.name, name)
391 path = os.path.join(self.tempdir.name, name)
394 d = os.path.dirname(path)
392 d = os.path.dirname(path)
395 if not os.path.isdir(d):
393 if not os.path.isdir(d):
396 os.makedirs(d)
394 os.makedirs(d)
397 with open(path, 'w') as f:
395 with open(path, 'w') as f:
398 f.write(textwrap.dedent(content))
396 f.write(textwrap.dedent(content))
399
397
400 def setUp(self):
398 def setUp(self):
401 self.package = package = 'tmp{0}'.format(repr(random.random())[2:])
399 self.package = package = 'tmp{0}'.format(repr(random.random())[2:])
402 """Temporary valid python package name."""
400 """Temporary valid python package name."""
403
401
404 self.value = int(random.random() * 10000)
402 self.value = int(random.random() * 10000)
405
403
406 self.tempdir = TemporaryDirectory()
404 self.tempdir = TemporaryDirectory()
407 self.__orig_cwd = py3compat.getcwd()
405 self.__orig_cwd = py3compat.getcwd()
408 sys.path.insert(0, self.tempdir.name)
406 sys.path.insert(0, self.tempdir.name)
409
407
410 self.writefile(os.path.join(package, '__init__.py'), '')
408 self.writefile(os.path.join(package, '__init__.py'), '')
411 self.writefile(os.path.join(package, 'sub.py'), """
409 self.writefile(os.path.join(package, 'sub.py'), """
412 x = {0!r}
410 x = {0!r}
413 """.format(self.value))
411 """.format(self.value))
414 self.writefile(os.path.join(package, 'relative.py'), """
412 self.writefile(os.path.join(package, 'relative.py'), """
415 from .sub import x
413 from .sub import x
416 """)
414 """)
417 self.writefile(os.path.join(package, 'absolute.py'), """
415 self.writefile(os.path.join(package, 'absolute.py'), """
418 from {0}.sub import x
416 from {0}.sub import x
419 """.format(package))
417 """.format(package))
420
418
421 def tearDown(self):
419 def tearDown(self):
422 os.chdir(self.__orig_cwd)
420 os.chdir(self.__orig_cwd)
423 sys.path[:] = [p for p in sys.path if p != self.tempdir.name]
421 sys.path[:] = [p for p in sys.path if p != self.tempdir.name]
424 self.tempdir.cleanup()
422 self.tempdir.cleanup()
425
423
426 def check_run_submodule(self, submodule, opts=''):
424 def check_run_submodule(self, submodule, opts=''):
427 _ip.user_ns.pop('x', None)
425 _ip.user_ns.pop('x', None)
428 _ip.magic('run {2} -m {0}.{1}'.format(self.package, submodule, opts))
426 _ip.magic('run {2} -m {0}.{1}'.format(self.package, submodule, opts))
429 self.assertEqual(_ip.user_ns['x'], self.value,
427 self.assertEqual(_ip.user_ns['x'], self.value,
430 'Variable `x` is not loaded from module `{0}`.'
428 'Variable `x` is not loaded from module `{0}`.'
431 .format(submodule))
429 .format(submodule))
432
430
433 def test_run_submodule_with_absolute_import(self):
431 def test_run_submodule_with_absolute_import(self):
434 self.check_run_submodule('absolute')
432 self.check_run_submodule('absolute')
435
433
436 def test_run_submodule_with_relative_import(self):
434 def test_run_submodule_with_relative_import(self):
437 """Run submodule that has a relative import statement (#2727)."""
435 """Run submodule that has a relative import statement (#2727)."""
438 self.check_run_submodule('relative')
436 self.check_run_submodule('relative')
439
437
440 def test_prun_submodule_with_absolute_import(self):
438 def test_prun_submodule_with_absolute_import(self):
441 self.check_run_submodule('absolute', '-p')
439 self.check_run_submodule('absolute', '-p')
442
440
443 def test_prun_submodule_with_relative_import(self):
441 def test_prun_submodule_with_relative_import(self):
444 self.check_run_submodule('relative', '-p')
442 self.check_run_submodule('relative', '-p')
445
443
446 def with_fake_debugger(func):
444 def with_fake_debugger(func):
447 @functools.wraps(func)
445 @functools.wraps(func)
448 def wrapper(*args, **kwds):
446 def wrapper(*args, **kwds):
449 with patch.object(debugger.Pdb, 'run', staticmethod(eval)):
447 with patch.object(debugger.Pdb, 'run', staticmethod(eval)):
450 return func(*args, **kwds)
448 return func(*args, **kwds)
451 return wrapper
449 return wrapper
452
450
453 @with_fake_debugger
451 @with_fake_debugger
454 def test_debug_run_submodule_with_absolute_import(self):
452 def test_debug_run_submodule_with_absolute_import(self):
455 self.check_run_submodule('absolute', '-d')
453 self.check_run_submodule('absolute', '-d')
456
454
457 @with_fake_debugger
455 @with_fake_debugger
458 def test_debug_run_submodule_with_relative_import(self):
456 def test_debug_run_submodule_with_relative_import(self):
459 self.check_run_submodule('relative', '-d')
457 self.check_run_submodule('relative', '-d')
460
458
461 def test_run__name__():
459 def test_run__name__():
462 with TemporaryDirectory() as td:
460 with TemporaryDirectory() as td:
463 path = pjoin(td, 'foo.py')
461 path = pjoin(td, 'foo.py')
464 with open(path, 'w') as f:
462 with open(path, 'w') as f:
465 f.write("q = __name__")
463 f.write("q = __name__")
466
464
467 _ip.user_ns.pop('q', None)
465 _ip.user_ns.pop('q', None)
468 _ip.magic('run {}'.format(path))
466 _ip.magic('run {}'.format(path))
469 nt.assert_equal(_ip.user_ns.pop('q'), '__main__')
467 nt.assert_equal(_ip.user_ns.pop('q'), '__main__')
470
468
471 _ip.magic('run -n {}'.format(path))
469 _ip.magic('run -n {}'.format(path))
472 nt.assert_equal(_ip.user_ns.pop('q'), 'foo')
470 nt.assert_equal(_ip.user_ns.pop('q'), 'foo')
473
471
474 def test_run_tb():
472 def test_run_tb():
475 """Test traceback offset in %run"""
473 """Test traceback offset in %run"""
476 with TemporaryDirectory() as td:
474 with TemporaryDirectory() as td:
477 path = pjoin(td, 'foo.py')
475 path = pjoin(td, 'foo.py')
478 with open(path, 'w') as f:
476 with open(path, 'w') as f:
479 f.write('\n'.join([
477 f.write('\n'.join([
480 "def foo():",
478 "def foo():",
481 " return bar()",
479 " return bar()",
482 "def bar():",
480 "def bar():",
483 " raise RuntimeError('hello!')",
481 " raise RuntimeError('hello!')",
484 "foo()",
482 "foo()",
485 ]))
483 ]))
486 with capture_output() as io:
484 with capture_output() as io:
487 _ip.magic('run {}'.format(path))
485 _ip.magic('run {}'.format(path))
488 out = io.stdout
486 out = io.stdout
489 nt.assert_not_in("execfile", out)
487 nt.assert_not_in("execfile", out)
490 nt.assert_in("RuntimeError", out)
488 nt.assert_in("RuntimeError", out)
491 nt.assert_equal(out.count("---->"), 3)
489 nt.assert_equal(out.count("---->"), 3)
492
490
493 @dec.knownfailureif(sys.platform == 'win32', "writes to io.stdout aren't captured on Windows")
491 @dec.knownfailureif(sys.platform == 'win32', "writes to io.stdout aren't captured on Windows")
494 def test_script_tb():
492 def test_script_tb():
495 """Test traceback offset in `ipython script.py`"""
493 """Test traceback offset in `ipython script.py`"""
496 with TemporaryDirectory() as td:
494 with TemporaryDirectory() as td:
497 path = pjoin(td, 'foo.py')
495 path = pjoin(td, 'foo.py')
498 with open(path, 'w') as f:
496 with open(path, 'w') as f:
499 f.write('\n'.join([
497 f.write('\n'.join([
500 "def foo():",
498 "def foo():",
501 " return bar()",
499 " return bar()",
502 "def bar():",
500 "def bar():",
503 " raise RuntimeError('hello!')",
501 " raise RuntimeError('hello!')",
504 "foo()",
502 "foo()",
505 ]))
503 ]))
506 out, err = tt.ipexec(path)
504 out, err = tt.ipexec(path)
507 nt.assert_not_in("execfile", out)
505 nt.assert_not_in("execfile", out)
508 nt.assert_in("RuntimeError", out)
506 nt.assert_in("RuntimeError", out)
509 nt.assert_equal(out.count("---->"), 3)
507 nt.assert_equal(out.count("---->"), 3)
510
508
@@ -1,68 +1,56 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for shellapp module.
2 """Tests for shellapp module.
3
3
4 Authors
4 Authors
5 -------
5 -------
6 * Bradley Froehle
6 * Bradley Froehle
7 """
7 """
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2012 The IPython Development Team
9 # Copyright (C) 2012 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 import unittest
18 import unittest
19
19
20 from IPython.testing import decorators as dec
20 from IPython.testing import decorators as dec
21 from IPython.testing import tools as tt
21 from IPython.testing import tools as tt
22 from IPython.utils.py3compat import PY3
23
22
24 sqlite_err_maybe = dec.module_not_available('sqlite3')
23 sqlite_err_maybe = dec.module_not_available('sqlite3')
25 SQLITE_NOT_AVAILABLE_ERROR = ('WARNING: IPython History requires SQLite,'
24 SQLITE_NOT_AVAILABLE_ERROR = ('WARNING: IPython History requires SQLite,'
26 ' your history will not be saved\n')
25 ' your history will not be saved\n')
27
26
28 class TestFileToRun(unittest.TestCase, tt.TempFileMixin):
27 class TestFileToRun(unittest.TestCase, tt.TempFileMixin):
29 """Test the behavior of the file_to_run parameter."""
28 """Test the behavior of the file_to_run parameter."""
30
29
31 def test_py_script_file_attribute(self):
30 def test_py_script_file_attribute(self):
32 """Test that `__file__` is set when running `ipython file.py`"""
31 """Test that `__file__` is set when running `ipython file.py`"""
33 src = "print(__file__)\n"
32 src = "print(__file__)\n"
34 self.mktmp(src)
33 self.mktmp(src)
35
34
36 err = SQLITE_NOT_AVAILABLE_ERROR if sqlite_err_maybe else None
35 err = SQLITE_NOT_AVAILABLE_ERROR if sqlite_err_maybe else None
37 tt.ipexec_validate(self.fname, self.fname, err)
36 tt.ipexec_validate(self.fname, self.fname, err)
38
37
39 def test_ipy_script_file_attribute(self):
38 def test_ipy_script_file_attribute(self):
40 """Test that `__file__` is set when running `ipython file.ipy`"""
39 """Test that `__file__` is set when running `ipython file.ipy`"""
41 src = "print(__file__)\n"
40 src = "print(__file__)\n"
42 self.mktmp(src, ext='.ipy')
41 self.mktmp(src, ext='.ipy')
43
42
44 err = SQLITE_NOT_AVAILABLE_ERROR if sqlite_err_maybe else None
43 err = SQLITE_NOT_AVAILABLE_ERROR if sqlite_err_maybe else None
45 tt.ipexec_validate(self.fname, self.fname, err)
44 tt.ipexec_validate(self.fname, self.fname, err)
46
45
47 # The commands option to ipexec_validate doesn't work on Windows, and it
46 # The commands option to ipexec_validate doesn't work on Windows, and it
48 # doesn't seem worth fixing
47 # doesn't seem worth fixing
49 @dec.skip_win32
48 @dec.skip_win32
50 def test_py_script_file_attribute_interactively(self):
49 def test_py_script_file_attribute_interactively(self):
51 """Test that `__file__` is not set after `ipython -i file.py`"""
50 """Test that `__file__` is not set after `ipython -i file.py`"""
52 src = "True\n"
51 src = "True\n"
53 self.mktmp(src)
52 self.mktmp(src)
54
53
55 out, err = tt.ipexec(self.fname, options=['-i'],
54 out, err = tt.ipexec(self.fname, options=['-i'],
56 commands=['"__file__" in globals()', 'exit()'])
55 commands=['"__file__" in globals()', 'exit()'])
57 self.assertIn("False", out)
56 self.assertIn("False", out)
58
59 @dec.skip_win32
60 @dec.skipif(PY3)
61 def test_py_script_file_compiler_directive(self):
62 """Test `__future__` compiler directives with `ipython -i file.py`"""
63 src = "from __future__ import division\n"
64 self.mktmp(src)
65
66 out, err = tt.ipexec(self.fname, options=['-i'],
67 commands=['type(1/2)', 'exit()'])
68 self.assertIn('float', out)
@@ -1,536 +1,487 b''
1 # coding: utf-8
1 # coding: utf-8
2 """Tests for IPython.lib.pretty."""
2 """Tests for IPython.lib.pretty."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 from __future__ import print_function
7 from __future__ import print_function
8
8
9 from collections import Counter, defaultdict, deque, OrderedDict
9 from collections import Counter, defaultdict, deque, OrderedDict
10 import types, string, ctypes
10 import types, string
11
11
12 import nose.tools as nt
12 import nose.tools as nt
13
13
14 from IPython.lib import pretty
14 from IPython.lib import pretty
15 from IPython.testing.decorators import (skip_without, py2_only, py3_only,
15 from IPython.testing.decorators import (skip_without, py2_only, py3_only)
16 cpython2_only)
16
17 from IPython.utils.py3compat import PY3, unicode_to_str
17 from IPython.utils.py3compat import PY3, unicode_to_str
18
18
19 if PY3:
19 if PY3:
20 from io import StringIO
20 from io import StringIO
21 else:
21 else:
22 from StringIO import StringIO
22 from StringIO import StringIO
23
23
24
24
25 class MyList(object):
25 class MyList(object):
26 def __init__(self, content):
26 def __init__(self, content):
27 self.content = content
27 self.content = content
28 def _repr_pretty_(self, p, cycle):
28 def _repr_pretty_(self, p, cycle):
29 if cycle:
29 if cycle:
30 p.text("MyList(...)")
30 p.text("MyList(...)")
31 else:
31 else:
32 with p.group(3, "MyList(", ")"):
32 with p.group(3, "MyList(", ")"):
33 for (i, child) in enumerate(self.content):
33 for (i, child) in enumerate(self.content):
34 if i:
34 if i:
35 p.text(",")
35 p.text(",")
36 p.breakable()
36 p.breakable()
37 else:
37 else:
38 p.breakable("")
38 p.breakable("")
39 p.pretty(child)
39 p.pretty(child)
40
40
41
41
42 class MyDict(dict):
42 class MyDict(dict):
43 def _repr_pretty_(self, p, cycle):
43 def _repr_pretty_(self, p, cycle):
44 p.text("MyDict(...)")
44 p.text("MyDict(...)")
45
45
46 class MyObj(object):
46 class MyObj(object):
47 def somemethod(self):
47 def somemethod(self):
48 pass
48 pass
49
49
50
50
51 class Dummy1(object):
51 class Dummy1(object):
52 def _repr_pretty_(self, p, cycle):
52 def _repr_pretty_(self, p, cycle):
53 p.text("Dummy1(...)")
53 p.text("Dummy1(...)")
54
54
55 class Dummy2(Dummy1):
55 class Dummy2(Dummy1):
56 _repr_pretty_ = None
56 _repr_pretty_ = None
57
57
58 class NoModule(object):
58 class NoModule(object):
59 pass
59 pass
60
60
61 NoModule.__module__ = None
61 NoModule.__module__ = None
62
62
63 class Breaking(object):
63 class Breaking(object):
64 def _repr_pretty_(self, p, cycle):
64 def _repr_pretty_(self, p, cycle):
65 with p.group(4,"TG: ",":"):
65 with p.group(4,"TG: ",":"):
66 p.text("Breaking(")
66 p.text("Breaking(")
67 p.break_()
67 p.break_()
68 p.text(")")
68 p.text(")")
69
69
70 class BreakingRepr(object):
70 class BreakingRepr(object):
71 def __repr__(self):
71 def __repr__(self):
72 return "Breaking(\n)"
72 return "Breaking(\n)"
73
73
74 class BreakingReprParent(object):
74 class BreakingReprParent(object):
75 def _repr_pretty_(self, p, cycle):
75 def _repr_pretty_(self, p, cycle):
76 with p.group(4,"TG: ",":"):
76 with p.group(4,"TG: ",":"):
77 p.pretty(BreakingRepr())
77 p.pretty(BreakingRepr())
78
78
79 class BadRepr(object):
79 class BadRepr(object):
80
80
81 def __repr__(self):
81 def __repr__(self):
82 return 1/0
82 return 1/0
83
83
84
84
85 def test_indentation():
85 def test_indentation():
86 """Test correct indentation in groups"""
86 """Test correct indentation in groups"""
87 count = 40
87 count = 40
88 gotoutput = pretty.pretty(MyList(range(count)))
88 gotoutput = pretty.pretty(MyList(range(count)))
89 expectedoutput = "MyList(\n" + ",\n".join(" %d" % i for i in range(count)) + ")"
89 expectedoutput = "MyList(\n" + ",\n".join(" %d" % i for i in range(count)) + ")"
90
90
91 nt.assert_equal(gotoutput, expectedoutput)
91 nt.assert_equal(gotoutput, expectedoutput)
92
92
93
93
94 def test_dispatch():
94 def test_dispatch():
95 """
95 """
96 Test correct dispatching: The _repr_pretty_ method for MyDict
96 Test correct dispatching: The _repr_pretty_ method for MyDict
97 must be found before the registered printer for dict.
97 must be found before the registered printer for dict.
98 """
98 """
99 gotoutput = pretty.pretty(MyDict())
99 gotoutput = pretty.pretty(MyDict())
100 expectedoutput = "MyDict(...)"
100 expectedoutput = "MyDict(...)"
101
101
102 nt.assert_equal(gotoutput, expectedoutput)
102 nt.assert_equal(gotoutput, expectedoutput)
103
103
104
104
105 def test_callability_checking():
105 def test_callability_checking():
106 """
106 """
107 Test that the _repr_pretty_ method is tested for callability and skipped if
107 Test that the _repr_pretty_ method is tested for callability and skipped if
108 not.
108 not.
109 """
109 """
110 gotoutput = pretty.pretty(Dummy2())
110 gotoutput = pretty.pretty(Dummy2())
111 expectedoutput = "Dummy1(...)"
111 expectedoutput = "Dummy1(...)"
112
112
113 nt.assert_equal(gotoutput, expectedoutput)
113 nt.assert_equal(gotoutput, expectedoutput)
114
114
115
115
116 def test_sets():
116 def test_sets():
117 """
117 """
118 Test that set and frozenset use Python 3 formatting.
118 Test that set and frozenset use Python 3 formatting.
119 """
119 """
120 objects = [set(), frozenset(), set([1]), frozenset([1]), set([1, 2]),
120 objects = [set(), frozenset(), set([1]), frozenset([1]), set([1, 2]),
121 frozenset([1, 2]), set([-1, -2, -3])]
121 frozenset([1, 2]), set([-1, -2, -3])]
122 expected = ['set()', 'frozenset()', '{1}', 'frozenset({1})', '{1, 2}',
122 expected = ['set()', 'frozenset()', '{1}', 'frozenset({1})', '{1, 2}',
123 'frozenset({1, 2})', '{-3, -2, -1}']
123 'frozenset({1, 2})', '{-3, -2, -1}']
124 for obj, expected_output in zip(objects, expected):
124 for obj, expected_output in zip(objects, expected):
125 got_output = pretty.pretty(obj)
125 got_output = pretty.pretty(obj)
126 yield nt.assert_equal, got_output, expected_output
126 yield nt.assert_equal, got_output, expected_output
127
127
128
128
129 @skip_without('xxlimited')
129 @skip_without('xxlimited')
130 def test_pprint_heap_allocated_type():
130 def test_pprint_heap_allocated_type():
131 """
131 """
132 Test that pprint works for heap allocated types.
132 Test that pprint works for heap allocated types.
133 """
133 """
134 import xxlimited
134 import xxlimited
135 output = pretty.pretty(xxlimited.Null)
135 output = pretty.pretty(xxlimited.Null)
136 nt.assert_equal(output, 'xxlimited.Null')
136 nt.assert_equal(output, 'xxlimited.Null')
137
137
138 def test_pprint_nomod():
138 def test_pprint_nomod():
139 """
139 """
140 Test that pprint works for classes with no __module__.
140 Test that pprint works for classes with no __module__.
141 """
141 """
142 output = pretty.pretty(NoModule)
142 output = pretty.pretty(NoModule)
143 nt.assert_equal(output, 'NoModule')
143 nt.assert_equal(output, 'NoModule')
144
144
145 def test_pprint_break():
145 def test_pprint_break():
146 """
146 """
147 Test that p.break_ produces expected output
147 Test that p.break_ produces expected output
148 """
148 """
149 output = pretty.pretty(Breaking())
149 output = pretty.pretty(Breaking())
150 expected = "TG: Breaking(\n ):"
150 expected = "TG: Breaking(\n ):"
151 nt.assert_equal(output, expected)
151 nt.assert_equal(output, expected)
152
152
153 def test_pprint_break_repr():
153 def test_pprint_break_repr():
154 """
154 """
155 Test that p.break_ is used in repr
155 Test that p.break_ is used in repr
156 """
156 """
157 output = pretty.pretty(BreakingReprParent())
157 output = pretty.pretty(BreakingReprParent())
158 expected = "TG: Breaking(\n ):"
158 expected = "TG: Breaking(\n ):"
159 nt.assert_equal(output, expected)
159 nt.assert_equal(output, expected)
160
160
161 def test_bad_repr():
161 def test_bad_repr():
162 """Don't catch bad repr errors"""
162 """Don't catch bad repr errors"""
163 with nt.assert_raises(ZeroDivisionError):
163 with nt.assert_raises(ZeroDivisionError):
164 output = pretty.pretty(BadRepr())
164 pretty.pretty(BadRepr())
165
165
166 class BadException(Exception):
166 class BadException(Exception):
167 def __str__(self):
167 def __str__(self):
168 return -1
168 return -1
169
169
170 class ReallyBadRepr(object):
170 class ReallyBadRepr(object):
171 __module__ = 1
171 __module__ = 1
172 @property
172 @property
173 def __class__(self):
173 def __class__(self):
174 raise ValueError("I am horrible")
174 raise ValueError("I am horrible")
175
175
176 def __repr__(self):
176 def __repr__(self):
177 raise BadException()
177 raise BadException()
178
178
179 def test_really_bad_repr():
179 def test_really_bad_repr():
180 with nt.assert_raises(BadException):
180 with nt.assert_raises(BadException):
181 output = pretty.pretty(ReallyBadRepr())
181 pretty.pretty(ReallyBadRepr())
182
182
183
183
184 class SA(object):
184 class SA(object):
185 pass
185 pass
186
186
187 class SB(SA):
187 class SB(SA):
188 pass
188 pass
189
189
190 def test_super_repr():
190 def test_super_repr():
191 # "<super: module_name.SA, None>"
191 # "<super: module_name.SA, None>"
192 output = pretty.pretty(super(SA))
192 output = pretty.pretty(super(SA))
193 nt.assert_regexp_matches(output, r"<super: \S+.SA, None>")
193 nt.assert_regexp_matches(output, r"<super: \S+.SA, None>")
194
194
195 # "<super: module_name.SA, <module_name.SB at 0x...>>"
195 # "<super: module_name.SA, <module_name.SB at 0x...>>"
196 sb = SB()
196 sb = SB()
197 output = pretty.pretty(super(SA, sb))
197 output = pretty.pretty(super(SA, sb))
198 nt.assert_regexp_matches(output, r"<super: \S+.SA,\s+<\S+.SB at 0x\S+>>")
198 nt.assert_regexp_matches(output, r"<super: \S+.SA,\s+<\S+.SB at 0x\S+>>")
199
199
200
200
201 def test_long_list():
201 def test_long_list():
202 lis = list(range(10000))
202 lis = list(range(10000))
203 p = pretty.pretty(lis)
203 p = pretty.pretty(lis)
204 last2 = p.rsplit('\n', 2)[-2:]
204 last2 = p.rsplit('\n', 2)[-2:]
205 nt.assert_equal(last2, [' 999,', ' ...]'])
205 nt.assert_equal(last2, [' 999,', ' ...]'])
206
206
207 def test_long_set():
207 def test_long_set():
208 s = set(range(10000))
208 s = set(range(10000))
209 p = pretty.pretty(s)
209 p = pretty.pretty(s)
210 last2 = p.rsplit('\n', 2)[-2:]
210 last2 = p.rsplit('\n', 2)[-2:]
211 nt.assert_equal(last2, [' 999,', ' ...}'])
211 nt.assert_equal(last2, [' 999,', ' ...}'])
212
212
213 def test_long_tuple():
213 def test_long_tuple():
214 tup = tuple(range(10000))
214 tup = tuple(range(10000))
215 p = pretty.pretty(tup)
215 p = pretty.pretty(tup)
216 last2 = p.rsplit('\n', 2)[-2:]
216 last2 = p.rsplit('\n', 2)[-2:]
217 nt.assert_equal(last2, [' 999,', ' ...)'])
217 nt.assert_equal(last2, [' 999,', ' ...)'])
218
218
219 def test_long_dict():
219 def test_long_dict():
220 d = { n:n for n in range(10000) }
220 d = { n:n for n in range(10000) }
221 p = pretty.pretty(d)
221 p = pretty.pretty(d)
222 last2 = p.rsplit('\n', 2)[-2:]
222 last2 = p.rsplit('\n', 2)[-2:]
223 nt.assert_equal(last2, [' 999: 999,', ' ...}'])
223 nt.assert_equal(last2, [' 999: 999,', ' ...}'])
224
224
225 def test_unbound_method():
225 def test_unbound_method():
226 output = pretty.pretty(MyObj.somemethod)
226 output = pretty.pretty(MyObj.somemethod)
227 nt.assert_in('MyObj.somemethod', output)
227 nt.assert_in('MyObj.somemethod', output)
228
228
229
229
230 class MetaClass(type):
230 class MetaClass(type):
231 def __new__(cls, name):
231 def __new__(cls, name):
232 return type.__new__(cls, name, (object,), {'name': name})
232 return type.__new__(cls, name, (object,), {'name': name})
233
233
234 def __repr__(self):
234 def __repr__(self):
235 return "[CUSTOM REPR FOR CLASS %s]" % self.name
235 return "[CUSTOM REPR FOR CLASS %s]" % self.name
236
236
237
237
238 ClassWithMeta = MetaClass('ClassWithMeta')
238 ClassWithMeta = MetaClass('ClassWithMeta')
239
239
240
240
241 def test_metaclass_repr():
241 def test_metaclass_repr():
242 output = pretty.pretty(ClassWithMeta)
242 output = pretty.pretty(ClassWithMeta)
243 nt.assert_equal(output, "[CUSTOM REPR FOR CLASS ClassWithMeta]")
243 nt.assert_equal(output, "[CUSTOM REPR FOR CLASS ClassWithMeta]")
244
244
245
245
246 def test_unicode_repr():
246 def test_unicode_repr():
247 u = u"üniçodé"
247 u = u"üniçodé"
248 ustr = unicode_to_str(u)
248 ustr = unicode_to_str(u)
249
249
250 class C(object):
250 class C(object):
251 def __repr__(self):
251 def __repr__(self):
252 return ustr
252 return ustr
253
253
254 c = C()
254 c = C()
255 p = pretty.pretty(c)
255 p = pretty.pretty(c)
256 nt.assert_equal(p, u)
256 nt.assert_equal(p, u)
257 p = pretty.pretty([c])
257 p = pretty.pretty([c])
258 nt.assert_equal(p, u'[%s]' % u)
258 nt.assert_equal(p, u'[%s]' % u)
259
259
260
260
261 def test_basic_class():
261 def test_basic_class():
262 def type_pprint_wrapper(obj, p, cycle):
262 def type_pprint_wrapper(obj, p, cycle):
263 if obj is MyObj:
263 if obj is MyObj:
264 type_pprint_wrapper.called = True
264 type_pprint_wrapper.called = True
265 return pretty._type_pprint(obj, p, cycle)
265 return pretty._type_pprint(obj, p, cycle)
266 type_pprint_wrapper.called = False
266 type_pprint_wrapper.called = False
267
267
268 stream = StringIO()
268 stream = StringIO()
269 printer = pretty.RepresentationPrinter(stream)
269 printer = pretty.RepresentationPrinter(stream)
270 printer.type_pprinters[type] = type_pprint_wrapper
270 printer.type_pprinters[type] = type_pprint_wrapper
271 printer.pretty(MyObj)
271 printer.pretty(MyObj)
272 printer.flush()
272 printer.flush()
273 output = stream.getvalue()
273 output = stream.getvalue()
274
274
275 nt.assert_equal(output, '%s.MyObj' % __name__)
275 nt.assert_equal(output, '%s.MyObj' % __name__)
276 nt.assert_true(type_pprint_wrapper.called)
276 nt.assert_true(type_pprint_wrapper.called)
277
277
278
278
279 # This is only run on Python 2 because in Python 3 the language prevents you
279 # This is only run on Python 2 because in Python 3 the language prevents you
280 # from setting a non-unicode value for __qualname__ on a metaclass, and it
280 # from setting a non-unicode value for __qualname__ on a metaclass, and it
281 # doesn't respect the descriptor protocol if you subclass unicode and implement
281 # doesn't respect the descriptor protocol if you subclass unicode and implement
282 # __get__.
282 # __get__.
283 @py2_only
283 @py2_only
284 def test_fallback_to__name__on_type():
284 def test_fallback_to__name__on_type():
285 # Test that we correctly repr types that have non-string values for
285 # Test that we correctly repr types that have non-string values for
286 # __qualname__ by falling back to __name__
286 # __qualname__ by falling back to __name__
287
287
288 class Type(object):
288 class Type(object):
289 __qualname__ = 5
289 __qualname__ = 5
290
290
291 # Test repring of the type.
291 # Test repring of the type.
292 stream = StringIO()
292 stream = StringIO()
293 printer = pretty.RepresentationPrinter(stream)
293 printer = pretty.RepresentationPrinter(stream)
294
294
295 printer.pretty(Type)
295 printer.pretty(Type)
296 printer.flush()
296 printer.flush()
297 output = stream.getvalue()
297 output = stream.getvalue()
298
298
299 # If __qualname__ is malformed, we should fall back to __name__.
299 # If __qualname__ is malformed, we should fall back to __name__.
300 expected = '.'.join([__name__, Type.__name__])
300 expected = '.'.join([__name__, Type.__name__])
301 nt.assert_equal(output, expected)
301 nt.assert_equal(output, expected)
302
302
303 # Clear stream buffer.
303 # Clear stream buffer.
304 stream.buf = ''
304 stream.buf = ''
305
305
306 # Test repring of an instance of the type.
306 # Test repring of an instance of the type.
307 instance = Type()
307 instance = Type()
308 printer.pretty(instance)
308 printer.pretty(instance)
309 printer.flush()
309 printer.flush()
310 output = stream.getvalue()
310 output = stream.getvalue()
311
311
312 # Should look like:
312 # Should look like:
313 # <IPython.lib.tests.test_pretty.Type at 0x7f7658ae07d0>
313 # <IPython.lib.tests.test_pretty.Type at 0x7f7658ae07d0>
314 prefix = '<' + '.'.join([__name__, Type.__name__]) + ' at 0x'
314 prefix = '<' + '.'.join([__name__, Type.__name__]) + ' at 0x'
315 nt.assert_true(output.startswith(prefix))
315 nt.assert_true(output.startswith(prefix))
316
316
317
317
318 @py2_only
318 @py2_only
319 def test_fail_gracefully_on_bogus__qualname__and__name__():
319 def test_fail_gracefully_on_bogus__qualname__and__name__():
320 # Test that we correctly repr types that have non-string values for both
320 # Test that we correctly repr types that have non-string values for both
321 # __qualname__ and __name__
321 # __qualname__ and __name__
322
322
323 class Meta(type):
323 class Meta(type):
324 __name__ = 5
324 __name__ = 5
325
325
326 class Type(object):
326 class Type(object):
327 __metaclass__ = Meta
327 __metaclass__ = Meta
328 __qualname__ = 5
328 __qualname__ = 5
329
329
330 stream = StringIO()
330 stream = StringIO()
331 printer = pretty.RepresentationPrinter(stream)
331 printer = pretty.RepresentationPrinter(stream)
332
332
333 printer.pretty(Type)
333 printer.pretty(Type)
334 printer.flush()
334 printer.flush()
335 output = stream.getvalue()
335 output = stream.getvalue()
336
336
337 # If we can't find __name__ or __qualname__ just use a sentinel string.
337 # If we can't find __name__ or __qualname__ just use a sentinel string.
338 expected = '.'.join([__name__, '<unknown type>'])
338 expected = '.'.join([__name__, '<unknown type>'])
339 nt.assert_equal(output, expected)
339 nt.assert_equal(output, expected)
340
340
341 # Clear stream buffer.
341 # Clear stream buffer.
342 stream.buf = ''
342 stream.buf = ''
343
343
344 # Test repring of an instance of the type.
344 # Test repring of an instance of the type.
345 instance = Type()
345 instance = Type()
346 printer.pretty(instance)
346 printer.pretty(instance)
347 printer.flush()
347 printer.flush()
348 output = stream.getvalue()
348 output = stream.getvalue()
349
349
350 # Should look like:
350 # Should look like:
351 # <IPython.lib.tests.test_pretty.<unknown type> at 0x7f7658ae07d0>
351 # <IPython.lib.tests.test_pretty.<unknown type> at 0x7f7658ae07d0>
352 prefix = '<' + '.'.join([__name__, '<unknown type>']) + ' at 0x'
352 prefix = '<' + '.'.join([__name__, '<unknown type>']) + ' at 0x'
353 nt.assert_true(output.startswith(prefix))
353 nt.assert_true(output.startswith(prefix))
354
354
355
355
356 def test_collections_defaultdict():
356 def test_collections_defaultdict():
357 # Create defaultdicts with cycles
357 # Create defaultdicts with cycles
358 a = defaultdict()
358 a = defaultdict()
359 a.default_factory = a
359 a.default_factory = a
360 b = defaultdict(list)
360 b = defaultdict(list)
361 b['key'] = b
361 b['key'] = b
362
362
363 # Dictionary order cannot be relied on, test against single keys.
363 # Dictionary order cannot be relied on, test against single keys.
364 cases = [
364 cases = [
365 (defaultdict(list), 'defaultdict(list, {})'),
365 (defaultdict(list), 'defaultdict(list, {})'),
366 (defaultdict(list, {'key': '-' * 50}),
366 (defaultdict(list, {'key': '-' * 50}),
367 "defaultdict(list,\n"
367 "defaultdict(list,\n"
368 " {'key': '--------------------------------------------------'})"),
368 " {'key': '--------------------------------------------------'})"),
369 (a, 'defaultdict(defaultdict(...), {})'),
369 (a, 'defaultdict(defaultdict(...), {})'),
370 (b, "defaultdict(list, {'key': defaultdict(...)})"),
370 (b, "defaultdict(list, {'key': defaultdict(...)})"),
371 ]
371 ]
372 for obj, expected in cases:
372 for obj, expected in cases:
373 nt.assert_equal(pretty.pretty(obj), expected)
373 nt.assert_equal(pretty.pretty(obj), expected)
374
374
375
375
376 def test_collections_ordereddict():
376 def test_collections_ordereddict():
377 # Create OrderedDict with cycle
377 # Create OrderedDict with cycle
378 a = OrderedDict()
378 a = OrderedDict()
379 a['key'] = a
379 a['key'] = a
380
380
381 cases = [
381 cases = [
382 (OrderedDict(), 'OrderedDict()'),
382 (OrderedDict(), 'OrderedDict()'),
383 (OrderedDict((i, i) for i in range(1000, 1010)),
383 (OrderedDict((i, i) for i in range(1000, 1010)),
384 'OrderedDict([(1000, 1000),\n'
384 'OrderedDict([(1000, 1000),\n'
385 ' (1001, 1001),\n'
385 ' (1001, 1001),\n'
386 ' (1002, 1002),\n'
386 ' (1002, 1002),\n'
387 ' (1003, 1003),\n'
387 ' (1003, 1003),\n'
388 ' (1004, 1004),\n'
388 ' (1004, 1004),\n'
389 ' (1005, 1005),\n'
389 ' (1005, 1005),\n'
390 ' (1006, 1006),\n'
390 ' (1006, 1006),\n'
391 ' (1007, 1007),\n'
391 ' (1007, 1007),\n'
392 ' (1008, 1008),\n'
392 ' (1008, 1008),\n'
393 ' (1009, 1009)])'),
393 ' (1009, 1009)])'),
394 (a, "OrderedDict([('key', OrderedDict(...))])"),
394 (a, "OrderedDict([('key', OrderedDict(...))])"),
395 ]
395 ]
396 for obj, expected in cases:
396 for obj, expected in cases:
397 nt.assert_equal(pretty.pretty(obj), expected)
397 nt.assert_equal(pretty.pretty(obj), expected)
398
398
399
399
400 def test_collections_deque():
400 def test_collections_deque():
401 # Create deque with cycle
401 # Create deque with cycle
402 a = deque()
402 a = deque()
403 a.append(a)
403 a.append(a)
404
404
405 cases = [
405 cases = [
406 (deque(), 'deque([])'),
406 (deque(), 'deque([])'),
407 (deque(i for i in range(1000, 1020)),
407 (deque(i for i in range(1000, 1020)),
408 'deque([1000,\n'
408 'deque([1000,\n'
409 ' 1001,\n'
409 ' 1001,\n'
410 ' 1002,\n'
410 ' 1002,\n'
411 ' 1003,\n'
411 ' 1003,\n'
412 ' 1004,\n'
412 ' 1004,\n'
413 ' 1005,\n'
413 ' 1005,\n'
414 ' 1006,\n'
414 ' 1006,\n'
415 ' 1007,\n'
415 ' 1007,\n'
416 ' 1008,\n'
416 ' 1008,\n'
417 ' 1009,\n'
417 ' 1009,\n'
418 ' 1010,\n'
418 ' 1010,\n'
419 ' 1011,\n'
419 ' 1011,\n'
420 ' 1012,\n'
420 ' 1012,\n'
421 ' 1013,\n'
421 ' 1013,\n'
422 ' 1014,\n'
422 ' 1014,\n'
423 ' 1015,\n'
423 ' 1015,\n'
424 ' 1016,\n'
424 ' 1016,\n'
425 ' 1017,\n'
425 ' 1017,\n'
426 ' 1018,\n'
426 ' 1018,\n'
427 ' 1019])'),
427 ' 1019])'),
428 (a, 'deque([deque(...)])'),
428 (a, 'deque([deque(...)])'),
429 ]
429 ]
430 for obj, expected in cases:
430 for obj, expected in cases:
431 nt.assert_equal(pretty.pretty(obj), expected)
431 nt.assert_equal(pretty.pretty(obj), expected)
432
432
433 def test_collections_counter():
433 def test_collections_counter():
434 class MyCounter(Counter):
434 class MyCounter(Counter):
435 pass
435 pass
436 cases = [
436 cases = [
437 (Counter(), 'Counter()'),
437 (Counter(), 'Counter()'),
438 (Counter(a=1), "Counter({'a': 1})"),
438 (Counter(a=1), "Counter({'a': 1})"),
439 (MyCounter(a=1), "MyCounter({'a': 1})"),
439 (MyCounter(a=1), "MyCounter({'a': 1})"),
440 ]
440 ]
441 for obj, expected in cases:
441 for obj, expected in cases:
442 nt.assert_equal(pretty.pretty(obj), expected)
442 nt.assert_equal(pretty.pretty(obj), expected)
443
443
444 @py3_only
444 @py3_only
445 def test_mappingproxy():
445 def test_mappingproxy():
446 MP = types.MappingProxyType
446 MP = types.MappingProxyType
447 underlying_dict = {}
447 underlying_dict = {}
448 mp_recursive = MP(underlying_dict)
448 mp_recursive = MP(underlying_dict)
449 underlying_dict[2] = mp_recursive
449 underlying_dict[2] = mp_recursive
450 underlying_dict[3] = underlying_dict
450 underlying_dict[3] = underlying_dict
451
451
452 cases = [
452 cases = [
453 (MP({}), "mappingproxy({})"),
453 (MP({}), "mappingproxy({})"),
454 (MP({None: MP({})}), "mappingproxy({None: mappingproxy({})})"),
454 (MP({None: MP({})}), "mappingproxy({None: mappingproxy({})})"),
455 (MP({k: k.upper() for k in string.ascii_lowercase}),
455 (MP({k: k.upper() for k in string.ascii_lowercase}),
456 "mappingproxy({'a': 'A',\n"
456 "mappingproxy({'a': 'A',\n"
457 " 'b': 'B',\n"
457 " 'b': 'B',\n"
458 " 'c': 'C',\n"
458 " 'c': 'C',\n"
459 " 'd': 'D',\n"
459 " 'd': 'D',\n"
460 " 'e': 'E',\n"
460 " 'e': 'E',\n"
461 " 'f': 'F',\n"
461 " 'f': 'F',\n"
462 " 'g': 'G',\n"
462 " 'g': 'G',\n"
463 " 'h': 'H',\n"
463 " 'h': 'H',\n"
464 " 'i': 'I',\n"
464 " 'i': 'I',\n"
465 " 'j': 'J',\n"
465 " 'j': 'J',\n"
466 " 'k': 'K',\n"
466 " 'k': 'K',\n"
467 " 'l': 'L',\n"
467 " 'l': 'L',\n"
468 " 'm': 'M',\n"
468 " 'm': 'M',\n"
469 " 'n': 'N',\n"
469 " 'n': 'N',\n"
470 " 'o': 'O',\n"
470 " 'o': 'O',\n"
471 " 'p': 'P',\n"
471 " 'p': 'P',\n"
472 " 'q': 'Q',\n"
472 " 'q': 'Q',\n"
473 " 'r': 'R',\n"
473 " 'r': 'R',\n"
474 " 's': 'S',\n"
474 " 's': 'S',\n"
475 " 't': 'T',\n"
475 " 't': 'T',\n"
476 " 'u': 'U',\n"
476 " 'u': 'U',\n"
477 " 'v': 'V',\n"
477 " 'v': 'V',\n"
478 " 'w': 'W',\n"
478 " 'w': 'W',\n"
479 " 'x': 'X',\n"
479 " 'x': 'X',\n"
480 " 'y': 'Y',\n"
480 " 'y': 'Y',\n"
481 " 'z': 'Z'})"),
481 " 'z': 'Z'})"),
482 (mp_recursive, "mappingproxy({2: {...}, 3: {2: {...}, 3: {...}}})"),
482 (mp_recursive, "mappingproxy({2: {...}, 3: {2: {...}, 3: {...}}})"),
483 (underlying_dict,
483 (underlying_dict,
484 "{2: mappingproxy({2: {...}, 3: {...}}), 3: {...}}"),
484 "{2: mappingproxy({2: {...}, 3: {...}}), 3: {...}}"),
485 ]
485 ]
486 for obj, expected in cases:
486 for obj, expected in cases:
487 nt.assert_equal(pretty.pretty(obj), expected)
487 nt.assert_equal(pretty.pretty(obj), expected)
488
489 @cpython2_only # In PyPy, types.DictProxyType is dict
490 def test_dictproxy():
491 # This is the dictproxy constructor itself from the Python API,
492 DP = ctypes.pythonapi.PyDictProxy_New
493 DP.argtypes, DP.restype = (ctypes.py_object,), ctypes.py_object
494
495 underlying_dict = {}
496 mp_recursive = DP(underlying_dict)
497 underlying_dict[0] = mp_recursive
498 underlying_dict[-3] = underlying_dict
499
500 cases = [
501 (DP({}), "dict_proxy({})"),
502 (DP({None: DP({})}), "dict_proxy({None: dict_proxy({})})"),
503 (DP({k: k.lower() for k in string.ascii_uppercase}),
504 "dict_proxy({'A': 'a',\n"
505 " 'B': 'b',\n"
506 " 'C': 'c',\n"
507 " 'D': 'd',\n"
508 " 'E': 'e',\n"
509 " 'F': 'f',\n"
510 " 'G': 'g',\n"
511 " 'H': 'h',\n"
512 " 'I': 'i',\n"
513 " 'J': 'j',\n"
514 " 'K': 'k',\n"
515 " 'L': 'l',\n"
516 " 'M': 'm',\n"
517 " 'N': 'n',\n"
518 " 'O': 'o',\n"
519 " 'P': 'p',\n"
520 " 'Q': 'q',\n"
521 " 'R': 'r',\n"
522 " 'S': 's',\n"
523 " 'T': 't',\n"
524 " 'U': 'u',\n"
525 " 'V': 'v',\n"
526 " 'W': 'w',\n"
527 " 'X': 'x',\n"
528 " 'Y': 'y',\n"
529 " 'Z': 'z'})"),
530 (mp_recursive, "dict_proxy({-3: {-3: {...}, 0: {...}}, 0: {...}})"),
531 ]
532 for obj, expected in cases:
533 nt.assert_is_instance(obj, types.DictProxyType) # Meta-test
534 nt.assert_equal(pretty.pretty(obj), expected)
535 nt.assert_equal(pretty.pretty(underlying_dict),
536 "{-3: {...}, 0: dict_proxy({-3: {...}, 0: {...}})}")
@@ -1,380 +1,379 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Decorators for labeling test objects.
2 """Decorators for labeling test objects.
3
3
4 Decorators that merely return a modified version of the original function
4 Decorators that merely return a modified version of the original function
5 object are straightforward. Decorators that return a new function object need
5 object are straightforward. Decorators that return a new function object need
6 to use nose.tools.make_decorator(original_function)(decorator) in returning the
6 to use nose.tools.make_decorator(original_function)(decorator) in returning the
7 decorator, in order to preserve metadata such as function name, setup and
7 decorator, in order to preserve metadata such as function name, setup and
8 teardown functions and so on - see nose.tools for more information.
8 teardown functions and so on - see nose.tools for more information.
9
9
10 This module provides a set of useful decorators meant to be ready to use in
10 This module provides a set of useful decorators meant to be ready to use in
11 your own tests. See the bottom of the file for the ready-made ones, and if you
11 your own tests. See the bottom of the file for the ready-made ones, and if you
12 find yourself writing a new one that may be of generic use, add it here.
12 find yourself writing a new one that may be of generic use, add it here.
13
13
14 Included decorators:
14 Included decorators:
15
15
16
16
17 Lightweight testing that remains unittest-compatible.
17 Lightweight testing that remains unittest-compatible.
18
18
19 - An @as_unittest decorator can be used to tag any normal parameter-less
19 - An @as_unittest decorator can be used to tag any normal parameter-less
20 function as a unittest TestCase. Then, both nose and normal unittest will
20 function as a unittest TestCase. Then, both nose and normal unittest will
21 recognize it as such. This will make it easier to migrate away from Nose if
21 recognize it as such. This will make it easier to migrate away from Nose if
22 we ever need/want to while maintaining very lightweight tests.
22 we ever need/want to while maintaining very lightweight tests.
23
23
24 NOTE: This file contains IPython-specific decorators. Using the machinery in
24 NOTE: This file contains IPython-specific decorators. Using the machinery in
25 IPython.external.decorators, we import either numpy.testing.decorators if numpy is
25 IPython.external.decorators, we import either numpy.testing.decorators if numpy is
26 available, OR use equivalent code in IPython.external._decorators, which
26 available, OR use equivalent code in IPython.external._decorators, which
27 we've copied verbatim from numpy.
27 we've copied verbatim from numpy.
28
28
29 """
29 """
30
30
31 # Copyright (c) IPython Development Team.
31 # Copyright (c) IPython Development Team.
32 # Distributed under the terms of the Modified BSD License.
32 # Distributed under the terms of the Modified BSD License.
33
33
34 import sys
34 import sys
35 import os
35 import os
36 import tempfile
36 import tempfile
37 import unittest
37 import unittest
38 import warnings
38 import warnings
39
39
40 from decorator import decorator
40 from decorator import decorator
41
41
42 # Expose the unittest-driven decorators
42 # Expose the unittest-driven decorators
43 from .ipunittest import ipdoctest, ipdocstring
43 from .ipunittest import ipdoctest, ipdocstring
44
44
45 # Grab the numpy-specific decorators which we keep in a file that we
45 # Grab the numpy-specific decorators which we keep in a file that we
46 # occasionally update from upstream: decorators.py is a copy of
46 # occasionally update from upstream: decorators.py is a copy of
47 # numpy.testing.decorators, we expose all of it here.
47 # numpy.testing.decorators, we expose all of it here.
48 from IPython.external.decorators import *
48 from IPython.external.decorators import *
49
49
50 # For onlyif_cmd_exists decorator
50 # For onlyif_cmd_exists decorator
51 from IPython.utils.py3compat import string_types, which, PY2, PY3, PYPY
51 from IPython.utils.py3compat import string_types, which, PY2, PY3, PYPY
52
52
53 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
54 # Classes and functions
54 # Classes and functions
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56
56
57 # Simple example of the basic idea
57 # Simple example of the basic idea
58 def as_unittest(func):
58 def as_unittest(func):
59 """Decorator to make a simple function into a normal test via unittest."""
59 """Decorator to make a simple function into a normal test via unittest."""
60 class Tester(unittest.TestCase):
60 class Tester(unittest.TestCase):
61 def test(self):
61 def test(self):
62 func()
62 func()
63
63
64 Tester.__name__ = func.__name__
64 Tester.__name__ = func.__name__
65
65
66 return Tester
66 return Tester
67
67
68 # Utility functions
68 # Utility functions
69
69
70 def apply_wrapper(wrapper,func):
70 def apply_wrapper(wrapper,func):
71 """Apply a wrapper to a function for decoration.
71 """Apply a wrapper to a function for decoration.
72
72
73 This mixes Michele Simionato's decorator tool with nose's make_decorator,
73 This mixes Michele Simionato's decorator tool with nose's make_decorator,
74 to apply a wrapper in a decorator so that all nose attributes, as well as
74 to apply a wrapper in a decorator so that all nose attributes, as well as
75 function signature and other properties, survive the decoration cleanly.
75 function signature and other properties, survive the decoration cleanly.
76 This will ensure that wrapped functions can still be well introspected via
76 This will ensure that wrapped functions can still be well introspected via
77 IPython, for example.
77 IPython, for example.
78 """
78 """
79 warnings.warn("The function `apply_wrapper` is deprecated and might be removed in IPython 5.0", DeprecationWarning)
79 warnings.warn("The function `apply_wrapper` is deprecated and might be removed in IPython 5.0", DeprecationWarning)
80
80
81 import nose.tools
81 import nose.tools
82
82
83 return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
83 return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
84
84
85
85
86 def make_label_dec(label,ds=None):
86 def make_label_dec(label,ds=None):
87 """Factory function to create a decorator that applies one or more labels.
87 """Factory function to create a decorator that applies one or more labels.
88
88
89 Parameters
89 Parameters
90 ----------
90 ----------
91 label : string or sequence
91 label : string or sequence
92 One or more labels that will be applied by the decorator to the functions
92 One or more labels that will be applied by the decorator to the functions
93 it decorates. Labels are attributes of the decorated function with their
93 it decorates. Labels are attributes of the decorated function with their
94 value set to True.
94 value set to True.
95
95
96 ds : string
96 ds : string
97 An optional docstring for the resulting decorator. If not given, a
97 An optional docstring for the resulting decorator. If not given, a
98 default docstring is auto-generated.
98 default docstring is auto-generated.
99
99
100 Returns
100 Returns
101 -------
101 -------
102 A decorator.
102 A decorator.
103
103
104 Examples
104 Examples
105 --------
105 --------
106
106
107 A simple labeling decorator:
107 A simple labeling decorator:
108
108
109 >>> slow = make_label_dec('slow')
109 >>> slow = make_label_dec('slow')
110 >>> slow.__doc__
110 >>> slow.__doc__
111 "Labels a test as 'slow'."
111 "Labels a test as 'slow'."
112
112
113 And one that uses multiple labels and a custom docstring:
113 And one that uses multiple labels and a custom docstring:
114
114
115 >>> rare = make_label_dec(['slow','hard'],
115 >>> rare = make_label_dec(['slow','hard'],
116 ... "Mix labels 'slow' and 'hard' for rare tests.")
116 ... "Mix labels 'slow' and 'hard' for rare tests.")
117 >>> rare.__doc__
117 >>> rare.__doc__
118 "Mix labels 'slow' and 'hard' for rare tests."
118 "Mix labels 'slow' and 'hard' for rare tests."
119
119
120 Now, let's test using this one:
120 Now, let's test using this one:
121 >>> @rare
121 >>> @rare
122 ... def f(): pass
122 ... def f(): pass
123 ...
123 ...
124 >>>
124 >>>
125 >>> f.slow
125 >>> f.slow
126 True
126 True
127 >>> f.hard
127 >>> f.hard
128 True
128 True
129 """
129 """
130
130
131 warnings.warn("The function `make_label_dec` is deprecated and might be removed in IPython 5.0", DeprecationWarning)
131 warnings.warn("The function `make_label_dec` is deprecated and might be removed in IPython 5.0", DeprecationWarning)
132 if isinstance(label, string_types):
132 if isinstance(label, string_types):
133 labels = [label]
133 labels = [label]
134 else:
134 else:
135 labels = label
135 labels = label
136
136
137 # Validate that the given label(s) are OK for use in setattr() by doing a
137 # Validate that the given label(s) are OK for use in setattr() by doing a
138 # dry run on a dummy function.
138 # dry run on a dummy function.
139 tmp = lambda : None
139 tmp = lambda : None
140 for label in labels:
140 for label in labels:
141 setattr(tmp,label,True)
141 setattr(tmp,label,True)
142
142
143 # This is the actual decorator we'll return
143 # This is the actual decorator we'll return
144 def decor(f):
144 def decor(f):
145 for label in labels:
145 for label in labels:
146 setattr(f,label,True)
146 setattr(f,label,True)
147 return f
147 return f
148
148
149 # Apply the user's docstring, or autogenerate a basic one
149 # Apply the user's docstring, or autogenerate a basic one
150 if ds is None:
150 if ds is None:
151 ds = "Labels a test as %r." % label
151 ds = "Labels a test as %r." % label
152 decor.__doc__ = ds
152 decor.__doc__ = ds
153
153
154 return decor
154 return decor
155
155
156
156
157 # Inspired by numpy's skipif, but uses the full apply_wrapper utility to
157 # Inspired by numpy's skipif, but uses the full apply_wrapper utility to
158 # preserve function metadata better and allows the skip condition to be a
158 # preserve function metadata better and allows the skip condition to be a
159 # callable.
159 # callable.
160 def skipif(skip_condition, msg=None):
160 def skipif(skip_condition, msg=None):
161 ''' Make function raise SkipTest exception if skip_condition is true
161 ''' Make function raise SkipTest exception if skip_condition is true
162
162
163 Parameters
163 Parameters
164 ----------
164 ----------
165
165
166 skip_condition : bool or callable
166 skip_condition : bool or callable
167 Flag to determine whether to skip test. If the condition is a
167 Flag to determine whether to skip test. If the condition is a
168 callable, it is used at runtime to dynamically make the decision. This
168 callable, it is used at runtime to dynamically make the decision. This
169 is useful for tests that may require costly imports, to delay the cost
169 is useful for tests that may require costly imports, to delay the cost
170 until the test suite is actually executed.
170 until the test suite is actually executed.
171 msg : string
171 msg : string
172 Message to give on raising a SkipTest exception.
172 Message to give on raising a SkipTest exception.
173
173
174 Returns
174 Returns
175 -------
175 -------
176 decorator : function
176 decorator : function
177 Decorator, which, when applied to a function, causes SkipTest
177 Decorator, which, when applied to a function, causes SkipTest
178 to be raised when the skip_condition was True, and the function
178 to be raised when the skip_condition was True, and the function
179 to be called normally otherwise.
179 to be called normally otherwise.
180
180
181 Notes
181 Notes
182 -----
182 -----
183 You will see from the code that we had to further decorate the
183 You will see from the code that we had to further decorate the
184 decorator with the nose.tools.make_decorator function in order to
184 decorator with the nose.tools.make_decorator function in order to
185 transmit function name, and various other metadata.
185 transmit function name, and various other metadata.
186 '''
186 '''
187
187
188 def skip_decorator(f):
188 def skip_decorator(f):
189 # Local import to avoid a hard nose dependency and only incur the
189 # Local import to avoid a hard nose dependency and only incur the
190 # import time overhead at actual test-time.
190 # import time overhead at actual test-time.
191 import nose
191 import nose
192
192
193 # Allow for both boolean or callable skip conditions.
193 # Allow for both boolean or callable skip conditions.
194 if callable(skip_condition):
194 if callable(skip_condition):
195 skip_val = skip_condition
195 skip_val = skip_condition
196 else:
196 else:
197 skip_val = lambda : skip_condition
197 skip_val = lambda : skip_condition
198
198
199 def get_msg(func,msg=None):
199 def get_msg(func,msg=None):
200 """Skip message with information about function being skipped."""
200 """Skip message with information about function being skipped."""
201 if msg is None: out = 'Test skipped due to test condition.'
201 if msg is None: out = 'Test skipped due to test condition.'
202 else: out = msg
202 else: out = msg
203 return "Skipping test: %s. %s" % (func.__name__,out)
203 return "Skipping test: %s. %s" % (func.__name__,out)
204
204
205 # We need to define *two* skippers because Python doesn't allow both
205 # We need to define *two* skippers because Python doesn't allow both
206 # return with value and yield inside the same function.
206 # return with value and yield inside the same function.
207 def skipper_func(*args, **kwargs):
207 def skipper_func(*args, **kwargs):
208 """Skipper for normal test functions."""
208 """Skipper for normal test functions."""
209 if skip_val():
209 if skip_val():
210 raise nose.SkipTest(get_msg(f,msg))
210 raise nose.SkipTest(get_msg(f,msg))
211 else:
211 else:
212 return f(*args, **kwargs)
212 return f(*args, **kwargs)
213
213
214 def skipper_gen(*args, **kwargs):
214 def skipper_gen(*args, **kwargs):
215 """Skipper for test generators."""
215 """Skipper for test generators."""
216 if skip_val():
216 if skip_val():
217 raise nose.SkipTest(get_msg(f,msg))
217 raise nose.SkipTest(get_msg(f,msg))
218 else:
218 else:
219 for x in f(*args, **kwargs):
219 for x in f(*args, **kwargs):
220 yield x
220 yield x
221
221
222 # Choose the right skipper to use when building the actual generator.
222 # Choose the right skipper to use when building the actual generator.
223 if nose.util.isgenerator(f):
223 if nose.util.isgenerator(f):
224 skipper = skipper_gen
224 skipper = skipper_gen
225 else:
225 else:
226 skipper = skipper_func
226 skipper = skipper_func
227
227
228 return nose.tools.make_decorator(f)(skipper)
228 return nose.tools.make_decorator(f)(skipper)
229
229
230 return skip_decorator
230 return skip_decorator
231
231
232 # A version with the condition set to true, common case just to attach a message
232 # A version with the condition set to true, common case just to attach a message
233 # to a skip decorator
233 # to a skip decorator
234 def skip(msg=None):
234 def skip(msg=None):
235 """Decorator factory - mark a test function for skipping from test suite.
235 """Decorator factory - mark a test function for skipping from test suite.
236
236
237 Parameters
237 Parameters
238 ----------
238 ----------
239 msg : string
239 msg : string
240 Optional message to be added.
240 Optional message to be added.
241
241
242 Returns
242 Returns
243 -------
243 -------
244 decorator : function
244 decorator : function
245 Decorator, which, when applied to a function, causes SkipTest
245 Decorator, which, when applied to a function, causes SkipTest
246 to be raised, with the optional message added.
246 to be raised, with the optional message added.
247 """
247 """
248
248
249 return skipif(True,msg)
249 return skipif(True,msg)
250
250
251
251
252 def onlyif(condition, msg):
252 def onlyif(condition, msg):
253 """The reverse from skipif, see skipif for details."""
253 """The reverse from skipif, see skipif for details."""
254
254
255 if callable(condition):
255 if callable(condition):
256 skip_condition = lambda : not condition()
256 skip_condition = lambda : not condition()
257 else:
257 else:
258 skip_condition = lambda : not condition
258 skip_condition = lambda : not condition
259
259
260 return skipif(skip_condition, msg)
260 return skipif(skip_condition, msg)
261
261
262 #-----------------------------------------------------------------------------
262 #-----------------------------------------------------------------------------
263 # Utility functions for decorators
263 # Utility functions for decorators
264 def module_not_available(module):
264 def module_not_available(module):
265 """Can module be imported? Returns true if module does NOT import.
265 """Can module be imported? Returns true if module does NOT import.
266
266
267 This is used to make a decorator to skip tests that require module to be
267 This is used to make a decorator to skip tests that require module to be
268 available, but delay the 'import numpy' to test execution time.
268 available, but delay the 'import numpy' to test execution time.
269 """
269 """
270 try:
270 try:
271 mod = __import__(module)
271 mod = __import__(module)
272 mod_not_avail = False
272 mod_not_avail = False
273 except ImportError:
273 except ImportError:
274 mod_not_avail = True
274 mod_not_avail = True
275
275
276 return mod_not_avail
276 return mod_not_avail
277
277
278
278
279 def decorated_dummy(dec, name):
279 def decorated_dummy(dec, name):
280 """Return a dummy function decorated with dec, with the given name.
280 """Return a dummy function decorated with dec, with the given name.
281
281
282 Examples
282 Examples
283 --------
283 --------
284 import IPython.testing.decorators as dec
284 import IPython.testing.decorators as dec
285 setup = dec.decorated_dummy(dec.skip_if_no_x11, __name__)
285 setup = dec.decorated_dummy(dec.skip_if_no_x11, __name__)
286 """
286 """
287 warnings.warn("The function `make_label_dec` is deprecated and might be removed in IPython 5.0", DeprecationWarning)
287 warnings.warn("The function `make_label_dec` is deprecated and might be removed in IPython 5.0", DeprecationWarning)
288 dummy = lambda: None
288 dummy = lambda: None
289 dummy.__name__ = name
289 dummy.__name__ = name
290 return dec(dummy)
290 return dec(dummy)
291
291
292 #-----------------------------------------------------------------------------
292 #-----------------------------------------------------------------------------
293 # Decorators for public use
293 # Decorators for public use
294
294
295 # Decorators to skip certain tests on specific platforms.
295 # Decorators to skip certain tests on specific platforms.
296 skip_win32 = skipif(sys.platform == 'win32',
296 skip_win32 = skipif(sys.platform == 'win32',
297 "This test does not run under Windows")
297 "This test does not run under Windows")
298 skip_linux = skipif(sys.platform.startswith('linux'),
298 skip_linux = skipif(sys.platform.startswith('linux'),
299 "This test does not run under Linux")
299 "This test does not run under Linux")
300 skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X")
300 skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X")
301
301
302
302
303 # Decorators to skip tests if not on specific platforms.
303 # Decorators to skip tests if not on specific platforms.
304 skip_if_not_win32 = skipif(sys.platform != 'win32',
304 skip_if_not_win32 = skipif(sys.platform != 'win32',
305 "This test only runs under Windows")
305 "This test only runs under Windows")
306 skip_if_not_linux = skipif(not sys.platform.startswith('linux'),
306 skip_if_not_linux = skipif(not sys.platform.startswith('linux'),
307 "This test only runs under Linux")
307 "This test only runs under Linux")
308 skip_if_not_osx = skipif(sys.platform != 'darwin',
308 skip_if_not_osx = skipif(sys.platform != 'darwin',
309 "This test only runs under OSX")
309 "This test only runs under OSX")
310
310
311
311
312 _x11_skip_cond = (sys.platform not in ('darwin', 'win32') and
312 _x11_skip_cond = (sys.platform not in ('darwin', 'win32') and
313 os.environ.get('DISPLAY', '') == '')
313 os.environ.get('DISPLAY', '') == '')
314 _x11_skip_msg = "Skipped under *nix when X11/XOrg not available"
314 _x11_skip_msg = "Skipped under *nix when X11/XOrg not available"
315
315
316 skip_if_no_x11 = skipif(_x11_skip_cond, _x11_skip_msg)
316 skip_if_no_x11 = skipif(_x11_skip_cond, _x11_skip_msg)
317
317
318 # not a decorator itself, returns a dummy function to be used as setup
318 # not a decorator itself, returns a dummy function to be used as setup
319 def skip_file_no_x11(name):
319 def skip_file_no_x11(name):
320 warnings.warn("The function `skip_file_no_x11` is deprecated and might be removed in IPython 5.0", DeprecationWarning)
320 warnings.warn("The function `skip_file_no_x11` is deprecated and might be removed in IPython 5.0", DeprecationWarning)
321 return decorated_dummy(skip_if_no_x11, name) if _x11_skip_cond else None
321 return decorated_dummy(skip_if_no_x11, name) if _x11_skip_cond else None
322
322
323 # Other skip decorators
323 # Other skip decorators
324
324
325 # generic skip without module
325 # generic skip without module
326 skip_without = lambda mod: skipif(module_not_available(mod), "This test requires %s" % mod)
326 skip_without = lambda mod: skipif(module_not_available(mod), "This test requires %s" % mod)
327
327
328 skipif_not_numpy = skip_without('numpy')
328 skipif_not_numpy = skip_without('numpy')
329
329
330 skipif_not_matplotlib = skip_without('matplotlib')
330 skipif_not_matplotlib = skip_without('matplotlib')
331
331
332 skipif_not_sympy = skip_without('sympy')
332 skipif_not_sympy = skip_without('sympy')
333
333
334 skip_known_failure = knownfailureif(True,'This test is known to fail')
334 skip_known_failure = knownfailureif(True,'This test is known to fail')
335
335
336 known_failure_py3 = knownfailureif(sys.version_info[0] >= 3,
336 known_failure_py3 = knownfailureif(sys.version_info[0] >= 3,
337 'This test is known to fail on Python 3.')
337 'This test is known to fail on Python 3.')
338
338
339 cpython2_only = skipif(PY3 or PYPY, "This test only runs on CPython 2.")
340 py2_only = skipif(PY3, "This test only runs on Python 2.")
339 py2_only = skipif(PY3, "This test only runs on Python 2.")
341 py3_only = skipif(PY2, "This test only runs on Python 3.")
340 py3_only = skipif(PY2, "This test only runs on Python 3.")
342
341
343 # A null 'decorator', useful to make more readable code that needs to pick
342 # A null 'decorator', useful to make more readable code that needs to pick
344 # between different decorators based on OS or other conditions
343 # between different decorators based on OS or other conditions
345 null_deco = lambda f: f
344 null_deco = lambda f: f
346
345
347 # Some tests only run where we can use unicode paths. Note that we can't just
346 # Some tests only run where we can use unicode paths. Note that we can't just
348 # check os.path.supports_unicode_filenames, which is always False on Linux.
347 # check os.path.supports_unicode_filenames, which is always False on Linux.
349 try:
348 try:
350 f = tempfile.NamedTemporaryFile(prefix=u"tmp€")
349 f = tempfile.NamedTemporaryFile(prefix=u"tmp€")
351 except UnicodeEncodeError:
350 except UnicodeEncodeError:
352 unicode_paths = False
351 unicode_paths = False
353 else:
352 else:
354 unicode_paths = True
353 unicode_paths = True
355 f.close()
354 f.close()
356
355
357 onlyif_unicode_paths = onlyif(unicode_paths, ("This test is only applicable "
356 onlyif_unicode_paths = onlyif(unicode_paths, ("This test is only applicable "
358 "where we can use unicode in filenames."))
357 "where we can use unicode in filenames."))
359
358
360
359
361 def onlyif_cmds_exist(*commands):
360 def onlyif_cmds_exist(*commands):
362 """
361 """
363 Decorator to skip test when at least one of `commands` is not found.
362 Decorator to skip test when at least one of `commands` is not found.
364 """
363 """
365 for cmd in commands:
364 for cmd in commands:
366 if not which(cmd):
365 if not which(cmd):
367 return skip("This test runs only if command '{0}' "
366 return skip("This test runs only if command '{0}' "
368 "is installed".format(cmd))
367 "is installed".format(cmd))
369 return null_deco
368 return null_deco
370
369
371 def onlyif_any_cmd_exists(*commands):
370 def onlyif_any_cmd_exists(*commands):
372 """
371 """
373 Decorator to skip test unless at least one of `commands` is found.
372 Decorator to skip test unless at least one of `commands` is found.
374 """
373 """
375 warnings.warn("The function `onlyif_any_cmd_exists` is deprecated and might be removed in IPython 5.0", DeprecationWarning)
374 warnings.warn("The function `onlyif_any_cmd_exists` is deprecated and might be removed in IPython 5.0", DeprecationWarning)
376 for cmd in commands:
375 for cmd in commands:
377 if which(cmd):
376 if which(cmd):
378 return null_deco
377 return null_deco
379 return skip("This test runs only if one of the commands {0} "
378 return skip("This test runs only if one of the commands {0} "
380 "is installed".format(commands))
379 "is installed".format(commands))
General Comments 0
You need to be logged in to leave comments. Login now