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