##// END OF EJS Templates
Make a few test non-optional....
Matthias Bussonnier -
Show More
@@ -1,192 +1,191 b''
1 1 # Copyright (c) IPython Development Team.
2 2 # Distributed under the terms of the Modified BSD License.
3 3
4 4 import json
5 import tempfile
6 5 import os
7 6 import warnings
8 7
9 8 import nose.tools as nt
10 9
11 10 from IPython.core import display
12 11 from IPython.core.getipython import get_ipython
13 12 from IPython.utils.tempdir import NamedFileInTemporaryDirectory
14 13 from IPython import paths as ipath
15 14
16 15 import IPython.testing.decorators as dec
17 16
18 17 def test_image_size():
19 18 """Simple test for display.Image(args, width=x,height=y)"""
20 19 thisurl = 'http://www.google.fr/images/srpr/logo3w.png'
21 20 img = display.Image(url=thisurl, width=200, height=200)
22 21 nt.assert_equal(u'<img src="%s" width="200" height="200"/>' % (thisurl), img._repr_html_())
23 22 img = display.Image(url=thisurl, width=200)
24 23 nt.assert_equal(u'<img src="%s" width="200"/>' % (thisurl), img._repr_html_())
25 24 img = display.Image(url=thisurl)
26 25 nt.assert_equal(u'<img src="%s"/>' % (thisurl), img._repr_html_())
27 26 img = display.Image(url=thisurl, unconfined=True)
28 27 nt.assert_equal(u'<img src="%s" class="unconfined"/>' % (thisurl), img._repr_html_())
29 28
30 29 def test_retina_png():
31 30 here = os.path.dirname(__file__)
32 31 img = display.Image(os.path.join(here, "2x2.png"), retina=True)
33 32 nt.assert_equal(img.height, 1)
34 33 nt.assert_equal(img.width, 1)
35 34 data, md = img._repr_png_()
36 35 nt.assert_equal(md['width'], 1)
37 36 nt.assert_equal(md['height'], 1)
38 37
39 38 def test_retina_jpeg():
40 39 here = os.path.dirname(__file__)
41 40 img = display.Image(os.path.join(here, "2x2.jpg"), retina=True)
42 41 nt.assert_equal(img.height, 1)
43 42 nt.assert_equal(img.width, 1)
44 43 data, md = img._repr_jpeg_()
45 44 nt.assert_equal(md['width'], 1)
46 45 nt.assert_equal(md['height'], 1)
47 46
48 47 def test_base64image():
49 48 display.Image("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94BCRQnOqNu0b4AAAAKSURBVAjXY2AAAAACAAHiIbwzAAAAAElFTkSuQmCC")
50 49
51 50 def test_image_filename_defaults():
52 51 '''test format constraint, and validity of jpeg and png'''
53 52 tpath = ipath.get_ipython_package_dir()
54 53 nt.assert_raises(ValueError, display.Image, filename=os.path.join(tpath, 'testing/tests/badformat.gif'),
55 54 embed=True)
56 55 nt.assert_raises(ValueError, display.Image)
57 56 nt.assert_raises(ValueError, display.Image, data='this is not an image', format='badformat', embed=True)
58 57 # check boths paths to allow packages to test at build and install time
59 58 imgfile = os.path.join(tpath, 'core/tests/2x2.png')
60 59 img = display.Image(filename=imgfile)
61 60 nt.assert_equal('png', img.format)
62 61 nt.assert_is_not_none(img._repr_png_())
63 62 img = display.Image(filename=os.path.join(tpath, 'testing/tests/logo.jpg'), embed=False)
64 63 nt.assert_equal('jpeg', img.format)
65 64 nt.assert_is_none(img._repr_jpeg_())
66 65
67 66 def _get_inline_config():
68 67 from ipykernel.pylab.config import InlineBackend
69 68 return InlineBackend.instance()
70 69
71 70 @dec.skip_without('matplotlib')
72 71 def test_set_matplotlib_close():
73 72 cfg = _get_inline_config()
74 73 cfg.close_figures = False
75 74 display.set_matplotlib_close()
76 75 assert cfg.close_figures
77 76 display.set_matplotlib_close(False)
78 77 assert not cfg.close_figures
79 78
80 79 _fmt_mime_map = {
81 80 'png': 'image/png',
82 81 'jpeg': 'image/jpeg',
83 82 'pdf': 'application/pdf',
84 83 'retina': 'image/png',
85 84 'svg': 'image/svg+xml',
86 85 }
87 86
88 87 @dec.skip_without('matplotlib')
89 88 def test_set_matplotlib_formats():
90 89 from matplotlib.figure import Figure
91 90 formatters = get_ipython().display_formatter.formatters
92 91 for formats in [
93 92 ('png',),
94 93 ('pdf', 'svg'),
95 94 ('jpeg', 'retina', 'png'),
96 95 (),
97 96 ]:
98 97 active_mimes = {_fmt_mime_map[fmt] for fmt in formats}
99 98 display.set_matplotlib_formats(*formats)
100 99 for mime, f in formatters.items():
101 100 if mime in active_mimes:
102 101 nt.assert_in(Figure, f)
103 102 else:
104 103 nt.assert_not_in(Figure, f)
105 104
106 105 @dec.skip_without('matplotlib')
107 106 def test_set_matplotlib_formats_kwargs():
108 107 from matplotlib.figure import Figure
109 108 ip = get_ipython()
110 109 cfg = _get_inline_config()
111 110 cfg.print_figure_kwargs.update(dict(foo='bar'))
112 111 kwargs = dict(quality=10)
113 112 display.set_matplotlib_formats('png', **kwargs)
114 113 formatter = ip.display_formatter.formatters['image/png']
115 114 f = formatter.lookup_by_type(Figure)
116 115 cell = f.__closure__[0].cell_contents
117 116 expected = kwargs
118 117 expected.update(cfg.print_figure_kwargs)
119 118 nt.assert_equal(cell, expected)
120 119
121 120 def test_displayobject_repr():
122 121 h = display.HTML('<br />')
123 122 nt.assert_equal(repr(h), '<IPython.core.display.HTML object>')
124 123 h._show_mem_addr = True
125 124 nt.assert_equal(repr(h), object.__repr__(h))
126 125 h._show_mem_addr = False
127 126 nt.assert_equal(repr(h), '<IPython.core.display.HTML object>')
128 127
129 128 j = display.Javascript('')
130 129 nt.assert_equal(repr(j), '<IPython.core.display.Javascript object>')
131 130 j._show_mem_addr = True
132 131 nt.assert_equal(repr(j), object.__repr__(j))
133 132 j._show_mem_addr = False
134 133 nt.assert_equal(repr(j), '<IPython.core.display.Javascript object>')
135 134
136 135 def test_json():
137 136 d = {'a': 5}
138 137 lis = [d]
139 138 j = display.JSON(d)
140 139 nt.assert_equal(j._repr_json_(), d)
141 140
142 141 with warnings.catch_warnings(record=True) as w:
143 142 warnings.simplefilter("always")
144 143 j = display.JSON(json.dumps(d))
145 144 nt.assert_equal(len(w), 1)
146 145 nt.assert_equal(j._repr_json_(), d)
147 146
148 147 j = display.JSON(lis)
149 148 nt.assert_equal(j._repr_json_(), lis)
150 149
151 150 with warnings.catch_warnings(record=True) as w:
152 151 warnings.simplefilter("always")
153 152 j = display.JSON(json.dumps(lis))
154 153 nt.assert_equal(len(w), 1)
155 154 nt.assert_equal(j._repr_json_(), lis)
156 155
157 156 def test_video_embedding():
158 157 """use a tempfile, with dummy-data, to ensure that video embedding doesn't crash"""
159 158 v = display.Video("http://ignored")
160 159 assert not v.embed
161 160 html = v._repr_html_()
162 161 nt.assert_not_in('src="data:', html)
163 162 nt.assert_in('src="http://ignored"', html)
164 163
165 164 with nt.assert_raises(ValueError):
166 165 v = display.Video(b'abc')
167 166
168 167 with NamedFileInTemporaryDirectory('test.mp4') as f:
169 168 f.write(b'abc')
170 169 f.close()
171 170
172 171 v = display.Video(f.name)
173 172 assert not v.embed
174 173 html = v._repr_html_()
175 174 nt.assert_not_in('src="data:', html)
176 175
177 176 v = display.Video(f.name, embed=True)
178 177 html = v._repr_html_()
179 178 nt.assert_in('src="data:video/mp4;base64,YWJj"',html)
180 179
181 180 v = display.Video(f.name, embed=True, mimetype='video/other')
182 181 html = v._repr_html_()
183 182 nt.assert_in('src="data:video/other;base64,YWJj"',html)
184 183
185 184 v = display.Video(b'abc', embed=True, mimetype='video/mp4')
186 185 html = v._repr_html_()
187 186 nt.assert_in('src="data:video/mp4;base64,YWJj"',html)
188 187
189 188 v = display.Video(u'YWJj', embed=True, mimetype='video/xyz')
190 189 html = v._repr_html_()
191 190 nt.assert_in('src="data:video/xyz;base64,YWJj"',html)
192 191
@@ -1,1002 +1,1002 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for various magic functions.
3 3
4 4 Needs to be run by nose (to make ipython session available).
5 5 """
6 6 from __future__ import absolute_import
7 7
8 8 import io
9 9 import os
10 10 import sys
11 11 import warnings
12 12 from unittest import TestCase
13 13
14 14 try:
15 15 from importlib import invalidate_caches # Required from Python 3.3
16 16 except ImportError:
17 17 def invalidate_caches():
18 18 pass
19 19
20 20 import nose.tools as nt
21 21
22 22 from IPython import get_ipython
23 23 from IPython.core import magic
24 24 from IPython.core.error import UsageError
25 25 from IPython.core.magic import (Magics, magics_class, line_magic,
26 26 cell_magic,
27 27 register_line_magic, register_cell_magic)
28 28 from IPython.core.magics import execution, script, code
29 29 from IPython.testing import decorators as dec
30 30 from IPython.testing import tools as tt
31 31 from IPython.utils import py3compat
32 32 from IPython.utils.io import capture_output
33 33 from IPython.utils.tempdir import TemporaryDirectory
34 34 from IPython.utils.process import find_cmd
35 35
36 36 if py3compat.PY3:
37 37 from io import StringIO
38 38 else:
39 39 from StringIO import StringIO
40 40
41 41
42 _ip = get_ipython()
43
42 44 @magic.magics_class
43 45 class DummyMagics(magic.Magics): pass
44 46
45 47 def test_extract_code_ranges():
46 48 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
47 49 expected = [(0, 1),
48 50 (2, 3),
49 51 (4, 6),
50 52 (6, 9),
51 53 (9, 14),
52 54 (16, None),
53 55 (None, 9),
54 56 (9, None),
55 57 (None, 13),
56 58 (None, None)]
57 59 actual = list(code.extract_code_ranges(instr))
58 60 nt.assert_equal(actual, expected)
59 61
60 62 def test_extract_symbols():
61 63 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
62 64 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
63 65 expected = [([], ['a']),
64 66 (["def b():\n return 42\n"], []),
65 67 (["class A: pass\n"], []),
66 68 (["class A: pass\n", "def b():\n return 42\n"], []),
67 69 (["class A: pass\n"], ['a']),
68 70 ([], ['z'])]
69 71 for symbols, exp in zip(symbols_args, expected):
70 72 nt.assert_equal(code.extract_symbols(source, symbols), exp)
71 73
72 74
73 75 def test_extract_symbols_raises_exception_with_non_python_code():
74 76 source = ("=begin A Ruby program :)=end\n"
75 77 "def hello\n"
76 78 "puts 'Hello world'\n"
77 79 "end")
78 80 with nt.assert_raises(SyntaxError):
79 81 code.extract_symbols(source, "hello")
80 82
81 83 def test_config():
82 84 """ test that config magic does not raise
83 85 can happen if Configurable init is moved too early into
84 86 Magics.__init__ as then a Config object will be registerd as a
85 87 magic.
86 88 """
87 89 ## should not raise.
88 90 _ip.magic('config')
89 91
90 92 def test_rehashx():
91 93 # clear up everything
92 _ip = get_ipython()
93 94 _ip.alias_manager.clear_aliases()
94 95 del _ip.db['syscmdlist']
95 96
96 97 _ip.magic('rehashx')
97 98 # Practically ALL ipython development systems will have more than 10 aliases
98 99
99 100 nt.assert_true(len(_ip.alias_manager.aliases) > 10)
100 101 for name, cmd in _ip.alias_manager.aliases:
101 102 # we must strip dots from alias names
102 103 nt.assert_not_in('.', name)
103 104
104 105 # rehashx must fill up syscmdlist
105 106 scoms = _ip.db['syscmdlist']
106 107 nt.assert_true(len(scoms) > 10)
107 108
108 109
109 110 def test_magic_parse_options():
110 111 """Test that we don't mangle paths when parsing magic options."""
111 112 ip = get_ipython()
112 113 path = 'c:\\x'
113 114 m = DummyMagics(ip)
114 115 opts = m.parse_options('-f %s' % path,'f:')[0]
115 116 # argv splitting is os-dependent
116 117 if os.name == 'posix':
117 118 expected = 'c:x'
118 119 else:
119 120 expected = path
120 121 nt.assert_equal(opts['f'], expected)
121 122
122 123 def test_magic_parse_long_options():
123 124 """Magic.parse_options can handle --foo=bar long options"""
124 125 ip = get_ipython()
125 126 m = DummyMagics(ip)
126 127 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
127 128 nt.assert_in('foo', opts)
128 129 nt.assert_in('bar', opts)
129 130 nt.assert_equal(opts['bar'], "bubble")
130 131
131 132
132 133 @dec.skip_without('sqlite3')
133 134 def doctest_hist_f():
134 135 """Test %hist -f with temporary filename.
135 136
136 137 In [9]: import tempfile
137 138
138 139 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
139 140
140 141 In [11]: %hist -nl -f $tfile 3
141 142
142 143 In [13]: import os; os.unlink(tfile)
143 144 """
144 145
145 146
146 147 @dec.skip_without('sqlite3')
147 148 def doctest_hist_r():
148 149 """Test %hist -r
149 150
150 151 XXX - This test is not recording the output correctly. For some reason, in
151 152 testing mode the raw history isn't getting populated. No idea why.
152 153 Disabling the output checking for now, though at least we do run it.
153 154
154 155 In [1]: 'hist' in _ip.lsmagic()
155 156 Out[1]: True
156 157
157 158 In [2]: x=1
158 159
159 160 In [3]: %hist -rl 2
160 161 x=1 # random
161 162 %hist -r 2
162 163 """
163 164
164 165
165 166 @dec.skip_without('sqlite3')
166 167 def doctest_hist_op():
167 168 """Test %hist -op
168 169
169 170 In [1]: class b(float):
170 171 ...: pass
171 172 ...:
172 173
173 174 In [2]: class s(object):
174 175 ...: def __str__(self):
175 176 ...: return 's'
176 177 ...:
177 178
178 179 In [3]:
179 180
180 181 In [4]: class r(b):
181 182 ...: def __repr__(self):
182 183 ...: return 'r'
183 184 ...:
184 185
185 186 In [5]: class sr(s,r): pass
186 187 ...:
187 188
188 189 In [6]:
189 190
190 191 In [7]: bb=b()
191 192
192 193 In [8]: ss=s()
193 194
194 195 In [9]: rr=r()
195 196
196 197 In [10]: ssrr=sr()
197 198
198 199 In [11]: 4.5
199 200 Out[11]: 4.5
200 201
201 202 In [12]: str(ss)
202 203 Out[12]: 's'
203 204
204 205 In [13]:
205 206
206 207 In [14]: %hist -op
207 208 >>> class b:
208 209 ... pass
209 210 ...
210 211 >>> class s(b):
211 212 ... def __str__(self):
212 213 ... return 's'
213 214 ...
214 215 >>>
215 216 >>> class r(b):
216 217 ... def __repr__(self):
217 218 ... return 'r'
218 219 ...
219 220 >>> class sr(s,r): pass
220 221 >>>
221 222 >>> bb=b()
222 223 >>> ss=s()
223 224 >>> rr=r()
224 225 >>> ssrr=sr()
225 226 >>> 4.5
226 227 4.5
227 228 >>> str(ss)
228 229 's'
229 230 >>>
230 231 """
231 232
232 233 def test_hist_pof():
233 234 ip = get_ipython()
234 235 ip.run_cell(u"1+2", store_history=True)
235 236 #raise Exception(ip.history_manager.session_number)
236 237 #raise Exception(list(ip.history_manager._get_range_session()))
237 238 with TemporaryDirectory() as td:
238 239 tf = os.path.join(td, 'hist.py')
239 240 ip.run_line_magic('history', '-pof %s' % tf)
240 241 assert os.path.isfile(tf)
241 242
242 243
243 244 @dec.skip_without('sqlite3')
244 245 def test_macro():
245 246 ip = get_ipython()
246 247 ip.history_manager.reset() # Clear any existing history.
247 248 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
248 249 for i, cmd in enumerate(cmds, start=1):
249 250 ip.history_manager.store_inputs(i, cmd)
250 251 ip.magic("macro test 1-3")
251 252 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
252 253
253 254 # List macros
254 255 nt.assert_in("test", ip.magic("macro"))
255 256
256 257
257 258 @dec.skip_without('sqlite3')
258 259 def test_macro_run():
259 260 """Test that we can run a multi-line macro successfully."""
260 261 ip = get_ipython()
261 262 ip.history_manager.reset()
262 263 cmds = ["a=10", "a+=1", py3compat.doctest_refactor_print("print a"),
263 264 "%macro test 2-3"]
264 265 for cmd in cmds:
265 266 ip.run_cell(cmd, store_history=True)
266 267 nt.assert_equal(ip.user_ns["test"].value,
267 268 py3compat.doctest_refactor_print("a+=1\nprint a\n"))
268 269 with tt.AssertPrints("12"):
269 270 ip.run_cell("test")
270 271 with tt.AssertPrints("13"):
271 272 ip.run_cell("test")
272 273
273 274
274 275 def test_magic_magic():
275 276 """Test %magic"""
276 277 ip = get_ipython()
277 278 with capture_output() as captured:
278 279 ip.magic("magic")
279 280
280 281 stdout = captured.stdout
281 282 nt.assert_in('%magic', stdout)
282 283 nt.assert_in('IPython', stdout)
283 284 nt.assert_in('Available', stdout)
284 285
285 286
286 287 @dec.skipif_not_numpy
287 288 def test_numpy_reset_array_undec():
288 289 "Test '%reset array' functionality"
289 290 _ip.ex('import numpy as np')
290 291 _ip.ex('a = np.empty(2)')
291 292 nt.assert_in('a', _ip.user_ns)
292 293 _ip.magic('reset -f array')
293 294 nt.assert_not_in('a', _ip.user_ns)
294 295
295 296 def test_reset_out():
296 297 "Test '%reset out' magic"
297 298 _ip.run_cell("parrot = 'dead'", store_history=True)
298 299 # test '%reset -f out', make an Out prompt
299 300 _ip.run_cell("parrot", store_history=True)
300 301 nt.assert_true('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
301 302 _ip.magic('reset -f out')
302 303 nt.assert_false('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
303 304 nt.assert_equal(len(_ip.user_ns['Out']), 0)
304 305
305 306 def test_reset_in():
306 307 "Test '%reset in' magic"
307 308 # test '%reset -f in'
308 309 _ip.run_cell("parrot", store_history=True)
309 310 nt.assert_true('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
310 311 _ip.magic('%reset -f in')
311 312 nt.assert_false('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
312 313 nt.assert_equal(len(set(_ip.user_ns['In'])), 1)
313 314
314 315 def test_reset_dhist():
315 316 "Test '%reset dhist' magic"
316 317 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
317 318 _ip.magic('cd ' + os.path.dirname(nt.__file__))
318 319 _ip.magic('cd -')
319 320 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
320 321 _ip.magic('reset -f dhist')
321 322 nt.assert_equal(len(_ip.user_ns['_dh']), 0)
322 323 _ip.run_cell("_dh = [d for d in tmp]") #restore
323 324
324 325 def test_reset_in_length():
325 326 "Test that '%reset in' preserves In[] length"
326 327 _ip.run_cell("print 'foo'")
327 328 _ip.run_cell("reset -f in")
328 329 nt.assert_equal(len(_ip.user_ns['In']), _ip.displayhook.prompt_count+1)
329 330
330 331 def test_tb_syntaxerror():
331 332 """test %tb after a SyntaxError"""
332 333 ip = get_ipython()
333 334 ip.run_cell("for")
334 335
335 336 # trap and validate stdout
336 337 save_stdout = sys.stdout
337 338 try:
338 339 sys.stdout = StringIO()
339 340 ip.run_cell("%tb")
340 341 out = sys.stdout.getvalue()
341 342 finally:
342 343 sys.stdout = save_stdout
343 344 # trim output, and only check the last line
344 345 last_line = out.rstrip().splitlines()[-1].strip()
345 346 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
346 347
347 348
348 349 def test_time():
349 350 ip = get_ipython()
350 351
351 352 with tt.AssertPrints("Wall time: "):
352 353 ip.run_cell("%time None")
353 354
354 355 ip.run_cell("def f(kmjy):\n"
355 356 " %time print (2*kmjy)")
356 357
357 358 with tt.AssertPrints("Wall time: "):
358 359 with tt.AssertPrints("hihi", suppress=False):
359 360 ip.run_cell("f('hi')")
360 361
361 362
362 363 @dec.skip_win32
363 364 def test_time2():
364 365 ip = get_ipython()
365 366
366 367 with tt.AssertPrints("CPU times: user "):
367 368 ip.run_cell("%time None")
368 369
369 370 def test_time3():
370 371 """Erroneous magic function calls, issue gh-3334"""
371 372 ip = get_ipython()
372 373 ip.user_ns.pop('run', None)
373 374
374 375 with tt.AssertNotPrints("not found", channel='stderr'):
375 376 ip.run_cell("%%time\n"
376 377 "run = 0\n"
377 378 "run += 1")
378 379
379 380 @dec.skipif(sys.version_info[0] >= 3, "no differences with __future__ in py3")
380 381 def test_time_futures():
381 382 "Test %time with __future__ environments"
382 383 ip = get_ipython()
383 384 ip.autocall = 0
384 385 ip.run_cell("from __future__ import division")
385 386 with tt.AssertPrints('0.25'):
386 387 ip.run_line_magic('time', 'print(1/4)')
387 388 ip.compile.reset_compiler_flags()
388 389 with tt.AssertNotPrints('0.25'):
389 390 ip.run_line_magic('time', 'print(1/4)')
390 391
391 392 def test_doctest_mode():
392 393 "Toggle doctest_mode twice, it should be a no-op and run without error"
393 394 _ip.magic('doctest_mode')
394 395 _ip.magic('doctest_mode')
395 396
396 397
397 398 def test_parse_options():
398 399 """Tests for basic options parsing in magics."""
399 400 # These are only the most minimal of tests, more should be added later. At
400 401 # the very least we check that basic text/unicode calls work OK.
401 402 m = DummyMagics(_ip)
402 403 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
403 404 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
404 405
405 406
406 407 def test_dirops():
407 408 """Test various directory handling operations."""
408 409 # curpath = lambda :os.path.splitdrive(py3compat.getcwd())[1].replace('\\','/')
409 410 curpath = py3compat.getcwd
410 411 startdir = py3compat.getcwd()
411 412 ipdir = os.path.realpath(_ip.ipython_dir)
412 413 try:
413 414 _ip.magic('cd "%s"' % ipdir)
414 415 nt.assert_equal(curpath(), ipdir)
415 416 _ip.magic('cd -')
416 417 nt.assert_equal(curpath(), startdir)
417 418 _ip.magic('pushd "%s"' % ipdir)
418 419 nt.assert_equal(curpath(), ipdir)
419 420 _ip.magic('popd')
420 421 nt.assert_equal(curpath(), startdir)
421 422 finally:
422 423 os.chdir(startdir)
423 424
424 425
425 426 def test_xmode():
426 427 # Calling xmode three times should be a no-op
427 428 xmode = _ip.InteractiveTB.mode
428 429 for i in range(3):
429 430 _ip.magic("xmode")
430 431 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
431 432
432 433 def test_reset_hard():
433 434 monitor = []
434 435 class A(object):
435 436 def __del__(self):
436 437 monitor.append(1)
437 438 def __repr__(self):
438 439 return "<A instance>"
439 440
440 441 _ip.user_ns["a"] = A()
441 442 _ip.run_cell("a")
442 443
443 444 nt.assert_equal(monitor, [])
444 445 _ip.magic("reset -f")
445 446 nt.assert_equal(monitor, [1])
446 447
447 448 class TestXdel(tt.TempFileMixin):
448 449 def test_xdel(self):
449 450 """Test that references from %run are cleared by xdel."""
450 451 src = ("class A(object):\n"
451 452 " monitor = []\n"
452 453 " def __del__(self):\n"
453 454 " self.monitor.append(1)\n"
454 455 "a = A()\n")
455 456 self.mktmp(src)
456 457 # %run creates some hidden references...
457 458 _ip.magic("run %s" % self.fname)
458 459 # ... as does the displayhook.
459 460 _ip.run_cell("a")
460 461
461 462 monitor = _ip.user_ns["A"].monitor
462 463 nt.assert_equal(monitor, [])
463 464
464 465 _ip.magic("xdel a")
465 466
466 467 # Check that a's __del__ method has been called.
467 468 nt.assert_equal(monitor, [1])
468 469
469 470 def doctest_who():
470 471 """doctest for %who
471 472
472 473 In [1]: %reset -f
473 474
474 475 In [2]: alpha = 123
475 476
476 477 In [3]: beta = 'beta'
477 478
478 479 In [4]: %who int
479 480 alpha
480 481
481 482 In [5]: %who str
482 483 beta
483 484
484 485 In [6]: %whos
485 486 Variable Type Data/Info
486 487 ----------------------------
487 488 alpha int 123
488 489 beta str beta
489 490
490 491 In [7]: %who_ls
491 492 Out[7]: ['alpha', 'beta']
492 493 """
493 494
494 495 def test_whos():
495 496 """Check that whos is protected against objects where repr() fails."""
496 497 class A(object):
497 498 def __repr__(self):
498 499 raise Exception()
499 500 _ip.user_ns['a'] = A()
500 501 _ip.magic("whos")
501 502
502 503 @py3compat.u_format
503 504 def doctest_precision():
504 505 """doctest for %precision
505 506
506 507 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
507 508
508 509 In [2]: %precision 5
509 510 Out[2]: {u}'%.5f'
510 511
511 512 In [3]: f.float_format
512 513 Out[3]: {u}'%.5f'
513 514
514 515 In [4]: %precision %e
515 516 Out[4]: {u}'%e'
516 517
517 518 In [5]: f(3.1415927)
518 519 Out[5]: {u}'3.141593e+00'
519 520 """
520 521
521 522 def test_psearch():
522 523 with tt.AssertPrints("dict.fromkeys"):
523 524 _ip.run_cell("dict.fr*?")
524 525
525 526 def test_timeit_shlex():
526 527 """test shlex issues with timeit (#1109)"""
527 528 _ip.ex("def f(*a,**kw): pass")
528 529 _ip.magic('timeit -n1 "this is a bug".count(" ")')
529 530 _ip.magic('timeit -r1 -n1 f(" ", 1)')
530 531 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
531 532 _ip.magic('timeit -r1 -n1 ("a " + "b")')
532 533 _ip.magic('timeit -r1 -n1 f("a " + "b")')
533 534 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
534 535
535 536
536 537 def test_timeit_arguments():
537 538 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
538 539 _ip.magic("timeit ('#')")
539 540
540 541
541 542 def test_timeit_special_syntax():
542 543 "Test %%timeit with IPython special syntax"
543 544 @register_line_magic
544 545 def lmagic(line):
545 546 ip = get_ipython()
546 547 ip.user_ns['lmagic_out'] = line
547 548
548 549 # line mode test
549 550 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
550 551 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
551 552 # cell mode test
552 553 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
553 554 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
554 555
555 556 def test_timeit_return():
556 557 """
557 558 test wether timeit -o return object
558 559 """
559 560
560 561 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
561 562 assert(res is not None)
562 563
563 564 def test_timeit_quiet():
564 565 """
565 566 test quiet option of timeit magic
566 567 """
567 568 with tt.AssertNotPrints("loops"):
568 569 _ip.run_cell("%timeit -n1 -r1 -q 1")
569 570
570 571 def test_timeit_return_quiet():
571 572 with tt.AssertNotPrints("loops"):
572 573 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
573 574 assert (res is not None)
574 575
575 576 @dec.skipif(sys.version_info[0] >= 3, "no differences with __future__ in py3")
576 577 def test_timeit_futures():
577 578 "Test %timeit with __future__ environments"
578 579 ip = get_ipython()
579 580 ip.run_cell("from __future__ import division")
580 581 with tt.AssertPrints('0.25'):
581 582 ip.run_line_magic('timeit', '-n1 -r1 print(1/4)')
582 583 ip.compile.reset_compiler_flags()
583 584 with tt.AssertNotPrints('0.25'):
584 585 ip.run_line_magic('timeit', '-n1 -r1 print(1/4)')
585 586
586 587 @dec.skipif(execution.profile is None)
587 588 def test_prun_special_syntax():
588 589 "Test %%prun with IPython special syntax"
589 590 @register_line_magic
590 591 def lmagic(line):
591 592 ip = get_ipython()
592 593 ip.user_ns['lmagic_out'] = line
593 594
594 595 # line mode test
595 596 _ip.run_line_magic('prun', '-q %lmagic my line')
596 597 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
597 598 # cell mode test
598 599 _ip.run_cell_magic('prun', '-q', '%lmagic my line2')
599 600 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
600 601
601 602 @dec.skipif(execution.profile is None)
602 603 def test_prun_quotes():
603 604 "Test that prun does not clobber string escapes (GH #1302)"
604 605 _ip.magic(r"prun -q x = '\t'")
605 606 nt.assert_equal(_ip.user_ns['x'], '\t')
606 607
607 608 def test_extension():
608 609 # Debugging information for failures of this test
609 610 print('sys.path:')
610 611 for p in sys.path:
611 612 print(' ', p)
612 613 print('CWD', os.getcwd())
613 614
614 615 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
615 616 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
616 617 sys.path.insert(0, daft_path)
617 618 try:
618 619 _ip.user_ns.pop('arq', None)
619 620 invalidate_caches() # Clear import caches
620 621 _ip.magic("load_ext daft_extension")
621 622 nt.assert_equal(_ip.user_ns['arq'], 185)
622 623 _ip.magic("unload_ext daft_extension")
623 624 assert 'arq' not in _ip.user_ns
624 625 finally:
625 626 sys.path.remove(daft_path)
626 627
627 628
628 @dec.skip_without('nbformat')
629 629 def test_notebook_export_json():
630 630 _ip = get_ipython()
631 631 _ip.history_manager.reset() # Clear any existing history.
632 632 cmds = [u"a=1", u"def b():\n return a**2", u"print('noΓ«l, Γ©tΓ©', b())"]
633 633 for i, cmd in enumerate(cmds, start=1):
634 634 _ip.history_manager.store_inputs(i, cmd)
635 635 with TemporaryDirectory() as td:
636 636 outfile = os.path.join(td, "nb.ipynb")
637 637 _ip.magic("notebook -e %s" % outfile)
638 638
639 639
640 640 class TestEnv(TestCase):
641 641
642 642 def test_env(self):
643 643 env = _ip.magic("env")
644 644 self.assertTrue(isinstance(env, dict))
645 645
646 646 def test_env_get_set_simple(self):
647 647 env = _ip.magic("env var val1")
648 648 self.assertEqual(env, None)
649 649 self.assertEqual(os.environ['var'], 'val1')
650 650 self.assertEqual(_ip.magic("env var"), 'val1')
651 651 env = _ip.magic("env var=val2")
652 652 self.assertEqual(env, None)
653 653 self.assertEqual(os.environ['var'], 'val2')
654 654
655 655 def test_env_get_set_complex(self):
656 656 env = _ip.magic("env var 'val1 '' 'val2")
657 657 self.assertEqual(env, None)
658 658 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
659 659 self.assertEqual(_ip.magic("env var"), "'val1 '' 'val2")
660 660 env = _ip.magic('env var=val2 val3="val4')
661 661 self.assertEqual(env, None)
662 662 self.assertEqual(os.environ['var'], 'val2 val3="val4')
663 663
664 664 def test_env_set_bad_input(self):
665 665 self.assertRaises(UsageError, lambda: _ip.magic("set_env var"))
666 666
667 667 def test_env_set_whitespace(self):
668 668 self.assertRaises(UsageError, lambda: _ip.magic("env var A=B"))
669 669
670 670
671 671 class CellMagicTestCase(TestCase):
672 672
673 673 def check_ident(self, magic):
674 674 # Manually called, we get the result
675 675 out = _ip.run_cell_magic(magic, 'a', 'b')
676 676 nt.assert_equal(out, ('a','b'))
677 677 # Via run_cell, it goes into the user's namespace via displayhook
678 678 _ip.run_cell('%%' + magic +' c\nd')
679 679 nt.assert_equal(_ip.user_ns['_'], ('c','d'))
680 680
681 681 def test_cell_magic_func_deco(self):
682 682 "Cell magic using simple decorator"
683 683 @register_cell_magic
684 684 def cellm(line, cell):
685 685 return line, cell
686 686
687 687 self.check_ident('cellm')
688 688
689 689 def test_cell_magic_reg(self):
690 690 "Cell magic manually registered"
691 691 def cellm(line, cell):
692 692 return line, cell
693 693
694 694 _ip.register_magic_function(cellm, 'cell', 'cellm2')
695 695 self.check_ident('cellm2')
696 696
697 697 def test_cell_magic_class(self):
698 698 "Cell magics declared via a class"
699 699 @magics_class
700 700 class MyMagics(Magics):
701 701
702 702 @cell_magic
703 703 def cellm3(self, line, cell):
704 704 return line, cell
705 705
706 706 _ip.register_magics(MyMagics)
707 707 self.check_ident('cellm3')
708 708
709 709 def test_cell_magic_class2(self):
710 710 "Cell magics declared via a class, #2"
711 711 @magics_class
712 712 class MyMagics2(Magics):
713 713
714 714 @cell_magic('cellm4')
715 715 def cellm33(self, line, cell):
716 716 return line, cell
717 717
718 718 _ip.register_magics(MyMagics2)
719 719 self.check_ident('cellm4')
720 720 # Check that nothing is registered as 'cellm33'
721 721 c33 = _ip.find_cell_magic('cellm33')
722 722 nt.assert_equal(c33, None)
723 723
724 724 def test_file():
725 725 """Basic %%file"""
726 726 ip = get_ipython()
727 727 with TemporaryDirectory() as td:
728 728 fname = os.path.join(td, 'file1')
729 729 ip.run_cell_magic("file", fname, u'\n'.join([
730 730 'line1',
731 731 'line2',
732 732 ]))
733 733 with open(fname) as f:
734 734 s = f.read()
735 735 nt.assert_in('line1\n', s)
736 736 nt.assert_in('line2', s)
737 737
738 738 def test_file_var_expand():
739 739 """%%file $filename"""
740 740 ip = get_ipython()
741 741 with TemporaryDirectory() as td:
742 742 fname = os.path.join(td, 'file1')
743 743 ip.user_ns['filename'] = fname
744 744 ip.run_cell_magic("file", '$filename', u'\n'.join([
745 745 'line1',
746 746 'line2',
747 747 ]))
748 748 with open(fname) as f:
749 749 s = f.read()
750 750 nt.assert_in('line1\n', s)
751 751 nt.assert_in('line2', s)
752 752
753 753 def test_file_unicode():
754 754 """%%file with unicode cell"""
755 755 ip = get_ipython()
756 756 with TemporaryDirectory() as td:
757 757 fname = os.path.join(td, 'file1')
758 758 ip.run_cell_magic("file", fname, u'\n'.join([
759 759 u'linΓ©1',
760 760 u'linΓ©2',
761 761 ]))
762 762 with io.open(fname, encoding='utf-8') as f:
763 763 s = f.read()
764 764 nt.assert_in(u'linΓ©1\n', s)
765 765 nt.assert_in(u'linΓ©2', s)
766 766
767 767 def test_file_amend():
768 768 """%%file -a amends files"""
769 769 ip = get_ipython()
770 770 with TemporaryDirectory() as td:
771 771 fname = os.path.join(td, 'file2')
772 772 ip.run_cell_magic("file", fname, u'\n'.join([
773 773 'line1',
774 774 'line2',
775 775 ]))
776 776 ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([
777 777 'line3',
778 778 'line4',
779 779 ]))
780 780 with open(fname) as f:
781 781 s = f.read()
782 782 nt.assert_in('line1\n', s)
783 783 nt.assert_in('line3\n', s)
784 784
785 785
786 786 def test_script_config():
787 787 ip = get_ipython()
788 788 ip.config.ScriptMagics.script_magics = ['whoda']
789 789 sm = script.ScriptMagics(shell=ip)
790 790 nt.assert_in('whoda', sm.magics['cell'])
791 791
792 792 @dec.skip_win32
793 793 def test_script_out():
794 794 ip = get_ipython()
795 795 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
796 796 nt.assert_equal(ip.user_ns['output'], 'hi\n')
797 797
798 798 @dec.skip_win32
799 799 def test_script_err():
800 800 ip = get_ipython()
801 801 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
802 802 nt.assert_equal(ip.user_ns['error'], 'hello\n')
803 803
804 804 @dec.skip_win32
805 805 def test_script_out_err():
806 806 ip = get_ipython()
807 807 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
808 808 nt.assert_equal(ip.user_ns['output'], 'hi\n')
809 809 nt.assert_equal(ip.user_ns['error'], 'hello\n')
810 810
811 811 @dec.skip_win32
812 812 def test_script_bg_out():
813 813 ip = get_ipython()
814 814 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
815 815 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
816 816
817 817 @dec.skip_win32
818 818 def test_script_bg_err():
819 819 ip = get_ipython()
820 820 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
821 821 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
822 822
823 823 @dec.skip_win32
824 824 def test_script_bg_out_err():
825 825 ip = get_ipython()
826 826 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
827 827 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
828 828 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
829 829
830 830 def test_script_defaults():
831 831 ip = get_ipython()
832 832 for cmd in ['sh', 'bash', 'perl', 'ruby']:
833 833 try:
834 834 find_cmd(cmd)
835 835 except Exception:
836 836 pass
837 837 else:
838 838 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
839 839
840 840
841 841 @magics_class
842 842 class FooFoo(Magics):
843 843 """class with both %foo and %%foo magics"""
844 844 @line_magic('foo')
845 845 def line_foo(self, line):
846 846 "I am line foo"
847 847 pass
848 848
849 849 @cell_magic("foo")
850 850 def cell_foo(self, line, cell):
851 851 "I am cell foo, not line foo"
852 852 pass
853 853
854 854 def test_line_cell_info():
855 855 """%%foo and %foo magics are distinguishable to inspect"""
856 856 ip = get_ipython()
857 857 ip.magics_manager.register(FooFoo)
858 858 oinfo = ip.object_inspect('foo')
859 859 nt.assert_true(oinfo['found'])
860 860 nt.assert_true(oinfo['ismagic'])
861 861
862 862 oinfo = ip.object_inspect('%%foo')
863 863 nt.assert_true(oinfo['found'])
864 864 nt.assert_true(oinfo['ismagic'])
865 865 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
866 866
867 867 oinfo = ip.object_inspect('%foo')
868 868 nt.assert_true(oinfo['found'])
869 869 nt.assert_true(oinfo['ismagic'])
870 870 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
871 871
872 872 def test_multiple_magics():
873 873 ip = get_ipython()
874 874 foo1 = FooFoo(ip)
875 875 foo2 = FooFoo(ip)
876 876 mm = ip.magics_manager
877 877 mm.register(foo1)
878 878 nt.assert_true(mm.magics['line']['foo'].__self__ is foo1)
879 879 mm.register(foo2)
880 880 nt.assert_true(mm.magics['line']['foo'].__self__ is foo2)
881 881
882 882 def test_alias_magic():
883 883 """Test %alias_magic."""
884 884 ip = get_ipython()
885 885 mm = ip.magics_manager
886 886
887 887 # Basic operation: both cell and line magics are created, if possible.
888 888 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
889 889 nt.assert_in('timeit_alias', mm.magics['line'])
890 890 nt.assert_in('timeit_alias', mm.magics['cell'])
891 891
892 892 # --cell is specified, line magic not created.
893 893 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
894 894 nt.assert_not_in('timeit_cell_alias', mm.magics['line'])
895 895 nt.assert_in('timeit_cell_alias', mm.magics['cell'])
896 896
897 897 # Test that line alias is created successfully.
898 898 ip.run_line_magic('alias_magic', '--line env_alias env')
899 899 nt.assert_equal(ip.run_line_magic('env', ''),
900 900 ip.run_line_magic('env_alias', ''))
901 901
902 902 def test_save():
903 903 """Test %save."""
904 904 ip = get_ipython()
905 905 ip.history_manager.reset() # Clear any existing history.
906 906 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
907 907 for i, cmd in enumerate(cmds, start=1):
908 908 ip.history_manager.store_inputs(i, cmd)
909 909 with TemporaryDirectory() as tmpdir:
910 910 file = os.path.join(tmpdir, "testsave.py")
911 911 ip.run_line_magic("save", "%s 1-10" % file)
912 912 with open(file) as f:
913 913 content = f.read()
914 914 nt.assert_equal(content.count(cmds[0]), 1)
915 915 nt.assert_in('coding: utf-8', content)
916 916 ip.run_line_magic("save", "-a %s 1-10" % file)
917 917 with open(file) as f:
918 918 content = f.read()
919 919 nt.assert_equal(content.count(cmds[0]), 2)
920 920 nt.assert_in('coding: utf-8', content)
921 921
922 922
923 923 def test_store():
924 924 """Test %store."""
925 925 ip = get_ipython()
926 926 ip.run_line_magic('load_ext', 'storemagic')
927 927
928 928 # make sure the storage is empty
929 929 ip.run_line_magic('store', '-z')
930 930 ip.user_ns['var'] = 42
931 931 ip.run_line_magic('store', 'var')
932 932 ip.user_ns['var'] = 39
933 933 ip.run_line_magic('store', '-r')
934 934 nt.assert_equal(ip.user_ns['var'], 42)
935 935
936 936 ip.run_line_magic('store', '-d var')
937 937 ip.user_ns['var'] = 39
938 938 ip.run_line_magic('store' , '-r')
939 939 nt.assert_equal(ip.user_ns['var'], 39)
940 940
941 941
942 942 def _run_edit_test(arg_s, exp_filename=None,
943 943 exp_lineno=-1,
944 944 exp_contents=None,
945 945 exp_is_temp=None):
946 946 ip = get_ipython()
947 947 M = code.CodeMagics(ip)
948 948 last_call = ['','']
949 949 opts,args = M.parse_options(arg_s,'prxn:')
950 950 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
951 951
952 952 if exp_filename is not None:
953 953 nt.assert_equal(exp_filename, filename)
954 954 if exp_contents is not None:
955 955 with io.open(filename, 'r', encoding='utf-8') as f:
956 956 contents = f.read()
957 957 nt.assert_equal(exp_contents, contents)
958 958 if exp_lineno != -1:
959 959 nt.assert_equal(exp_lineno, lineno)
960 960 if exp_is_temp is not None:
961 961 nt.assert_equal(exp_is_temp, is_temp)
962 962
963 963
964 964 def test_edit_interactive():
965 965 """%edit on interactively defined objects"""
966 966 ip = get_ipython()
967 967 n = ip.execution_count
968 968 ip.run_cell(u"def foo(): return 1", store_history=True)
969 969
970 970 try:
971 971 _run_edit_test("foo")
972 972 except code.InteractivelyDefined as e:
973 973 nt.assert_equal(e.index, n)
974 974 else:
975 975 raise AssertionError("Should have raised InteractivelyDefined")
976 976
977 977
978 978 def test_edit_cell():
979 979 """%edit [cell id]"""
980 980 ip = get_ipython()
981 981
982 982 ip.run_cell(u"def foo(): return 1", store_history=True)
983 983
984 984 # test
985 985 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
986 986
987 987 def test_bookmark():
988 988 ip = get_ipython()
989 989 ip.run_line_magic('bookmark', 'bmname')
990 990 with tt.AssertPrints('bmname'):
991 991 ip.run_line_magic('bookmark', '-l')
992 992 ip.run_line_magic('bookmark', '-d bmname')
993 993
994 994 def test_ls_magic():
995 995 ip = get_ipython()
996 996 json_formatter = ip.display_formatter.formatters['application/json']
997 997 json_formatter.enabled = True
998 998 lsmagic = ip.magic('lsmagic')
999 999 with warnings.catch_warnings(record=True) as w:
1000 1000 j = json_formatter(lsmagic)
1001 1001 nt.assert_equal(sorted(j), ['cell', 'line'])
1002 1002 nt.assert_equal(w, []) # no warnings
@@ -1,517 +1,517 b''
1 1 # encoding: utf-8
2 2 """Tests for code execution (%run and related), which is particularly tricky.
3 3
4 4 Because of how %run manages namespaces, and the fact that we are trying here to
5 5 verify subtle object deletion and reference counting issues, the %run tests
6 6 will be kept in this separate file. This makes it easier to aggregate in one
7 7 place the tricks needed to handle it; most other magics are much easier to test
8 8 and we do so in a common test_magic file.
9 9 """
10 10
11 11 # Copyright (c) IPython Development Team.
12 12 # Distributed under the terms of the Modified BSD License.
13 13
14 14 from __future__ import absolute_import
15 15
16 16
17 17 import functools
18 18 import os
19 19 from os.path import join as pjoin
20 20 import random
21 21 import sys
22 22 import tempfile
23 23 import textwrap
24 24 import unittest
25 25
26 26 try:
27 27 from unittest.mock import patch
28 28 except ImportError:
29 29 from mock import patch
30 30
31 31 import nose.tools as nt
32 32 from nose import SkipTest
33 33
34 34 from IPython.testing import decorators as dec
35 35 from IPython.testing import tools as tt
36 36 from IPython.utils import py3compat
37 37 from IPython.utils.io import capture_output
38 38 from IPython.utils.tempdir import TemporaryDirectory
39 39 from IPython.core import debugger
40 40
41 41
42 42 def doctest_refbug():
43 43 """Very nasty problem with references held by multiple runs of a script.
44 44 See: https://github.com/ipython/ipython/issues/141
45 45
46 46 In [1]: _ip.clear_main_mod_cache()
47 47 # random
48 48
49 49 In [2]: %run refbug
50 50
51 51 In [3]: call_f()
52 52 lowercased: hello
53 53
54 54 In [4]: %run refbug
55 55
56 56 In [5]: call_f()
57 57 lowercased: hello
58 58 lowercased: hello
59 59 """
60 60
61 61
62 62 def doctest_run_builtins():
63 63 r"""Check that %run doesn't damage __builtins__.
64 64
65 65 In [1]: import tempfile
66 66
67 67 In [2]: bid1 = id(__builtins__)
68 68
69 69 In [3]: fname = tempfile.mkstemp('.py')[1]
70 70
71 71 In [3]: f = open(fname,'w')
72 72
73 73 In [4]: dummy= f.write('pass\n')
74 74
75 75 In [5]: f.flush()
76 76
77 77 In [6]: t1 = type(__builtins__)
78 78
79 79 In [7]: %run $fname
80 80
81 81 In [7]: f.close()
82 82
83 83 In [8]: bid2 = id(__builtins__)
84 84
85 85 In [9]: t2 = type(__builtins__)
86 86
87 87 In [10]: t1 == t2
88 88 Out[10]: True
89 89
90 90 In [10]: bid1 == bid2
91 91 Out[10]: True
92 92
93 93 In [12]: try:
94 94 ....: os.unlink(fname)
95 95 ....: except:
96 96 ....: pass
97 97 ....:
98 98 """
99 99
100 100
101 101 def doctest_run_option_parser():
102 102 r"""Test option parser in %run.
103 103
104 104 In [1]: %run print_argv.py
105 105 []
106 106
107 107 In [2]: %run print_argv.py print*.py
108 108 ['print_argv.py']
109 109
110 110 In [3]: %run -G print_argv.py print*.py
111 111 ['print*.py']
112 112
113 113 """
114 114
115 115
116 116 @dec.skip_win32
117 117 def doctest_run_option_parser_for_posix():
118 118 r"""Test option parser in %run (Linux/OSX specific).
119 119
120 120 You need double quote to escape glob in POSIX systems:
121 121
122 122 In [1]: %run print_argv.py print\\*.py
123 123 ['print*.py']
124 124
125 125 You can't use quote to escape glob in POSIX systems:
126 126
127 127 In [2]: %run print_argv.py 'print*.py'
128 128 ['print_argv.py']
129 129
130 130 """
131 131
132 132
133 133 @dec.skip_if_not_win32
134 134 def doctest_run_option_parser_for_windows():
135 135 r"""Test option parser in %run (Windows specific).
136 136
137 137 In Windows, you can't escape ``*` `by backslash:
138 138
139 139 In [1]: %run print_argv.py print\\*.py
140 140 ['print\\*.py']
141 141
142 142 You can use quote to escape glob:
143 143
144 144 In [2]: %run print_argv.py 'print*.py'
145 145 ['print*.py']
146 146
147 147 """
148 148
149 149
150 150 @py3compat.doctest_refactor_print
151 151 def doctest_reset_del():
152 152 """Test that resetting doesn't cause errors in __del__ methods.
153 153
154 154 In [2]: class A(object):
155 155 ...: def __del__(self):
156 156 ...: print str("Hi")
157 157 ...:
158 158
159 159 In [3]: a = A()
160 160
161 161 In [4]: get_ipython().reset()
162 162 Hi
163 163
164 164 In [5]: 1+1
165 165 Out[5]: 2
166 166 """
167 167
168 168 # For some tests, it will be handy to organize them in a class with a common
169 169 # setup that makes a temp file
170 170
171 171 class TestMagicRunPass(tt.TempFileMixin):
172 172
173 173 def setup(self):
174 174 """Make a valid python temp file."""
175 175 self.mktmp('pass\n')
176 176
177 177 def run_tmpfile(self):
178 178 _ip = get_ipython()
179 179 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
180 180 # See below and ticket https://bugs.launchpad.net/bugs/366353
181 181 _ip.magic('run %s' % self.fname)
182 182
183 183 def run_tmpfile_p(self):
184 184 _ip = get_ipython()
185 185 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
186 186 # See below and ticket https://bugs.launchpad.net/bugs/366353
187 187 _ip.magic('run -p %s' % self.fname)
188 188
189 189 def test_builtins_id(self):
190 190 """Check that %run doesn't damage __builtins__ """
191 191 _ip = get_ipython()
192 192 # Test that the id of __builtins__ is not modified by %run
193 193 bid1 = id(_ip.user_ns['__builtins__'])
194 194 self.run_tmpfile()
195 195 bid2 = id(_ip.user_ns['__builtins__'])
196 196 nt.assert_equal(bid1, bid2)
197 197
198 198 def test_builtins_type(self):
199 199 """Check that the type of __builtins__ doesn't change with %run.
200 200
201 201 However, the above could pass if __builtins__ was already modified to
202 202 be a dict (it should be a module) by a previous use of %run. So we
203 203 also check explicitly that it really is a module:
204 204 """
205 205 _ip = get_ipython()
206 206 self.run_tmpfile()
207 207 nt.assert_equal(type(_ip.user_ns['__builtins__']),type(sys))
208 208
209 209 def test_prompts(self):
210 210 """Test that prompts correctly generate after %run"""
211 211 self.run_tmpfile()
212 212 _ip = get_ipython()
213 213 p2 = _ip.prompt_manager.render('in2').strip()
214 214 nt.assert_equal(p2[:3], '...')
215 215
216 216 def test_run_profile( self ):
217 217 """Test that the option -p, which invokes the profiler, do not
218 218 crash by invoking execfile"""
219 219 _ip = get_ipython()
220 220 self.run_tmpfile_p()
221 221
222 222
223 223 class TestMagicRunSimple(tt.TempFileMixin):
224 224
225 225 def test_simpledef(self):
226 226 """Test that simple class definitions work."""
227 227 src = ("class foo: pass\n"
228 228 "def f(): return foo()")
229 229 self.mktmp(src)
230 230 _ip.magic('run %s' % self.fname)
231 231 _ip.run_cell('t = isinstance(f(), foo)')
232 232 nt.assert_true(_ip.user_ns['t'])
233 233
234 234 def test_obj_del(self):
235 235 """Test that object's __del__ methods are called on exit."""
236 236 if sys.platform == 'win32':
237 237 try:
238 238 import win32api
239 239 except ImportError:
240 240 raise SkipTest("Test requires pywin32")
241 241 src = ("class A(object):\n"
242 242 " def __del__(self):\n"
243 243 " print 'object A deleted'\n"
244 244 "a = A()\n")
245 245 self.mktmp(py3compat.doctest_refactor_print(src))
246 246 if dec.module_not_available('sqlite3'):
247 247 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
248 248 else:
249 249 err = None
250 250 tt.ipexec_validate(self.fname, 'object A deleted', err)
251 251
252 252 def test_aggressive_namespace_cleanup(self):
253 253 """Test that namespace cleanup is not too aggressive GH-238
254 254
255 255 Returning from another run magic deletes the namespace"""
256 256 # see ticket https://github.com/ipython/ipython/issues/238
257 class secondtmp(tt.TempFileMixin): pass
258 empty = secondtmp()
257
258 with tt.TempFileMixin() as empty:
259 259 empty.mktmp('')
260 260 # On Windows, the filename will have \users in it, so we need to use the
261 261 # repr so that the \u becomes \\u.
262 262 src = ("ip = get_ipython()\n"
263 263 "for i in range(5):\n"
264 264 " try:\n"
265 265 " ip.magic(%r)\n"
266 266 " except NameError as e:\n"
267 267 " print(i)\n"
268 268 " break\n" % ('run ' + empty.fname))
269 269 self.mktmp(src)
270 270 _ip.magic('run %s' % self.fname)
271 271 _ip.run_cell('ip == get_ipython()')
272 272 nt.assert_equal(_ip.user_ns['i'], 4)
273 273
274 274 def test_run_second(self):
275 275 """Test that running a second file doesn't clobber the first, gh-3547
276 276 """
277 277 self.mktmp("avar = 1\n"
278 278 "def afunc():\n"
279 279 " return avar\n")
280 280
281 empty = tt.TempFileMixin()
281 with tt.TempFileMixin() as empty:
282 282 empty.mktmp("")
283 283
284 284 _ip.magic('run %s' % self.fname)
285 285 _ip.magic('run %s' % empty.fname)
286 286 nt.assert_equal(_ip.user_ns['afunc'](), 1)
287 287
288 288 @dec.skip_win32
289 289 def test_tclass(self):
290 290 mydir = os.path.dirname(__file__)
291 291 tc = os.path.join(mydir, 'tclass')
292 292 src = ("%%run '%s' C-first\n"
293 293 "%%run '%s' C-second\n"
294 294 "%%run '%s' C-third\n") % (tc, tc, tc)
295 295 self.mktmp(src, '.ipy')
296 296 out = """\
297 297 ARGV 1-: ['C-first']
298 298 ARGV 1-: ['C-second']
299 299 tclass.py: deleting object: C-first
300 300 ARGV 1-: ['C-third']
301 301 tclass.py: deleting object: C-second
302 302 tclass.py: deleting object: C-third
303 303 """
304 304 if dec.module_not_available('sqlite3'):
305 305 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
306 306 else:
307 307 err = None
308 308 tt.ipexec_validate(self.fname, out, err)
309 309
310 310 def test_run_i_after_reset(self):
311 311 """Check that %run -i still works after %reset (gh-693)"""
312 312 src = "yy = zz\n"
313 313 self.mktmp(src)
314 314 _ip.run_cell("zz = 23")
315 315 _ip.magic('run -i %s' % self.fname)
316 316 nt.assert_equal(_ip.user_ns['yy'], 23)
317 317 _ip.magic('reset -f')
318 318 _ip.run_cell("zz = 23")
319 319 _ip.magic('run -i %s' % self.fname)
320 320 nt.assert_equal(_ip.user_ns['yy'], 23)
321 321
322 322 def test_unicode(self):
323 323 """Check that files in odd encodings are accepted."""
324 324 mydir = os.path.dirname(__file__)
325 325 na = os.path.join(mydir, 'nonascii.py')
326 326 _ip.magic('run "%s"' % na)
327 327 nt.assert_equal(_ip.user_ns['u'], u'ΠŽΡ‚β„–Π€')
328 328
329 329 def test_run_py_file_attribute(self):
330 330 """Test handling of `__file__` attribute in `%run <file>.py`."""
331 331 src = "t = __file__\n"
332 332 self.mktmp(src)
333 333 _missing = object()
334 334 file1 = _ip.user_ns.get('__file__', _missing)
335 335 _ip.magic('run %s' % self.fname)
336 336 file2 = _ip.user_ns.get('__file__', _missing)
337 337
338 338 # Check that __file__ was equal to the filename in the script's
339 339 # namespace.
340 340 nt.assert_equal(_ip.user_ns['t'], self.fname)
341 341
342 342 # Check that __file__ was not leaked back into user_ns.
343 343 nt.assert_equal(file1, file2)
344 344
345 345 def test_run_ipy_file_attribute(self):
346 346 """Test handling of `__file__` attribute in `%run <file.ipy>`."""
347 347 src = "t = __file__\n"
348 348 self.mktmp(src, ext='.ipy')
349 349 _missing = object()
350 350 file1 = _ip.user_ns.get('__file__', _missing)
351 351 _ip.magic('run %s' % self.fname)
352 352 file2 = _ip.user_ns.get('__file__', _missing)
353 353
354 354 # Check that __file__ was equal to the filename in the script's
355 355 # namespace.
356 356 nt.assert_equal(_ip.user_ns['t'], self.fname)
357 357
358 358 # Check that __file__ was not leaked back into user_ns.
359 359 nt.assert_equal(file1, file2)
360 360
361 361 def test_run_formatting(self):
362 362 """ Test that %run -t -N<N> does not raise a TypeError for N > 1."""
363 363 src = "pass"
364 364 self.mktmp(src)
365 365 _ip.magic('run -t -N 1 %s' % self.fname)
366 366 _ip.magic('run -t -N 10 %s' % self.fname)
367 367
368 368 def test_ignore_sys_exit(self):
369 369 """Test the -e option to ignore sys.exit()"""
370 370 src = "import sys; sys.exit(1)"
371 371 self.mktmp(src)
372 372 with tt.AssertPrints('SystemExit'):
373 373 _ip.magic('run %s' % self.fname)
374 374
375 375 with tt.AssertNotPrints('SystemExit'):
376 376 _ip.magic('run -e %s' % self.fname)
377 377
378 378 @dec.skip_without('nbformat') # Requires jsonschema
379 379 def test_run_nb(self):
380 380 """Test %run notebook.ipynb"""
381 381 from nbformat import v4, writes
382 382 nb = v4.new_notebook(
383 383 cells=[
384 384 v4.new_markdown_cell("The Ultimate Question of Everything"),
385 385 v4.new_code_cell("answer=42")
386 386 ]
387 387 )
388 388 src = writes(nb, version=4)
389 389 self.mktmp(src, ext='.ipynb')
390 390
391 391 _ip.magic("run %s" % self.fname)
392 392
393 393 nt.assert_equal(_ip.user_ns['answer'], 42)
394 394
395 395
396 396
397 397 class TestMagicRunWithPackage(unittest.TestCase):
398 398
399 399 def writefile(self, name, content):
400 400 path = os.path.join(self.tempdir.name, name)
401 401 d = os.path.dirname(path)
402 402 if not os.path.isdir(d):
403 403 os.makedirs(d)
404 404 with open(path, 'w') as f:
405 405 f.write(textwrap.dedent(content))
406 406
407 407 def setUp(self):
408 408 self.package = package = 'tmp{0}'.format(repr(random.random())[2:])
409 409 """Temporary valid python package name."""
410 410
411 411 self.value = int(random.random() * 10000)
412 412
413 413 self.tempdir = TemporaryDirectory()
414 414 self.__orig_cwd = py3compat.getcwd()
415 415 sys.path.insert(0, self.tempdir.name)
416 416
417 417 self.writefile(os.path.join(package, '__init__.py'), '')
418 418 self.writefile(os.path.join(package, 'sub.py'), """
419 419 x = {0!r}
420 420 """.format(self.value))
421 421 self.writefile(os.path.join(package, 'relative.py'), """
422 422 from .sub import x
423 423 """)
424 424 self.writefile(os.path.join(package, 'absolute.py'), """
425 425 from {0}.sub import x
426 426 """.format(package))
427 427
428 428 def tearDown(self):
429 429 os.chdir(self.__orig_cwd)
430 430 sys.path[:] = [p for p in sys.path if p != self.tempdir.name]
431 431 self.tempdir.cleanup()
432 432
433 433 def check_run_submodule(self, submodule, opts=''):
434 434 _ip.user_ns.pop('x', None)
435 435 _ip.magic('run {2} -m {0}.{1}'.format(self.package, submodule, opts))
436 436 self.assertEqual(_ip.user_ns['x'], self.value,
437 437 'Variable `x` is not loaded from module `{0}`.'
438 438 .format(submodule))
439 439
440 440 def test_run_submodule_with_absolute_import(self):
441 441 self.check_run_submodule('absolute')
442 442
443 443 def test_run_submodule_with_relative_import(self):
444 444 """Run submodule that has a relative import statement (#2727)."""
445 445 self.check_run_submodule('relative')
446 446
447 447 def test_prun_submodule_with_absolute_import(self):
448 448 self.check_run_submodule('absolute', '-p')
449 449
450 450 def test_prun_submodule_with_relative_import(self):
451 451 self.check_run_submodule('relative', '-p')
452 452
453 453 def with_fake_debugger(func):
454 454 @functools.wraps(func)
455 455 def wrapper(*args, **kwds):
456 456 with patch.object(debugger.Pdb, 'run', staticmethod(eval)):
457 457 return func(*args, **kwds)
458 458 return wrapper
459 459
460 460 @with_fake_debugger
461 461 def test_debug_run_submodule_with_absolute_import(self):
462 462 self.check_run_submodule('absolute', '-d')
463 463
464 464 @with_fake_debugger
465 465 def test_debug_run_submodule_with_relative_import(self):
466 466 self.check_run_submodule('relative', '-d')
467 467
468 468 def test_run__name__():
469 469 with TemporaryDirectory() as td:
470 470 path = pjoin(td, 'foo.py')
471 471 with open(path, 'w') as f:
472 472 f.write("q = __name__")
473 473
474 474 _ip.user_ns.pop('q', None)
475 475 _ip.magic('run {}'.format(path))
476 476 nt.assert_equal(_ip.user_ns.pop('q'), '__main__')
477 477
478 478 _ip.magic('run -n {}'.format(path))
479 479 nt.assert_equal(_ip.user_ns.pop('q'), 'foo')
480 480
481 481 def test_run_tb():
482 482 """Test traceback offset in %run"""
483 483 with TemporaryDirectory() as td:
484 484 path = pjoin(td, 'foo.py')
485 485 with open(path, 'w') as f:
486 486 f.write('\n'.join([
487 487 "def foo():",
488 488 " return bar()",
489 489 "def bar():",
490 490 " raise RuntimeError('hello!')",
491 491 "foo()",
492 492 ]))
493 493 with capture_output() as io:
494 494 _ip.magic('run {}'.format(path))
495 495 out = io.stdout
496 496 nt.assert_not_in("execfile", out)
497 497 nt.assert_in("RuntimeError", out)
498 498 nt.assert_equal(out.count("---->"), 3)
499 499
500 500 @dec.knownfailureif(sys.platform == 'win32', "writes to io.stdout aren't captured on Windows")
501 501 def test_script_tb():
502 502 """Test traceback offset in `ipython script.py`"""
503 503 with TemporaryDirectory() as td:
504 504 path = pjoin(td, 'foo.py')
505 505 with open(path, 'w') as f:
506 506 f.write('\n'.join([
507 507 "def foo():",
508 508 " return bar()",
509 509 "def bar():",
510 510 " raise RuntimeError('hello!')",
511 511 "foo()",
512 512 ]))
513 513 out, err = tt.ipexec(path)
514 514 nt.assert_not_in("execfile", out)
515 515 nt.assert_in("RuntimeError", out)
516 516 nt.assert_equal(out.count("---->"), 3)
517 517
@@ -1,30 +1,29 b''
1 1 """Test help output of various IPython entry points"""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6 import IPython.testing.tools as tt
7 7 from IPython.testing.decorators import skip_without
8 8
9 9
10 10 def test_ipython_help():
11 11 tt.help_all_output_test()
12 12
13 13 def test_profile_help():
14 14 tt.help_all_output_test("profile")
15 15
16 16 def test_profile_list_help():
17 17 tt.help_all_output_test("profile list")
18 18
19 19 def test_profile_create_help():
20 20 tt.help_all_output_test("profile create")
21 21
22 22 def test_locate_help():
23 23 tt.help_all_output_test("locate")
24 24
25 25 def test_locate_profile_help():
26 26 tt.help_all_output_test("locate profile")
27 27
28 @skip_without('nbformat') # Requires jsonschema to be installed
29 28 def test_trust_help():
30 29 tt.help_all_output_test("trust")
@@ -1,434 +1,435 b''
1 1 # -*- coding: utf-8 -*-
2 2 """IPython Test Suite Runner.
3 3
4 4 This module provides a main entry point to a user script to test IPython
5 5 itself from the command line. There are two ways of running this script:
6 6
7 7 1. With the syntax `iptest all`. This runs our entire test suite by
8 8 calling this script (with different arguments) recursively. This
9 9 causes modules and package to be tested in different processes, using nose
10 10 or trial where appropriate.
11 11 2. With the regular nose syntax, like `iptest -vvs IPython`. In this form
12 12 the script simply calls nose, but with special command line flags and
13 13 plugins loaded.
14 14
15 15 """
16 16
17 17 # Copyright (c) IPython Development Team.
18 18 # Distributed under the terms of the Modified BSD License.
19 19
20 20 from __future__ import print_function
21 21
22 22 import glob
23 23 from io import BytesIO
24 24 import os
25 25 import os.path as path
26 26 import sys
27 27 from threading import Thread, Lock, Event
28 28 import warnings
29 29
30 30 import nose.plugins.builtin
31 31 from nose.plugins.xunit import Xunit
32 32 from nose import SkipTest
33 33 from nose.core import TestProgram
34 34 from nose.plugins import Plugin
35 35 from nose.util import safe_str
36 36
37 37 from IPython import version_info
38 38 from IPython.utils.py3compat import bytes_to_str
39 39 from IPython.utils.importstring import import_item
40 40 from IPython.testing.plugin.ipdoctest import IPythonDoctest
41 41 from IPython.external.decorators import KnownFailure, knownfailureif
42 42
43 43 pjoin = path.join
44 44
45 45
46 46 # Enable printing all warnings raise by IPython's modules
47 warnings.filterwarnings('ignore', message='.*Matplotlib is building the font cache.*', category=UserWarning, module='.*')
47 48 if sys.version_info > (3,0):
48 49 warnings.filterwarnings('error', message='.*', category=ResourceWarning, module='.*')
49 50 warnings.filterwarnings('default', message='.*', category=Warning, module='IPy.*')
50 51
51 52 if version_info < (6,):
52 53 # nose.tools renames all things from `camelCase` to `snake_case` which raise an
53 54 # warning with the runner they also import from standard import library. (as of Dec 2015)
54 55 # Ignore, let's revisit that in a couple of years for IPython 6.
55 56 warnings.filterwarnings('ignore', message='.*Please use assertEqual instead', category=Warning, module='IPython.*')
56 57
57 58
58 59 # ------------------------------------------------------------------------------
59 60 # Monkeypatch Xunit to count known failures as skipped.
60 61 # ------------------------------------------------------------------------------
61 62 def monkeypatch_xunit():
62 63 try:
63 64 knownfailureif(True)(lambda: None)()
64 65 except Exception as e:
65 66 KnownFailureTest = type(e)
66 67
67 68 def addError(self, test, err, capt=None):
68 69 if issubclass(err[0], KnownFailureTest):
69 70 err = (SkipTest,) + err[1:]
70 71 return self.orig_addError(test, err, capt)
71 72
72 73 Xunit.orig_addError = Xunit.addError
73 74 Xunit.addError = addError
74 75
75 76 #-----------------------------------------------------------------------------
76 77 # Check which dependencies are installed and greater than minimum version.
77 78 #-----------------------------------------------------------------------------
78 79 def extract_version(mod):
79 80 return mod.__version__
80 81
81 82 def test_for(item, min_version=None, callback=extract_version):
82 83 """Test to see if item is importable, and optionally check against a minimum
83 84 version.
84 85
85 86 If min_version is given, the default behavior is to check against the
86 87 `__version__` attribute of the item, but specifying `callback` allows you to
87 88 extract the value you are interested in. e.g::
88 89
89 90 In [1]: import sys
90 91
91 92 In [2]: from IPython.testing.iptest import test_for
92 93
93 94 In [3]: test_for('sys', (2,6), callback=lambda sys: sys.version_info)
94 95 Out[3]: True
95 96
96 97 """
97 98 try:
98 99 check = import_item(item)
99 100 except (ImportError, RuntimeError):
100 101 # GTK reports Runtime error if it can't be initialized even if it's
101 102 # importable.
102 103 return False
103 104 else:
104 105 if min_version:
105 106 if callback:
106 107 # extra processing step to get version to compare
107 108 check = callback(check)
108 109
109 110 return check >= min_version
110 111 else:
111 112 return True
112 113
113 114 # Global dict where we can store information on what we have and what we don't
114 115 # have available at test run time
115 116 have = {'matplotlib': test_for('matplotlib'),
116 117 'pygments': test_for('pygments'),
117 118 'sqlite3': test_for('sqlite3')}
118 119
119 120 #-----------------------------------------------------------------------------
120 121 # Test suite definitions
121 122 #-----------------------------------------------------------------------------
122 123
123 124 test_group_names = ['core',
124 125 'extensions', 'lib', 'terminal', 'testing', 'utils',
125 126 ]
126 127
127 128 class TestSection(object):
128 129 def __init__(self, name, includes):
129 130 self.name = name
130 131 self.includes = includes
131 132 self.excludes = []
132 133 self.dependencies = []
133 134 self.enabled = True
134 135
135 136 def exclude(self, module):
136 137 if not module.startswith('IPython'):
137 138 module = self.includes[0] + "." + module
138 139 self.excludes.append(module.replace('.', os.sep))
139 140
140 141 def requires(self, *packages):
141 142 self.dependencies.extend(packages)
142 143
143 144 @property
144 145 def will_run(self):
145 146 return self.enabled and all(have[p] for p in self.dependencies)
146 147
147 148 # Name -> (include, exclude, dependencies_met)
148 149 test_sections = {n:TestSection(n, ['IPython.%s' % n]) for n in test_group_names}
149 150
150 151
151 152 # Exclusions and dependencies
152 153 # ---------------------------
153 154
154 155 # core:
155 156 sec = test_sections['core']
156 157 if not have['sqlite3']:
157 158 sec.exclude('tests.test_history')
158 159 sec.exclude('history')
159 160 if not have['matplotlib']:
160 161 sec.exclude('pylabtools'),
161 162 sec.exclude('tests.test_pylabtools')
162 163
163 164 # lib:
164 165 sec = test_sections['lib']
165 166 sec.exclude('kernel')
166 167 if not have['pygments']:
167 168 sec.exclude('tests.test_lexers')
168 169 # We do this unconditionally, so that the test suite doesn't import
169 170 # gtk, changing the default encoding and masking some unicode bugs.
170 171 sec.exclude('inputhookgtk')
171 172 # We also do this unconditionally, because wx can interfere with Unix signals.
172 173 # There are currently no tests for it anyway.
173 174 sec.exclude('inputhookwx')
174 175 # Testing inputhook will need a lot of thought, to figure out
175 176 # how to have tests that don't lock up with the gui event
176 177 # loops in the picture
177 178 sec.exclude('inputhook')
178 179
179 180 # testing:
180 181 sec = test_sections['testing']
181 182 # These have to be skipped on win32 because they use echo, rm, cd, etc.
182 183 # See ticket https://github.com/ipython/ipython/issues/87
183 184 if sys.platform == 'win32':
184 185 sec.exclude('plugin.test_exampleip')
185 186 sec.exclude('plugin.dtexample')
186 187
187 188 # don't run jupyter_console tests found via shim
188 189 test_sections['terminal'].exclude('console')
189 190
190 191 # extensions:
191 192 sec = test_sections['extensions']
192 193 # This is deprecated in favour of rpy2
193 194 sec.exclude('rmagic')
194 195 # autoreload does some strange stuff, so move it to its own test section
195 196 sec.exclude('autoreload')
196 197 sec.exclude('tests.test_autoreload')
197 198 test_sections['autoreload'] = TestSection('autoreload',
198 199 ['IPython.extensions.autoreload', 'IPython.extensions.tests.test_autoreload'])
199 200 test_group_names.append('autoreload')
200 201
201 202
202 203 #-----------------------------------------------------------------------------
203 204 # Functions and classes
204 205 #-----------------------------------------------------------------------------
205 206
206 207 def check_exclusions_exist():
207 208 from IPython.paths import get_ipython_package_dir
208 209 from warnings import warn
209 210 parent = os.path.dirname(get_ipython_package_dir())
210 211 for sec in test_sections:
211 212 for pattern in sec.exclusions:
212 213 fullpath = pjoin(parent, pattern)
213 214 if not os.path.exists(fullpath) and not glob.glob(fullpath + '.*'):
214 215 warn("Excluding nonexistent file: %r" % pattern)
215 216
216 217
217 218 class ExclusionPlugin(Plugin):
218 219 """A nose plugin to effect our exclusions of files and directories.
219 220 """
220 221 name = 'exclusions'
221 222 score = 3000 # Should come before any other plugins
222 223
223 224 def __init__(self, exclude_patterns=None):
224 225 """
225 226 Parameters
226 227 ----------
227 228
228 229 exclude_patterns : sequence of strings, optional
229 230 Filenames containing these patterns (as raw strings, not as regular
230 231 expressions) are excluded from the tests.
231 232 """
232 233 self.exclude_patterns = exclude_patterns or []
233 234 super(ExclusionPlugin, self).__init__()
234 235
235 236 def options(self, parser, env=os.environ):
236 237 Plugin.options(self, parser, env)
237 238
238 239 def configure(self, options, config):
239 240 Plugin.configure(self, options, config)
240 241 # Override nose trying to disable plugin.
241 242 self.enabled = True
242 243
243 244 def wantFile(self, filename):
244 245 """Return whether the given filename should be scanned for tests.
245 246 """
246 247 if any(pat in filename for pat in self.exclude_patterns):
247 248 return False
248 249 return None
249 250
250 251 def wantDirectory(self, directory):
251 252 """Return whether the given directory should be scanned for tests.
252 253 """
253 254 if any(pat in directory for pat in self.exclude_patterns):
254 255 return False
255 256 return None
256 257
257 258
258 259 class StreamCapturer(Thread):
259 260 daemon = True # Don't hang if main thread crashes
260 261 started = False
261 262 def __init__(self, echo=False):
262 263 super(StreamCapturer, self).__init__()
263 264 self.echo = echo
264 265 self.streams = []
265 266 self.buffer = BytesIO()
266 267 self.readfd, self.writefd = os.pipe()
267 268 self.buffer_lock = Lock()
268 269 self.stop = Event()
269 270
270 271 def run(self):
271 272 self.started = True
272 273
273 274 while not self.stop.is_set():
274 275 chunk = os.read(self.readfd, 1024)
275 276
276 277 with self.buffer_lock:
277 278 self.buffer.write(chunk)
278 279 if self.echo:
279 280 sys.stdout.write(bytes_to_str(chunk))
280 281
281 282 os.close(self.readfd)
282 283 os.close(self.writefd)
283 284
284 285 def reset_buffer(self):
285 286 with self.buffer_lock:
286 287 self.buffer.truncate(0)
287 288 self.buffer.seek(0)
288 289
289 290 def get_buffer(self):
290 291 with self.buffer_lock:
291 292 return self.buffer.getvalue()
292 293
293 294 def ensure_started(self):
294 295 if not self.started:
295 296 self.start()
296 297
297 298 def halt(self):
298 299 """Safely stop the thread."""
299 300 if not self.started:
300 301 return
301 302
302 303 self.stop.set()
303 304 os.write(self.writefd, b'\0') # Ensure we're not locked in a read()
304 305 self.join()
305 306
306 307 class SubprocessStreamCapturePlugin(Plugin):
307 308 name='subprocstreams'
308 309 def __init__(self):
309 310 Plugin.__init__(self)
310 311 self.stream_capturer = StreamCapturer()
311 312 self.destination = os.environ.get('IPTEST_SUBPROC_STREAMS', 'capture')
312 313 # This is ugly, but distant parts of the test machinery need to be able
313 314 # to redirect streams, so we make the object globally accessible.
314 315 nose.iptest_stdstreams_fileno = self.get_write_fileno
315 316
316 317 def get_write_fileno(self):
317 318 if self.destination == 'capture':
318 319 self.stream_capturer.ensure_started()
319 320 return self.stream_capturer.writefd
320 321 elif self.destination == 'discard':
321 322 return os.open(os.devnull, os.O_WRONLY)
322 323 else:
323 324 return sys.__stdout__.fileno()
324 325
325 326 def configure(self, options, config):
326 327 Plugin.configure(self, options, config)
327 328 # Override nose trying to disable plugin.
328 329 if self.destination == 'capture':
329 330 self.enabled = True
330 331
331 332 def startTest(self, test):
332 333 # Reset log capture
333 334 self.stream_capturer.reset_buffer()
334 335
335 336 def formatFailure(self, test, err):
336 337 # Show output
337 338 ec, ev, tb = err
338 339 captured = self.stream_capturer.get_buffer().decode('utf-8', 'replace')
339 340 if captured.strip():
340 341 ev = safe_str(ev)
341 342 out = [ev, '>> begin captured subprocess output <<',
342 343 captured,
343 344 '>> end captured subprocess output <<']
344 345 return ec, '\n'.join(out), tb
345 346
346 347 return err
347 348
348 349 formatError = formatFailure
349 350
350 351 def finalize(self, result):
351 352 self.stream_capturer.halt()
352 353
353 354
354 355 def run_iptest():
355 356 """Run the IPython test suite using nose.
356 357
357 358 This function is called when this script is **not** called with the form
358 359 `iptest all`. It simply calls nose with appropriate command line flags
359 360 and accepts all of the standard nose arguments.
360 361 """
361 362 # Apply our monkeypatch to Xunit
362 363 if '--with-xunit' in sys.argv and not hasattr(Xunit, 'orig_addError'):
363 364 monkeypatch_xunit()
364 365
365 366 warnings.filterwarnings('ignore',
366 367 'This will be removed soon. Use IPython.testing.util instead')
367 368
368 369 arg1 = sys.argv[1]
369 370 if arg1 in test_sections:
370 371 section = test_sections[arg1]
371 372 sys.argv[1:2] = section.includes
372 373 elif arg1.startswith('IPython.') and arg1[8:] in test_sections:
373 374 section = test_sections[arg1[8:]]
374 375 sys.argv[1:2] = section.includes
375 376 else:
376 377 section = TestSection(arg1, includes=[arg1])
377 378
378 379
379 380 argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
380 381 # We add --exe because of setuptools' imbecility (it
381 382 # blindly does chmod +x on ALL files). Nose does the
382 383 # right thing and it tries to avoid executables,
383 384 # setuptools unfortunately forces our hand here. This
384 385 # has been discussed on the distutils list and the
385 386 # setuptools devs refuse to fix this problem!
386 387 '--exe',
387 388 ]
388 389 if '-a' not in argv and '-A' not in argv:
389 390 argv = argv + ['-a', '!crash']
390 391
391 392 if nose.__version__ >= '0.11':
392 393 # I don't fully understand why we need this one, but depending on what
393 394 # directory the test suite is run from, if we don't give it, 0 tests
394 395 # get run. Specifically, if the test suite is run from the source dir
395 396 # with an argument (like 'iptest.py IPython.core', 0 tests are run,
396 397 # even if the same call done in this directory works fine). It appears
397 398 # that if the requested package is in the current dir, nose bails early
398 399 # by default. Since it's otherwise harmless, leave it in by default
399 400 # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it.
400 401 argv.append('--traverse-namespace')
401 402
402 403 plugins = [ ExclusionPlugin(section.excludes), KnownFailure(),
403 404 SubprocessStreamCapturePlugin() ]
404 405
405 406 # we still have some vestigial doctests in core
406 407 if (section.name.startswith(('core', 'IPython.core'))):
407 408 plugins.append(IPythonDoctest())
408 409 argv.extend([
409 410 '--with-ipdoctest',
410 411 '--ipdoctest-tests',
411 412 '--ipdoctest-extension=txt',
412 413 ])
413 414
414 415
415 416 # Use working directory set by parent process (see iptestcontroller)
416 417 if 'IPTEST_WORKING_DIR' in os.environ:
417 418 os.chdir(os.environ['IPTEST_WORKING_DIR'])
418 419
419 420 # We need a global ipython running in this process, but the special
420 421 # in-process group spawns its own IPython kernels, so for *that* group we
421 422 # must avoid also opening the global one (otherwise there's a conflict of
422 423 # singletons). Ultimately the solution to this problem is to refactor our
423 424 # assumptions about what needs to be a singleton and what doesn't (app
424 425 # objects should, individual shells shouldn't). But for now, this
425 426 # workaround allows the test suite for the inprocess module to complete.
426 427 if 'kernel.inprocess' not in section.name:
427 428 from IPython.testing import globalipapp
428 429 globalipapp.start_ipython()
429 430
430 431 # Now nose can run
431 432 TestProgram(argv=argv, addplugins=plugins)
432 433
433 434 if __name__ == '__main__':
434 435 run_iptest()
@@ -1,467 +1,474 b''
1 1 """Generic testing tools.
2 2
3 3 Authors
4 4 -------
5 5 - Fernando Perez <Fernando.Perez@berkeley.edu>
6 6 """
7 7
8 8 from __future__ import absolute_import
9 9
10 10 #-----------------------------------------------------------------------------
11 11 # Copyright (C) 2009 The IPython Development Team
12 12 #
13 13 # Distributed under the terms of the BSD License. The full license is in
14 14 # the file COPYING, distributed as part of this software.
15 15 #-----------------------------------------------------------------------------
16 16
17 17 #-----------------------------------------------------------------------------
18 18 # Imports
19 19 #-----------------------------------------------------------------------------
20 20
21 21 import os
22 22 import re
23 23 import sys
24 24 import tempfile
25 25
26 26 from contextlib import contextmanager
27 27 from io import StringIO
28 28 from subprocess import Popen, PIPE
29 29
30 30 try:
31 31 # These tools are used by parts of the runtime, so we make the nose
32 32 # dependency optional at this point. Nose is a hard dependency to run the
33 33 # test suite, but NOT to use ipython itself.
34 34 import nose.tools as nt
35 35 has_nose = True
36 36 except ImportError:
37 37 has_nose = False
38 38
39 39 from traitlets.config.loader import Config
40 40 from IPython.utils.process import get_output_error_code
41 41 from IPython.utils.text import list_strings
42 42 from IPython.utils.io import temp_pyfile, Tee
43 43 from IPython.utils import py3compat
44 44 from IPython.utils.encoding import DEFAULT_ENCODING
45 45
46 46 from . import decorators as dec
47 47 from . import skipdoctest
48 48
49 49 #-----------------------------------------------------------------------------
50 50 # Functions and classes
51 51 #-----------------------------------------------------------------------------
52 52
53 53 # The docstring for full_path doctests differently on win32 (different path
54 54 # separator) so just skip the doctest there. The example remains informative.
55 55 doctest_deco = skipdoctest.skip_doctest if sys.platform == 'win32' else dec.null_deco
56 56
57 57 @doctest_deco
58 58 def full_path(startPath,files):
59 59 """Make full paths for all the listed files, based on startPath.
60 60
61 61 Only the base part of startPath is kept, since this routine is typically
62 62 used with a script's ``__file__`` variable as startPath. The base of startPath
63 63 is then prepended to all the listed files, forming the output list.
64 64
65 65 Parameters
66 66 ----------
67 67 startPath : string
68 68 Initial path to use as the base for the results. This path is split
69 69 using os.path.split() and only its first component is kept.
70 70
71 71 files : string or list
72 72 One or more files.
73 73
74 74 Examples
75 75 --------
76 76
77 77 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
78 78 ['/foo/a.txt', '/foo/b.txt']
79 79
80 80 >>> full_path('/foo',['a.txt','b.txt'])
81 81 ['/a.txt', '/b.txt']
82 82
83 83 If a single file is given, the output is still a list::
84 84
85 85 >>> full_path('/foo','a.txt')
86 86 ['/a.txt']
87 87 """
88 88
89 89 files = list_strings(files)
90 90 base = os.path.split(startPath)[0]
91 91 return [ os.path.join(base,f) for f in files ]
92 92
93 93
94 94 def parse_test_output(txt):
95 95 """Parse the output of a test run and return errors, failures.
96 96
97 97 Parameters
98 98 ----------
99 99 txt : str
100 100 Text output of a test run, assumed to contain a line of one of the
101 101 following forms::
102 102
103 103 'FAILED (errors=1)'
104 104 'FAILED (failures=1)'
105 105 'FAILED (errors=1, failures=1)'
106 106
107 107 Returns
108 108 -------
109 109 nerr, nfail
110 110 number of errors and failures.
111 111 """
112 112
113 113 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
114 114 if err_m:
115 115 nerr = int(err_m.group(1))
116 116 nfail = 0
117 117 return nerr, nfail
118 118
119 119 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
120 120 if fail_m:
121 121 nerr = 0
122 122 nfail = int(fail_m.group(1))
123 123 return nerr, nfail
124 124
125 125 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
126 126 re.MULTILINE)
127 127 if both_m:
128 128 nerr = int(both_m.group(1))
129 129 nfail = int(both_m.group(2))
130 130 return nerr, nfail
131 131
132 132 # If the input didn't match any of these forms, assume no error/failures
133 133 return 0, 0
134 134
135 135
136 136 # So nose doesn't think this is a test
137 137 parse_test_output.__test__ = False
138 138
139 139
140 140 def default_argv():
141 141 """Return a valid default argv for creating testing instances of ipython"""
142 142
143 143 return ['--quick', # so no config file is loaded
144 144 # Other defaults to minimize side effects on stdout
145 145 '--colors=NoColor', '--no-term-title','--no-banner',
146 146 '--autocall=0']
147 147
148 148
149 149 def default_config():
150 150 """Return a config object with good defaults for testing."""
151 151 config = Config()
152 152 config.TerminalInteractiveShell.colors = 'NoColor'
153 153 config.TerminalTerminalInteractiveShell.term_title = False,
154 154 config.TerminalInteractiveShell.autocall = 0
155 155 f = tempfile.NamedTemporaryFile(suffix=u'test_hist.sqlite', delete=False)
156 156 config.HistoryManager.hist_file = f.name
157 157 f.close()
158 158 config.HistoryManager.db_cache_size = 10000
159 159 return config
160 160
161 161
162 162 def get_ipython_cmd(as_string=False):
163 163 """
164 164 Return appropriate IPython command line name. By default, this will return
165 165 a list that can be used with subprocess.Popen, for example, but passing
166 166 `as_string=True` allows for returning the IPython command as a string.
167 167
168 168 Parameters
169 169 ----------
170 170 as_string: bool
171 171 Flag to allow to return the command as a string.
172 172 """
173 173 ipython_cmd = [sys.executable, "-m", "IPython"]
174 174
175 175 if as_string:
176 176 ipython_cmd = " ".join(ipython_cmd)
177 177
178 178 return ipython_cmd
179 179
180 180 def ipexec(fname, options=None, commands=()):
181 181 """Utility to call 'ipython filename'.
182 182
183 183 Starts IPython with a minimal and safe configuration to make startup as fast
184 184 as possible.
185 185
186 186 Note that this starts IPython in a subprocess!
187 187
188 188 Parameters
189 189 ----------
190 190 fname : str
191 191 Name of file to be executed (should have .py or .ipy extension).
192 192
193 193 options : optional, list
194 194 Extra command-line flags to be passed to IPython.
195 195
196 196 commands : optional, list
197 197 Commands to send in on stdin
198 198
199 199 Returns
200 200 -------
201 201 (stdout, stderr) of ipython subprocess.
202 202 """
203 203 if options is None: options = []
204 204
205 205 # For these subprocess calls, eliminate all prompt printing so we only see
206 206 # output from script execution
207 207 prompt_opts = [ '--PromptManager.in_template=""',
208 208 '--PromptManager.in2_template=""',
209 209 '--PromptManager.out_template=""'
210 210 ]
211 211 cmdargs = default_argv() + prompt_opts + options
212 212
213 213 test_dir = os.path.dirname(__file__)
214 214
215 215 ipython_cmd = get_ipython_cmd()
216 216 # Absolute path for filename
217 217 full_fname = os.path.join(test_dir, fname)
218 218 full_cmd = ipython_cmd + cmdargs + [full_fname]
219 219 env = os.environ.copy()
220 220 # FIXME: ignore all warnings in ipexec while we have shims
221 221 # should we keep suppressing warnings here, even after removing shims?
222 222 env['PYTHONWARNINGS'] = 'ignore'
223 223 # env.pop('PYTHONWARNINGS', None) # Avoid extraneous warnings appearing on stderr
224 224 for k, v in env.items():
225 225 # Debug a bizarre failure we've seen on Windows:
226 226 # TypeError: environment can only contain strings
227 227 if not isinstance(v, str):
228 228 print(k, v)
229 229 p = Popen(full_cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE, env=env)
230 230 out, err = p.communicate(input=py3compat.str_to_bytes('\n'.join(commands)) or None)
231 231 out, err = py3compat.bytes_to_str(out), py3compat.bytes_to_str(err)
232 232 # `import readline` causes 'ESC[?1034h' to be output sometimes,
233 233 # so strip that out before doing comparisons
234 234 if out:
235 235 out = re.sub(r'\x1b\[[^h]+h', '', out)
236 236 return out, err
237 237
238 238
239 239 def ipexec_validate(fname, expected_out, expected_err='',
240 240 options=None, commands=()):
241 241 """Utility to call 'ipython filename' and validate output/error.
242 242
243 243 This function raises an AssertionError if the validation fails.
244 244
245 245 Note that this starts IPython in a subprocess!
246 246
247 247 Parameters
248 248 ----------
249 249 fname : str
250 250 Name of the file to be executed (should have .py or .ipy extension).
251 251
252 252 expected_out : str
253 253 Expected stdout of the process.
254 254
255 255 expected_err : optional, str
256 256 Expected stderr of the process.
257 257
258 258 options : optional, list
259 259 Extra command-line flags to be passed to IPython.
260 260
261 261 Returns
262 262 -------
263 263 None
264 264 """
265 265
266 266 import nose.tools as nt
267 267
268 268 out, err = ipexec(fname, options, commands)
269 269 #print 'OUT', out # dbg
270 270 #print 'ERR', err # dbg
271 271 # If there are any errors, we must check those befor stdout, as they may be
272 272 # more informative than simply having an empty stdout.
273 273 if err:
274 274 if expected_err:
275 275 nt.assert_equal("\n".join(err.strip().splitlines()), "\n".join(expected_err.strip().splitlines()))
276 276 else:
277 277 raise ValueError('Running file %r produced error: %r' %
278 278 (fname, err))
279 279 # If no errors or output on stderr was expected, match stdout
280 280 nt.assert_equal("\n".join(out.strip().splitlines()), "\n".join(expected_out.strip().splitlines()))
281 281
282 282
283 283 class TempFileMixin(object):
284 284 """Utility class to create temporary Python/IPython files.
285 285
286 286 Meant as a mixin class for test cases."""
287 287
288 288 def mktmp(self, src, ext='.py'):
289 289 """Make a valid python temp file."""
290 290 fname, f = temp_pyfile(src, ext)
291 291 self.tmpfile = f
292 292 self.fname = fname
293 293
294 294 def tearDown(self):
295 295 if hasattr(self, 'tmpfile'):
296 296 # If the tmpfile wasn't made because of skipped tests, like in
297 297 # win32, there's nothing to cleanup.
298 298 self.tmpfile.close()
299 299 try:
300 300 os.unlink(self.fname)
301 301 except:
302 302 # On Windows, even though we close the file, we still can't
303 303 # delete it. I have no clue why
304 304 pass
305 305
306 def __enter__(self):
307 return self
308
309 def __exit__(self, exc_type, exc_value, traceback):
310 self.tearDown()
311
312
306 313 pair_fail_msg = ("Testing {0}\n\n"
307 314 "In:\n"
308 315 " {1!r}\n"
309 316 "Expected:\n"
310 317 " {2!r}\n"
311 318 "Got:\n"
312 319 " {3!r}\n")
313 320 def check_pairs(func, pairs):
314 321 """Utility function for the common case of checking a function with a
315 322 sequence of input/output pairs.
316 323
317 324 Parameters
318 325 ----------
319 326 func : callable
320 327 The function to be tested. Should accept a single argument.
321 328 pairs : iterable
322 329 A list of (input, expected_output) tuples.
323 330
324 331 Returns
325 332 -------
326 333 None. Raises an AssertionError if any output does not match the expected
327 334 value.
328 335 """
329 336 name = getattr(func, "func_name", getattr(func, "__name__", "<unknown>"))
330 337 for inp, expected in pairs:
331 338 out = func(inp)
332 339 assert out == expected, pair_fail_msg.format(name, inp, expected, out)
333 340
334 341
335 342 if py3compat.PY3:
336 343 MyStringIO = StringIO
337 344 else:
338 345 # In Python 2, stdout/stderr can have either bytes or unicode written to them,
339 346 # so we need a class that can handle both.
340 347 class MyStringIO(StringIO):
341 348 def write(self, s):
342 349 s = py3compat.cast_unicode(s, encoding=DEFAULT_ENCODING)
343 350 super(MyStringIO, self).write(s)
344 351
345 352 _re_type = type(re.compile(r''))
346 353
347 354 notprinted_msg = """Did not find {0!r} in printed output (on {1}):
348 355 -------
349 356 {2!s}
350 357 -------
351 358 """
352 359
353 360 class AssertPrints(object):
354 361 """Context manager for testing that code prints certain text.
355 362
356 363 Examples
357 364 --------
358 365 >>> with AssertPrints("abc", suppress=False):
359 366 ... print("abcd")
360 367 ... print("def")
361 368 ...
362 369 abcd
363 370 def
364 371 """
365 372 def __init__(self, s, channel='stdout', suppress=True):
366 373 self.s = s
367 374 if isinstance(self.s, (py3compat.string_types, _re_type)):
368 375 self.s = [self.s]
369 376 self.channel = channel
370 377 self.suppress = suppress
371 378
372 379 def __enter__(self):
373 380 self.orig_stream = getattr(sys, self.channel)
374 381 self.buffer = MyStringIO()
375 382 self.tee = Tee(self.buffer, channel=self.channel)
376 383 setattr(sys, self.channel, self.buffer if self.suppress else self.tee)
377 384
378 385 def __exit__(self, etype, value, traceback):
379 386 try:
380 387 if value is not None:
381 388 # If an error was raised, don't check anything else
382 389 return False
383 390 self.tee.flush()
384 391 setattr(sys, self.channel, self.orig_stream)
385 392 printed = self.buffer.getvalue()
386 393 for s in self.s:
387 394 if isinstance(s, _re_type):
388 395 assert s.search(printed), notprinted_msg.format(s.pattern, self.channel, printed)
389 396 else:
390 397 assert s in printed, notprinted_msg.format(s, self.channel, printed)
391 398 return False
392 399 finally:
393 400 self.tee.close()
394 401
395 402 printed_msg = """Found {0!r} in printed output (on {1}):
396 403 -------
397 404 {2!s}
398 405 -------
399 406 """
400 407
401 408 class AssertNotPrints(AssertPrints):
402 409 """Context manager for checking that certain output *isn't* produced.
403 410
404 411 Counterpart of AssertPrints"""
405 412 def __exit__(self, etype, value, traceback):
406 413 try:
407 414 if value is not None:
408 415 # If an error was raised, don't check anything else
409 416 self.tee.close()
410 417 return False
411 418 self.tee.flush()
412 419 setattr(sys, self.channel, self.orig_stream)
413 420 printed = self.buffer.getvalue()
414 421 for s in self.s:
415 422 if isinstance(s, _re_type):
416 423 assert not s.search(printed),printed_msg.format(
417 424 s.pattern, self.channel, printed)
418 425 else:
419 426 assert s not in printed, printed_msg.format(
420 427 s, self.channel, printed)
421 428 return False
422 429 finally:
423 430 self.tee.close()
424 431
425 432 @contextmanager
426 433 def mute_warn():
427 434 from IPython.utils import warn
428 435 save_warn = warn.warn
429 436 warn.warn = lambda *a, **kw: None
430 437 try:
431 438 yield
432 439 finally:
433 440 warn.warn = save_warn
434 441
435 442 @contextmanager
436 443 def make_tempfile(name):
437 444 """ Create an empty, named, temporary file for the duration of the context.
438 445 """
439 446 f = open(name, 'w')
440 447 f.close()
441 448 try:
442 449 yield
443 450 finally:
444 451 os.unlink(name)
445 452
446 453
447 454 def help_output_test(subcommand=''):
448 455 """test that `ipython [subcommand] -h` works"""
449 456 cmd = get_ipython_cmd() + [subcommand, '-h']
450 457 out, err, rc = get_output_error_code(cmd)
451 458 nt.assert_equal(rc, 0, err)
452 459 nt.assert_not_in("Traceback", err)
453 460 nt.assert_in("Options", out)
454 461 nt.assert_in("--help-all", out)
455 462 return out, err
456 463
457 464
458 465 def help_all_output_test(subcommand=''):
459 466 """test that `ipython [subcommand] --help-all` works"""
460 467 cmd = get_ipython_cmd() + [subcommand, '--help-all']
461 468 out, err, rc = get_output_error_code(cmd)
462 469 nt.assert_equal(rc, 0, err)
463 470 nt.assert_not_in("Traceback", err)
464 471 nt.assert_in("Options", out)
465 472 nt.assert_in("Class parameters", out)
466 473 return out, err
467 474
@@ -1,299 +1,300 b''
1 1 #!/usr/bin/env python
2 2 # -*- coding: utf-8 -*-
3 3 """Setup script for IPython.
4 4
5 5 Under Posix environments it works like a typical setup.py script.
6 6 Under Windows, the command sdist is not supported, since IPython
7 7 requires utilities which are not available under Windows."""
8 8
9 9 #-----------------------------------------------------------------------------
10 10 # Copyright (c) 2008-2011, IPython Development Team.
11 11 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
12 12 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
13 13 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
14 14 #
15 15 # Distributed under the terms of the Modified BSD License.
16 16 #
17 17 # The full license is in the file COPYING.rst, distributed with this software.
18 18 #-----------------------------------------------------------------------------
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Minimal Python version sanity check
22 22 #-----------------------------------------------------------------------------
23 23 from __future__ import print_function
24 24
25 25 import sys
26 26
27 27 # This check is also made in IPython/__init__, don't forget to update both when
28 28 # changing Python version requirements.
29 29 v = sys.version_info
30 30 if v[:2] < (2,7) or (v[0] >= 3 and v[:2] < (3,3)):
31 31 error = "ERROR: IPython requires Python version 2.7 or 3.3 or above."
32 32 print(error, file=sys.stderr)
33 33 sys.exit(1)
34 34
35 35 PY3 = (sys.version_info[0] >= 3)
36 36
37 37 # At least we're on the python version we need, move on.
38 38
39 39 #-------------------------------------------------------------------------------
40 40 # Imports
41 41 #-------------------------------------------------------------------------------
42 42
43 43 # Stdlib imports
44 44 import os
45 45
46 46 from glob import glob
47 47
48 48 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
49 49 # update it when the contents of directories change.
50 50 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
51 51
52 52 from distutils.core import setup
53 53
54 54 # Our own imports
55 55 from setupbase import target_update
56 56
57 57 from setupbase import (
58 58 setup_args,
59 59 find_packages,
60 60 find_package_data,
61 61 check_package_data_first,
62 62 find_entry_points,
63 63 build_scripts_entrypt,
64 64 find_data_files,
65 65 git_prebuild,
66 66 install_symlinked,
67 67 install_lib_symlink,
68 68 install_scripts_for_symlink,
69 69 unsymlink,
70 70 )
71 71
72 72 isfile = os.path.isfile
73 73 pjoin = os.path.join
74 74
75 75 #-------------------------------------------------------------------------------
76 76 # Handle OS specific things
77 77 #-------------------------------------------------------------------------------
78 78
79 79 if os.name in ('nt','dos'):
80 80 os_name = 'windows'
81 81 else:
82 82 os_name = os.name
83 83
84 84 # Under Windows, 'sdist' has not been supported. Now that the docs build with
85 85 # Sphinx it might work, but let's not turn it on until someone confirms that it
86 86 # actually works.
87 87 if os_name == 'windows' and 'sdist' in sys.argv:
88 88 print('The sdist command is not available under Windows. Exiting.')
89 89 sys.exit(1)
90 90
91 91
92 92 #-------------------------------------------------------------------------------
93 93 # Things related to the IPython documentation
94 94 #-------------------------------------------------------------------------------
95 95
96 96 # update the manuals when building a source dist
97 97 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
98 98
99 99 # List of things to be updated. Each entry is a triplet of args for
100 100 # target_update()
101 101 to_update = [
102 102 ('docs/man/ipython.1.gz',
103 103 ['docs/man/ipython.1'],
104 104 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
105 105 ]
106 106
107 107
108 108 [ target_update(*t) for t in to_update ]
109 109
110 110 #---------------------------------------------------------------------------
111 111 # Find all the packages, package data, and data_files
112 112 #---------------------------------------------------------------------------
113 113
114 114 packages = find_packages()
115 115 package_data = find_package_data()
116 116
117 117 data_files = find_data_files()
118 118
119 119 setup_args['packages'] = packages
120 120 setup_args['package_data'] = package_data
121 121 setup_args['data_files'] = data_files
122 122
123 123 #---------------------------------------------------------------------------
124 124 # custom distutils commands
125 125 #---------------------------------------------------------------------------
126 126 # imports here, so they are after setuptools import if there was one
127 127 from distutils.command.sdist import sdist
128 128 from distutils.command.upload import upload
129 129
130 130 class UploadWindowsInstallers(upload):
131 131
132 132 description = "Upload Windows installers to PyPI (only used from tools/release_windows.py)"
133 133 user_options = upload.user_options + [
134 134 ('files=', 'f', 'exe file (or glob) to upload')
135 135 ]
136 136 def initialize_options(self):
137 137 upload.initialize_options(self)
138 138 meta = self.distribution.metadata
139 139 base = '{name}-{version}'.format(
140 140 name=meta.get_name(),
141 141 version=meta.get_version()
142 142 )
143 143 self.files = os.path.join('dist', '%s.*.exe' % base)
144 144
145 145 def run(self):
146 146 for dist_file in glob(self.files):
147 147 self.upload_file('bdist_wininst', 'any', dist_file)
148 148
149 149 setup_args['cmdclass'] = {
150 150 'build_py': \
151 151 check_package_data_first(git_prebuild('IPython')),
152 152 'sdist' : git_prebuild('IPython', sdist),
153 153 'upload_wininst' : UploadWindowsInstallers,
154 154 'symlink': install_symlinked,
155 155 'install_lib_symlink': install_lib_symlink,
156 156 'install_scripts_sym': install_scripts_for_symlink,
157 157 'unsymlink': unsymlink,
158 158 }
159 159
160 160
161 161 #---------------------------------------------------------------------------
162 162 # Handle scripts, dependencies, and setuptools specific things
163 163 #---------------------------------------------------------------------------
164 164
165 165 # For some commands, use setuptools. Note that we do NOT list install here!
166 166 # If you want a setuptools-enhanced install, just run 'setupegg.py install'
167 167 needs_setuptools = set(('develop', 'release', 'bdist_egg', 'bdist_rpm',
168 168 'bdist', 'bdist_dumb', 'bdist_wininst', 'bdist_wheel',
169 169 'egg_info', 'easy_install', 'upload', 'install_egg_info',
170 170 ))
171 171
172 172 if len(needs_setuptools.intersection(sys.argv)) > 0:
173 173 import setuptools
174 174
175 175 # This dict is used for passing extra arguments that are setuptools
176 176 # specific to setup
177 177 setuptools_extra_args = {}
178 178
179 179 # setuptools requirements
180 180
181 181 extras_require = dict(
182 182 parallel = ['ipyparallel'],
183 183 qtconsole = ['qtconsole'],
184 184 doc = ['Sphinx>=1.3'],
185 test = ['nose>=0.10.1', 'requests', 'testpath', 'pygments'],
185 test = ['nose>=0.10.1', 'requests', 'testpath', 'pygments', 'nbformat', 'ipykernel'],
186 186 terminal = [],
187 187 kernel = ['ipykernel'],
188 188 nbformat = ['nbformat'],
189 189 notebook = ['notebook', 'ipywidgets'],
190 190 nbconvert = ['nbconvert'],
191 191 )
192
192 193 install_requires = [
193 194 'setuptools>=18.5',
194 195 'decorator',
195 196 'pickleshare',
196 197 'simplegeneric>0.8',
197 198 'traitlets>=4.2',
198 199 'prompt_toolkit>=1.0.0,<2.0.0',
199 200 'pygments',
200 201 ]
201 202
202 203 # Platform-specific dependencies:
203 204 # This is the correct way to specify these,
204 205 # but requires pip >= 6. pip < 6 ignores these.
205 206
206 207 extras_require.update({
207 208 ':python_version == "2.7"': ['backports.shutil_get_terminal_size'],
208 209 ':python_version == "2.7" or python_version == "3.3"': ['pathlib2'],
209 210 ':sys_platform != "win32"': ['pexpect'],
210 211 ':sys_platform == "darwin"': ['appnope'],
211 212 ':sys_platform == "win32"': ['colorama'],
212 213 'test:python_version == "2.7"': ['mock'],
213 214 })
214 215 # FIXME: re-specify above platform dependencies for pip < 6
215 216 # These would result in non-portable bdists.
216 217 if not any(arg.startswith('bdist') for arg in sys.argv):
217 218 if sys.version_info < (3, 3):
218 219 extras_require['test'].append('mock')
219 220
220 221 if sys.platform == 'darwin':
221 222 install_requires.extend(['appnope'])
222 223 have_readline = False
223 224 try:
224 225 import readline
225 226 except ImportError:
226 227 pass
227 228 else:
228 229 if 'libedit' not in readline.__doc__:
229 230 have_readline = True
230 231 if not have_readline:
231 232 install_requires.extend(['gnureadline'])
232 233
233 234 if sys.platform.startswith('win'):
234 235 extras_require['terminal'].append('pyreadline>=2.0')
235 236 else:
236 237 install_requires.append('pexpect')
237 238
238 239 # workaround pypa/setuptools#147, where setuptools misspells
239 240 # platform_python_implementation as python_implementation
240 241 if 'setuptools' in sys.modules:
241 242 for key in list(extras_require):
242 243 if 'platform_python_implementation' in key:
243 244 new_key = key.replace('platform_python_implementation', 'python_implementation')
244 245 extras_require[new_key] = extras_require.pop(key)
245 246
246 247 everything = set()
247 248 for key, deps in extras_require.items():
248 249 if ':' not in key:
249 250 everything.update(deps)
250 251 extras_require['all'] = everything
251 252
252 253 if 'setuptools' in sys.modules:
253 254 setuptools_extra_args['zip_safe'] = False
254 255 setuptools_extra_args['entry_points'] = {
255 256 'console_scripts': find_entry_points(),
256 257 'pygments.lexers': [
257 258 'ipythonconsole = IPython.lib.lexers:IPythonConsoleLexer',
258 259 'ipython = IPython.lib.lexers:IPythonLexer',
259 260 'ipython3 = IPython.lib.lexers:IPython3Lexer',
260 261 ],
261 262 }
262 263 setup_args['extras_require'] = extras_require
263 264 requires = setup_args['install_requires'] = install_requires
264 265
265 266 # Script to be run by the windows binary installer after the default setup
266 267 # routine, to add shortcuts and similar windows-only things. Windows
267 268 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
268 269 # doesn't find them.
269 270 if 'bdist_wininst' in sys.argv:
270 271 if len(sys.argv) > 2 and \
271 272 ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
272 273 print("ERROR: bdist_wininst must be run alone. Exiting.", file=sys.stderr)
273 274 sys.exit(1)
274 275 setup_args['data_files'].append(
275 276 ['Scripts', ('scripts/ipython.ico', 'scripts/ipython_nb.ico')])
276 277 setup_args['scripts'] = [pjoin('scripts','ipython_win_post_install.py')]
277 278 setup_args['options'] = {"bdist_wininst":
278 279 {"install_script":
279 280 "ipython_win_post_install.py"}}
280 281
281 282 else:
282 283 # scripts has to be a non-empty list, or install_scripts isn't called
283 284 setup_args['scripts'] = [e.split('=')[0].strip() for e in find_entry_points()]
284 285
285 286 setup_args['cmdclass']['build_scripts'] = build_scripts_entrypt
286 287
287 288 #---------------------------------------------------------------------------
288 289 # Do the actual setup now
289 290 #---------------------------------------------------------------------------
290 291
291 292 setup_args.update(setuptools_extra_args)
292 293
293 294
294 295
295 296 def main():
296 297 setup(**setup_args)
297 298
298 299 if __name__ == '__main__':
299 300 main()
General Comments 0
You need to be logged in to leave comments. Login now