##// END OF EJS Templates
Backport PR #12868: Misc CI warning and error.
Matthias Bussonnier -
Show More
@@ -1,459 +1,459 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 os
5 import os
6 import warnings
6 import warnings
7
7
8 from unittest import mock
8 from unittest import mock
9
9
10 import nose.tools as nt
10 import nose.tools as nt
11
11
12 from IPython.core import display
12 from IPython.core import display
13 from IPython.core.getipython import get_ipython
13 from IPython.core.getipython import get_ipython
14 from IPython.utils.io import capture_output
14 from IPython.utils.io import capture_output
15 from IPython.utils.tempdir import NamedFileInTemporaryDirectory
15 from IPython.utils.tempdir import NamedFileInTemporaryDirectory
16 from IPython import paths as ipath
16 from IPython import paths as ipath
17 from IPython.testing.tools import AssertNotPrints
17 from IPython.testing.tools import AssertNotPrints
18
18
19 import IPython.testing.decorators as dec
19 import IPython.testing.decorators as dec
20
20
21 def test_image_size():
21 def test_image_size():
22 """Simple test for display.Image(args, width=x,height=y)"""
22 """Simple test for display.Image(args, width=x,height=y)"""
23 thisurl = 'http://www.google.fr/images/srpr/logo3w.png'
23 thisurl = 'http://www.google.fr/images/srpr/logo3w.png'
24 img = display.Image(url=thisurl, width=200, height=200)
24 img = display.Image(url=thisurl, width=200, height=200)
25 nt.assert_equal(u'<img src="%s" width="200" height="200"/>' % (thisurl), img._repr_html_())
25 nt.assert_equal(u'<img src="%s" width="200" height="200"/>' % (thisurl), img._repr_html_())
26 img = display.Image(url=thisurl, metadata={'width':200, 'height':200})
26 img = display.Image(url=thisurl, metadata={'width':200, 'height':200})
27 nt.assert_equal(u'<img src="%s" width="200" height="200"/>' % (thisurl), img._repr_html_())
27 nt.assert_equal(u'<img src="%s" width="200" height="200"/>' % (thisurl), img._repr_html_())
28 img = display.Image(url=thisurl, width=200)
28 img = display.Image(url=thisurl, width=200)
29 nt.assert_equal(u'<img src="%s" width="200"/>' % (thisurl), img._repr_html_())
29 nt.assert_equal(u'<img src="%s" width="200"/>' % (thisurl), img._repr_html_())
30 img = display.Image(url=thisurl)
30 img = display.Image(url=thisurl)
31 nt.assert_equal(u'<img src="%s"/>' % (thisurl), img._repr_html_())
31 nt.assert_equal(u'<img src="%s"/>' % (thisurl), img._repr_html_())
32 img = display.Image(url=thisurl, unconfined=True)
32 img = display.Image(url=thisurl, unconfined=True)
33 nt.assert_equal(u'<img src="%s" class="unconfined"/>' % (thisurl), img._repr_html_())
33 nt.assert_equal(u'<img src="%s" class="unconfined"/>' % (thisurl), img._repr_html_())
34
34
35
35
36 def test_image_mimes():
36 def test_image_mimes():
37 fmt = get_ipython().display_formatter.format
37 fmt = get_ipython().display_formatter.format
38 for format in display.Image._ACCEPTABLE_EMBEDDINGS:
38 for format in display.Image._ACCEPTABLE_EMBEDDINGS:
39 mime = display.Image._MIMETYPES[format]
39 mime = display.Image._MIMETYPES[format]
40 img = display.Image(b'garbage', format=format)
40 img = display.Image(b'garbage', format=format)
41 data, metadata = fmt(img)
41 data, metadata = fmt(img)
42 nt.assert_equal(sorted(data), sorted([mime, 'text/plain']))
42 nt.assert_equal(sorted(data), sorted([mime, 'text/plain']))
43
43
44
44
45 def test_geojson():
45 def test_geojson():
46
46
47 gj = display.GeoJSON(data={
47 gj = display.GeoJSON(data={
48 "type": "Feature",
48 "type": "Feature",
49 "geometry": {
49 "geometry": {
50 "type": "Point",
50 "type": "Point",
51 "coordinates": [-81.327, 296.038]
51 "coordinates": [-81.327, 296.038]
52 },
52 },
53 "properties": {
53 "properties": {
54 "name": "Inca City"
54 "name": "Inca City"
55 }
55 }
56 },
56 },
57 url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
57 url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
58 layer_options={
58 layer_options={
59 "basemap_id": "celestia_mars-shaded-16k_global",
59 "basemap_id": "celestia_mars-shaded-16k_global",
60 "attribution": "Celestia/praesepe",
60 "attribution": "Celestia/praesepe",
61 "minZoom": 0,
61 "minZoom": 0,
62 "maxZoom": 18,
62 "maxZoom": 18,
63 })
63 })
64 nt.assert_equal(u'<IPython.core.display.GeoJSON object>', str(gj))
64 nt.assert_equal(u'<IPython.core.display.GeoJSON object>', str(gj))
65
65
66 def test_retina_png():
66 def test_retina_png():
67 here = os.path.dirname(__file__)
67 here = os.path.dirname(__file__)
68 img = display.Image(os.path.join(here, "2x2.png"), retina=True)
68 img = display.Image(os.path.join(here, "2x2.png"), retina=True)
69 nt.assert_equal(img.height, 1)
69 nt.assert_equal(img.height, 1)
70 nt.assert_equal(img.width, 1)
70 nt.assert_equal(img.width, 1)
71 data, md = img._repr_png_()
71 data, md = img._repr_png_()
72 nt.assert_equal(md['width'], 1)
72 nt.assert_equal(md['width'], 1)
73 nt.assert_equal(md['height'], 1)
73 nt.assert_equal(md['height'], 1)
74
74
75 def test_embed_svg_url():
75 def test_embed_svg_url():
76 import gzip
76 import gzip
77 from io import BytesIO
77 from io import BytesIO
78 svg_data = b'<svg><circle x="0" y="0" r="1"/></svg>'
78 svg_data = b'<svg><circle x="0" y="0" r="1"/></svg>'
79 url = 'http://test.com/circle.svg'
79 url = 'http://test.com/circle.svg'
80
80
81 gzip_svg = BytesIO()
81 gzip_svg = BytesIO()
82 with gzip.open(gzip_svg, 'wb') as fp:
82 with gzip.open(gzip_svg, 'wb') as fp:
83 fp.write(svg_data)
83 fp.write(svg_data)
84 gzip_svg = gzip_svg.getvalue()
84 gzip_svg = gzip_svg.getvalue()
85
85
86 def mocked_urlopen(*args, **kwargs):
86 def mocked_urlopen(*args, **kwargs):
87 class MockResponse:
87 class MockResponse:
88 def __init__(self, svg):
88 def __init__(self, svg):
89 self._svg_data = svg
89 self._svg_data = svg
90 self.headers = {'content-type': 'image/svg+xml'}
90 self.headers = {'content-type': 'image/svg+xml'}
91
91
92 def read(self):
92 def read(self):
93 return self._svg_data
93 return self._svg_data
94
94
95 if args[0] == url:
95 if args[0] == url:
96 return MockResponse(svg_data)
96 return MockResponse(svg_data)
97 elif args[0] == url + 'z':
97 elif args[0] == url + 'z':
98 ret= MockResponse(gzip_svg)
98 ret= MockResponse(gzip_svg)
99 ret.headers['content-encoding']= 'gzip'
99 ret.headers['content-encoding']= 'gzip'
100 return ret
100 return ret
101 return MockResponse(None)
101 return MockResponse(None)
102
102
103 with mock.patch('urllib.request.urlopen', side_effect=mocked_urlopen):
103 with mock.patch('urllib.request.urlopen', side_effect=mocked_urlopen):
104 svg = display.SVG(url=url)
104 svg = display.SVG(url=url)
105 nt.assert_true(svg._repr_svg_().startswith('<svg'))
105 nt.assert_true(svg._repr_svg_().startswith('<svg'))
106 svg = display.SVG(url=url + 'z')
106 svg = display.SVG(url=url + 'z')
107 nt.assert_true(svg._repr_svg_().startswith('<svg'))
107 nt.assert_true(svg._repr_svg_().startswith('<svg'))
108
108
109 def test_retina_jpeg():
109 def test_retina_jpeg():
110 here = os.path.dirname(__file__)
110 here = os.path.dirname(__file__)
111 img = display.Image(os.path.join(here, "2x2.jpg"), retina=True)
111 img = display.Image(os.path.join(here, "2x2.jpg"), retina=True)
112 nt.assert_equal(img.height, 1)
112 nt.assert_equal(img.height, 1)
113 nt.assert_equal(img.width, 1)
113 nt.assert_equal(img.width, 1)
114 data, md = img._repr_jpeg_()
114 data, md = img._repr_jpeg_()
115 nt.assert_equal(md['width'], 1)
115 nt.assert_equal(md['width'], 1)
116 nt.assert_equal(md['height'], 1)
116 nt.assert_equal(md['height'], 1)
117
117
118 def test_base64image():
118 def test_base64image():
119 display.Image("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94BCRQnOqNu0b4AAAAKSURBVAjXY2AAAAACAAHiIbwzAAAAAElFTkSuQmCC")
119 display.Image("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94BCRQnOqNu0b4AAAAKSURBVAjXY2AAAAACAAHiIbwzAAAAAElFTkSuQmCC")
120
120
121 def test_image_filename_defaults():
121 def test_image_filename_defaults():
122 '''test format constraint, and validity of jpeg and png'''
122 '''test format constraint, and validity of jpeg and png'''
123 tpath = ipath.get_ipython_package_dir()
123 tpath = ipath.get_ipython_package_dir()
124 nt.assert_raises(ValueError, display.Image, filename=os.path.join(tpath, 'testing/tests/badformat.zip'),
124 nt.assert_raises(ValueError, display.Image, filename=os.path.join(tpath, 'testing/tests/badformat.zip'),
125 embed=True)
125 embed=True)
126 nt.assert_raises(ValueError, display.Image)
126 nt.assert_raises(ValueError, display.Image)
127 nt.assert_raises(ValueError, display.Image, data='this is not an image', format='badformat', embed=True)
127 nt.assert_raises(ValueError, display.Image, data='this is not an image', format='badformat', embed=True)
128 # check boths paths to allow packages to test at build and install time
128 # check boths paths to allow packages to test at build and install time
129 imgfile = os.path.join(tpath, 'core/tests/2x2.png')
129 imgfile = os.path.join(tpath, 'core/tests/2x2.png')
130 img = display.Image(filename=imgfile)
130 img = display.Image(filename=imgfile)
131 nt.assert_equal('png', img.format)
131 nt.assert_equal('png', img.format)
132 nt.assert_is_not_none(img._repr_png_())
132 nt.assert_is_not_none(img._repr_png_())
133 img = display.Image(filename=os.path.join(tpath, 'testing/tests/logo.jpg'), embed=False)
133 img = display.Image(filename=os.path.join(tpath, 'testing/tests/logo.jpg'), embed=False)
134 nt.assert_equal('jpeg', img.format)
134 nt.assert_equal('jpeg', img.format)
135 nt.assert_is_none(img._repr_jpeg_())
135 nt.assert_is_none(img._repr_jpeg_())
136
136
137 def _get_inline_config():
137 def _get_inline_config():
138 from ipykernel.pylab.config import InlineBackend
138 from ipykernel.pylab.config import InlineBackend
139 return InlineBackend.instance()
139 return InlineBackend.instance()
140
140
141
141
142 @dec.skip_without("ipykernel")
142 @dec.skip_without("ipykernel")
143 @dec.skip_without("matplotlib")
143 @dec.skip_without("matplotlib")
144 def test_set_matplotlib_close():
144 def test_set_matplotlib_close():
145 cfg = _get_inline_config()
145 cfg = _get_inline_config()
146 cfg.close_figures = False
146 cfg.close_figures = False
147 display.set_matplotlib_close()
147 display.set_matplotlib_close()
148 assert cfg.close_figures
148 assert cfg.close_figures
149 display.set_matplotlib_close(False)
149 display.set_matplotlib_close(False)
150 assert not cfg.close_figures
150 assert not cfg.close_figures
151
151
152 _fmt_mime_map = {
152 _fmt_mime_map = {
153 'png': 'image/png',
153 'png': 'image/png',
154 'jpeg': 'image/jpeg',
154 'jpeg': 'image/jpeg',
155 'pdf': 'application/pdf',
155 'pdf': 'application/pdf',
156 'retina': 'image/png',
156 'retina': 'image/png',
157 'svg': 'image/svg+xml',
157 'svg': 'image/svg+xml',
158 }
158 }
159
159
160 @dec.skip_without('matplotlib')
160 @dec.skip_without('matplotlib')
161 def test_set_matplotlib_formats():
161 def test_set_matplotlib_formats():
162 from matplotlib.figure import Figure
162 from matplotlib.figure import Figure
163 formatters = get_ipython().display_formatter.formatters
163 formatters = get_ipython().display_formatter.formatters
164 for formats in [
164 for formats in [
165 ('png',),
165 ('png',),
166 ('pdf', 'svg'),
166 ('pdf', 'svg'),
167 ('jpeg', 'retina', 'png'),
167 ('jpeg', 'retina', 'png'),
168 (),
168 (),
169 ]:
169 ]:
170 active_mimes = {_fmt_mime_map[fmt] for fmt in formats}
170 active_mimes = {_fmt_mime_map[fmt] for fmt in formats}
171 display.set_matplotlib_formats(*formats)
171 display.set_matplotlib_formats(*formats)
172 for mime, f in formatters.items():
172 for mime, f in formatters.items():
173 if mime in active_mimes:
173 if mime in active_mimes:
174 nt.assert_in(Figure, f)
174 nt.assert_in(Figure, f)
175 else:
175 else:
176 nt.assert_not_in(Figure, f)
176 nt.assert_not_in(Figure, f)
177
177
178
178
179 @dec.skip_without("ipykernel")
179 @dec.skip_without("ipykernel")
180 @dec.skip_without("matplotlib")
180 @dec.skip_without("matplotlib")
181 def test_set_matplotlib_formats_kwargs():
181 def test_set_matplotlib_formats_kwargs():
182 from matplotlib.figure import Figure
182 from matplotlib.figure import Figure
183 ip = get_ipython()
183 ip = get_ipython()
184 cfg = _get_inline_config()
184 cfg = _get_inline_config()
185 cfg.print_figure_kwargs.update(dict(foo='bar'))
185 cfg.print_figure_kwargs.update(dict(foo='bar'))
186 kwargs = dict(quality=10)
186 kwargs = dict(dpi=150)
187 display.set_matplotlib_formats('png', **kwargs)
187 display.set_matplotlib_formats('png', **kwargs)
188 formatter = ip.display_formatter.formatters['image/png']
188 formatter = ip.display_formatter.formatters['image/png']
189 f = formatter.lookup_by_type(Figure)
189 f = formatter.lookup_by_type(Figure)
190 cell = f.__closure__[0].cell_contents
190 cell = f.__closure__[0].cell_contents
191 expected = kwargs
191 expected = kwargs
192 expected.update(cfg.print_figure_kwargs)
192 expected.update(cfg.print_figure_kwargs)
193 nt.assert_equal(cell, expected)
193 nt.assert_equal(cell, expected)
194
194
195 def test_display_available():
195 def test_display_available():
196 """
196 """
197 Test that display is available without import
197 Test that display is available without import
198
198
199 We don't really care if it's in builtin or anything else, but it should
199 We don't really care if it's in builtin or anything else, but it should
200 always be available.
200 always be available.
201 """
201 """
202 ip = get_ipython()
202 ip = get_ipython()
203 with AssertNotPrints('NameError'):
203 with AssertNotPrints('NameError'):
204 ip.run_cell('display')
204 ip.run_cell('display')
205 try:
205 try:
206 ip.run_cell('del display')
206 ip.run_cell('del display')
207 except NameError:
207 except NameError:
208 pass # it's ok, it might be in builtins
208 pass # it's ok, it might be in builtins
209 # even if deleted it should be back
209 # even if deleted it should be back
210 with AssertNotPrints('NameError'):
210 with AssertNotPrints('NameError'):
211 ip.run_cell('display')
211 ip.run_cell('display')
212
212
213 def test_textdisplayobj_pretty_repr():
213 def test_textdisplayobj_pretty_repr():
214 p = display.Pretty("This is a simple test")
214 p = display.Pretty("This is a simple test")
215 nt.assert_equal(repr(p), '<IPython.core.display.Pretty object>')
215 nt.assert_equal(repr(p), '<IPython.core.display.Pretty object>')
216 nt.assert_equal(p.data, 'This is a simple test')
216 nt.assert_equal(p.data, 'This is a simple test')
217
217
218 p._show_mem_addr = True
218 p._show_mem_addr = True
219 nt.assert_equal(repr(p), object.__repr__(p))
219 nt.assert_equal(repr(p), object.__repr__(p))
220
220
221 def test_displayobject_repr():
221 def test_displayobject_repr():
222 h = display.HTML('<br />')
222 h = display.HTML('<br />')
223 nt.assert_equal(repr(h), '<IPython.core.display.HTML object>')
223 nt.assert_equal(repr(h), '<IPython.core.display.HTML object>')
224 h._show_mem_addr = True
224 h._show_mem_addr = True
225 nt.assert_equal(repr(h), object.__repr__(h))
225 nt.assert_equal(repr(h), object.__repr__(h))
226 h._show_mem_addr = False
226 h._show_mem_addr = False
227 nt.assert_equal(repr(h), '<IPython.core.display.HTML object>')
227 nt.assert_equal(repr(h), '<IPython.core.display.HTML object>')
228
228
229 j = display.Javascript('')
229 j = display.Javascript('')
230 nt.assert_equal(repr(j), '<IPython.core.display.Javascript object>')
230 nt.assert_equal(repr(j), '<IPython.core.display.Javascript object>')
231 j._show_mem_addr = True
231 j._show_mem_addr = True
232 nt.assert_equal(repr(j), object.__repr__(j))
232 nt.assert_equal(repr(j), object.__repr__(j))
233 j._show_mem_addr = False
233 j._show_mem_addr = False
234 nt.assert_equal(repr(j), '<IPython.core.display.Javascript object>')
234 nt.assert_equal(repr(j), '<IPython.core.display.Javascript object>')
235
235
236 @mock.patch('warnings.warn')
236 @mock.patch('warnings.warn')
237 def test_encourage_iframe_over_html(m_warn):
237 def test_encourage_iframe_over_html(m_warn):
238 display.HTML()
238 display.HTML()
239 m_warn.assert_not_called()
239 m_warn.assert_not_called()
240
240
241 display.HTML('<br />')
241 display.HTML('<br />')
242 m_warn.assert_not_called()
242 m_warn.assert_not_called()
243
243
244 display.HTML('<html><p>Lots of content here</p><iframe src="http://a.com"></iframe>')
244 display.HTML('<html><p>Lots of content here</p><iframe src="http://a.com"></iframe>')
245 m_warn.assert_not_called()
245 m_warn.assert_not_called()
246
246
247 display.HTML('<iframe src="http://a.com"></iframe>')
247 display.HTML('<iframe src="http://a.com"></iframe>')
248 m_warn.assert_called_with('Consider using IPython.display.IFrame instead')
248 m_warn.assert_called_with('Consider using IPython.display.IFrame instead')
249
249
250 m_warn.reset_mock()
250 m_warn.reset_mock()
251 display.HTML('<IFRAME SRC="http://a.com"></IFRAME>')
251 display.HTML('<IFRAME SRC="http://a.com"></IFRAME>')
252 m_warn.assert_called_with('Consider using IPython.display.IFrame instead')
252 m_warn.assert_called_with('Consider using IPython.display.IFrame instead')
253
253
254 def test_progress():
254 def test_progress():
255 p = display.ProgressBar(10)
255 p = display.ProgressBar(10)
256 nt.assert_in('0/10',repr(p))
256 nt.assert_in('0/10',repr(p))
257 p.html_width = '100%'
257 p.html_width = '100%'
258 p.progress = 5
258 p.progress = 5
259 nt.assert_equal(p._repr_html_(), "<progress style='width:100%' max='10' value='5'></progress>")
259 nt.assert_equal(p._repr_html_(), "<progress style='width:100%' max='10' value='5'></progress>")
260
260
261 def test_progress_iter():
261 def test_progress_iter():
262 with capture_output(display=False) as captured:
262 with capture_output(display=False) as captured:
263 for i in display.ProgressBar(5):
263 for i in display.ProgressBar(5):
264 out = captured.stdout
264 out = captured.stdout
265 nt.assert_in('{0}/5'.format(i), out)
265 nt.assert_in('{0}/5'.format(i), out)
266 out = captured.stdout
266 out = captured.stdout
267 nt.assert_in('5/5', out)
267 nt.assert_in('5/5', out)
268
268
269 def test_json():
269 def test_json():
270 d = {'a': 5}
270 d = {'a': 5}
271 lis = [d]
271 lis = [d]
272 metadata = [
272 metadata = [
273 {'expanded': False, 'root': 'root'},
273 {'expanded': False, 'root': 'root'},
274 {'expanded': True, 'root': 'root'},
274 {'expanded': True, 'root': 'root'},
275 {'expanded': False, 'root': 'custom'},
275 {'expanded': False, 'root': 'custom'},
276 {'expanded': True, 'root': 'custom'},
276 {'expanded': True, 'root': 'custom'},
277 ]
277 ]
278 json_objs = [
278 json_objs = [
279 display.JSON(d),
279 display.JSON(d),
280 display.JSON(d, expanded=True),
280 display.JSON(d, expanded=True),
281 display.JSON(d, root='custom'),
281 display.JSON(d, root='custom'),
282 display.JSON(d, expanded=True, root='custom'),
282 display.JSON(d, expanded=True, root='custom'),
283 ]
283 ]
284 for j, md in zip(json_objs, metadata):
284 for j, md in zip(json_objs, metadata):
285 nt.assert_equal(j._repr_json_(), (d, md))
285 nt.assert_equal(j._repr_json_(), (d, md))
286
286
287 with warnings.catch_warnings(record=True) as w:
287 with warnings.catch_warnings(record=True) as w:
288 warnings.simplefilter("always")
288 warnings.simplefilter("always")
289 j = display.JSON(json.dumps(d))
289 j = display.JSON(json.dumps(d))
290 nt.assert_equal(len(w), 1)
290 nt.assert_equal(len(w), 1)
291 nt.assert_equal(j._repr_json_(), (d, metadata[0]))
291 nt.assert_equal(j._repr_json_(), (d, metadata[0]))
292
292
293 json_objs = [
293 json_objs = [
294 display.JSON(lis),
294 display.JSON(lis),
295 display.JSON(lis, expanded=True),
295 display.JSON(lis, expanded=True),
296 display.JSON(lis, root='custom'),
296 display.JSON(lis, root='custom'),
297 display.JSON(lis, expanded=True, root='custom'),
297 display.JSON(lis, expanded=True, root='custom'),
298 ]
298 ]
299 for j, md in zip(json_objs, metadata):
299 for j, md in zip(json_objs, metadata):
300 nt.assert_equal(j._repr_json_(), (lis, md))
300 nt.assert_equal(j._repr_json_(), (lis, md))
301
301
302 with warnings.catch_warnings(record=True) as w:
302 with warnings.catch_warnings(record=True) as w:
303 warnings.simplefilter("always")
303 warnings.simplefilter("always")
304 j = display.JSON(json.dumps(lis))
304 j = display.JSON(json.dumps(lis))
305 nt.assert_equal(len(w), 1)
305 nt.assert_equal(len(w), 1)
306 nt.assert_equal(j._repr_json_(), (lis, metadata[0]))
306 nt.assert_equal(j._repr_json_(), (lis, metadata[0]))
307
307
308 def test_video_embedding():
308 def test_video_embedding():
309 """use a tempfile, with dummy-data, to ensure that video embedding doesn't crash"""
309 """use a tempfile, with dummy-data, to ensure that video embedding doesn't crash"""
310 v = display.Video("http://ignored")
310 v = display.Video("http://ignored")
311 assert not v.embed
311 assert not v.embed
312 html = v._repr_html_()
312 html = v._repr_html_()
313 nt.assert_not_in('src="data:', html)
313 nt.assert_not_in('src="data:', html)
314 nt.assert_in('src="http://ignored"', html)
314 nt.assert_in('src="http://ignored"', html)
315
315
316 with nt.assert_raises(ValueError):
316 with nt.assert_raises(ValueError):
317 v = display.Video(b'abc')
317 v = display.Video(b'abc')
318
318
319 with NamedFileInTemporaryDirectory('test.mp4') as f:
319 with NamedFileInTemporaryDirectory('test.mp4') as f:
320 f.write(b'abc')
320 f.write(b'abc')
321 f.close()
321 f.close()
322
322
323 v = display.Video(f.name)
323 v = display.Video(f.name)
324 assert not v.embed
324 assert not v.embed
325 html = v._repr_html_()
325 html = v._repr_html_()
326 nt.assert_not_in('src="data:', html)
326 nt.assert_not_in('src="data:', html)
327
327
328 v = display.Video(f.name, embed=True)
328 v = display.Video(f.name, embed=True)
329 html = v._repr_html_()
329 html = v._repr_html_()
330 nt.assert_in('src="data:video/mp4;base64,YWJj"',html)
330 nt.assert_in('src="data:video/mp4;base64,YWJj"',html)
331
331
332 v = display.Video(f.name, embed=True, mimetype='video/other')
332 v = display.Video(f.name, embed=True, mimetype='video/other')
333 html = v._repr_html_()
333 html = v._repr_html_()
334 nt.assert_in('src="data:video/other;base64,YWJj"',html)
334 nt.assert_in('src="data:video/other;base64,YWJj"',html)
335
335
336 v = display.Video(b'abc', embed=True, mimetype='video/mp4')
336 v = display.Video(b'abc', embed=True, mimetype='video/mp4')
337 html = v._repr_html_()
337 html = v._repr_html_()
338 nt.assert_in('src="data:video/mp4;base64,YWJj"',html)
338 nt.assert_in('src="data:video/mp4;base64,YWJj"',html)
339
339
340 v = display.Video(u'YWJj', embed=True, mimetype='video/xyz')
340 v = display.Video(u'YWJj', embed=True, mimetype='video/xyz')
341 html = v._repr_html_()
341 html = v._repr_html_()
342 nt.assert_in('src="data:video/xyz;base64,YWJj"',html)
342 nt.assert_in('src="data:video/xyz;base64,YWJj"',html)
343
343
344 def test_html_metadata():
344 def test_html_metadata():
345 s = "<h1>Test</h1>"
345 s = "<h1>Test</h1>"
346 h = display.HTML(s, metadata={"isolated": True})
346 h = display.HTML(s, metadata={"isolated": True})
347 nt.assert_equal(h._repr_html_(), (s, {"isolated": True}))
347 nt.assert_equal(h._repr_html_(), (s, {"isolated": True}))
348
348
349 def test_display_id():
349 def test_display_id():
350 ip = get_ipython()
350 ip = get_ipython()
351 with mock.patch.object(ip.display_pub, 'publish') as pub:
351 with mock.patch.object(ip.display_pub, 'publish') as pub:
352 handle = display.display('x')
352 handle = display.display('x')
353 nt.assert_is(handle, None)
353 nt.assert_is(handle, None)
354 handle = display.display('y', display_id='secret')
354 handle = display.display('y', display_id='secret')
355 nt.assert_is_instance(handle, display.DisplayHandle)
355 nt.assert_is_instance(handle, display.DisplayHandle)
356 handle2 = display.display('z', display_id=True)
356 handle2 = display.display('z', display_id=True)
357 nt.assert_is_instance(handle2, display.DisplayHandle)
357 nt.assert_is_instance(handle2, display.DisplayHandle)
358 nt.assert_not_equal(handle.display_id, handle2.display_id)
358 nt.assert_not_equal(handle.display_id, handle2.display_id)
359
359
360 nt.assert_equal(pub.call_count, 3)
360 nt.assert_equal(pub.call_count, 3)
361 args, kwargs = pub.call_args_list[0]
361 args, kwargs = pub.call_args_list[0]
362 nt.assert_equal(args, ())
362 nt.assert_equal(args, ())
363 nt.assert_equal(kwargs, {
363 nt.assert_equal(kwargs, {
364 'data': {
364 'data': {
365 'text/plain': repr('x')
365 'text/plain': repr('x')
366 },
366 },
367 'metadata': {},
367 'metadata': {},
368 })
368 })
369 args, kwargs = pub.call_args_list[1]
369 args, kwargs = pub.call_args_list[1]
370 nt.assert_equal(args, ())
370 nt.assert_equal(args, ())
371 nt.assert_equal(kwargs, {
371 nt.assert_equal(kwargs, {
372 'data': {
372 'data': {
373 'text/plain': repr('y')
373 'text/plain': repr('y')
374 },
374 },
375 'metadata': {},
375 'metadata': {},
376 'transient': {
376 'transient': {
377 'display_id': handle.display_id,
377 'display_id': handle.display_id,
378 },
378 },
379 })
379 })
380 args, kwargs = pub.call_args_list[2]
380 args, kwargs = pub.call_args_list[2]
381 nt.assert_equal(args, ())
381 nt.assert_equal(args, ())
382 nt.assert_equal(kwargs, {
382 nt.assert_equal(kwargs, {
383 'data': {
383 'data': {
384 'text/plain': repr('z')
384 'text/plain': repr('z')
385 },
385 },
386 'metadata': {},
386 'metadata': {},
387 'transient': {
387 'transient': {
388 'display_id': handle2.display_id,
388 'display_id': handle2.display_id,
389 },
389 },
390 })
390 })
391
391
392
392
393 def test_update_display():
393 def test_update_display():
394 ip = get_ipython()
394 ip = get_ipython()
395 with mock.patch.object(ip.display_pub, 'publish') as pub:
395 with mock.patch.object(ip.display_pub, 'publish') as pub:
396 with nt.assert_raises(TypeError):
396 with nt.assert_raises(TypeError):
397 display.update_display('x')
397 display.update_display('x')
398 display.update_display('x', display_id='1')
398 display.update_display('x', display_id='1')
399 display.update_display('y', display_id='2')
399 display.update_display('y', display_id='2')
400 args, kwargs = pub.call_args_list[0]
400 args, kwargs = pub.call_args_list[0]
401 nt.assert_equal(args, ())
401 nt.assert_equal(args, ())
402 nt.assert_equal(kwargs, {
402 nt.assert_equal(kwargs, {
403 'data': {
403 'data': {
404 'text/plain': repr('x')
404 'text/plain': repr('x')
405 },
405 },
406 'metadata': {},
406 'metadata': {},
407 'transient': {
407 'transient': {
408 'display_id': '1',
408 'display_id': '1',
409 },
409 },
410 'update': True,
410 'update': True,
411 })
411 })
412 args, kwargs = pub.call_args_list[1]
412 args, kwargs = pub.call_args_list[1]
413 nt.assert_equal(args, ())
413 nt.assert_equal(args, ())
414 nt.assert_equal(kwargs, {
414 nt.assert_equal(kwargs, {
415 'data': {
415 'data': {
416 'text/plain': repr('y')
416 'text/plain': repr('y')
417 },
417 },
418 'metadata': {},
418 'metadata': {},
419 'transient': {
419 'transient': {
420 'display_id': '2',
420 'display_id': '2',
421 },
421 },
422 'update': True,
422 'update': True,
423 })
423 })
424
424
425
425
426 def test_display_handle():
426 def test_display_handle():
427 ip = get_ipython()
427 ip = get_ipython()
428 handle = display.DisplayHandle()
428 handle = display.DisplayHandle()
429 nt.assert_is_instance(handle.display_id, str)
429 nt.assert_is_instance(handle.display_id, str)
430 handle = display.DisplayHandle('my-id')
430 handle = display.DisplayHandle('my-id')
431 nt.assert_equal(handle.display_id, 'my-id')
431 nt.assert_equal(handle.display_id, 'my-id')
432 with mock.patch.object(ip.display_pub, 'publish') as pub:
432 with mock.patch.object(ip.display_pub, 'publish') as pub:
433 handle.display('x')
433 handle.display('x')
434 handle.update('y')
434 handle.update('y')
435
435
436 args, kwargs = pub.call_args_list[0]
436 args, kwargs = pub.call_args_list[0]
437 nt.assert_equal(args, ())
437 nt.assert_equal(args, ())
438 nt.assert_equal(kwargs, {
438 nt.assert_equal(kwargs, {
439 'data': {
439 'data': {
440 'text/plain': repr('x')
440 'text/plain': repr('x')
441 },
441 },
442 'metadata': {},
442 'metadata': {},
443 'transient': {
443 'transient': {
444 'display_id': handle.display_id,
444 'display_id': handle.display_id,
445 }
445 }
446 })
446 })
447 args, kwargs = pub.call_args_list[1]
447 args, kwargs = pub.call_args_list[1]
448 nt.assert_equal(args, ())
448 nt.assert_equal(args, ())
449 nt.assert_equal(kwargs, {
449 nt.assert_equal(kwargs, {
450 'data': {
450 'data': {
451 'text/plain': repr('y')
451 'text/plain': repr('y')
452 },
452 },
453 'metadata': {},
453 'metadata': {},
454 'transient': {
454 'transient': {
455 'display_id': handle.display_id,
455 'display_id': handle.display_id,
456 },
456 },
457 'update': True,
457 'update': True,
458 })
458 })
459
459
@@ -1,654 +1,655 b''
1 """Various display related classes.
1 """Various display related classes.
2
2
3 Authors : MinRK, gregcaporaso, dannystaple
3 Authors : MinRK, gregcaporaso, dannystaple
4 """
4 """
5 from html import escape as html_escape
5 from html import escape as html_escape
6 from os.path import exists, isfile, splitext, abspath, join, isdir
6 from os.path import exists, isfile, splitext, abspath, join, isdir
7 from os import walk, sep, fsdecode
7 from os import walk, sep, fsdecode
8
8
9 from IPython.core.display import DisplayObject, TextDisplayObject
9 from IPython.core.display import DisplayObject, TextDisplayObject
10
10
11 from typing import Tuple
12
11 __all__ = ['Audio', 'IFrame', 'YouTubeVideo', 'VimeoVideo', 'ScribdDocument',
13 __all__ = ['Audio', 'IFrame', 'YouTubeVideo', 'VimeoVideo', 'ScribdDocument',
12 'FileLink', 'FileLinks', 'Code']
14 'FileLink', 'FileLinks', 'Code']
13
15
14
16
15 class Audio(DisplayObject):
17 class Audio(DisplayObject):
16 """Create an audio object.
18 """Create an audio object.
17
19
18 When this object is returned by an input cell or passed to the
20 When this object is returned by an input cell or passed to the
19 display function, it will result in Audio controls being displayed
21 display function, it will result in Audio controls being displayed
20 in the frontend (only works in the notebook).
22 in the frontend (only works in the notebook).
21
23
22 Parameters
24 Parameters
23 ----------
25 ----------
24 data : numpy array, list, unicode, str or bytes
26 data : numpy array, list, unicode, str or bytes
25 Can be one of
27 Can be one of
26
28
27 * Numpy 1d array containing the desired waveform (mono)
29 * Numpy 1d array containing the desired waveform (mono)
28 * Numpy 2d array containing waveforms for each channel.
30 * Numpy 2d array containing waveforms for each channel.
29 Shape=(NCHAN, NSAMPLES). For the standard channel order, see
31 Shape=(NCHAN, NSAMPLES). For the standard channel order, see
30 http://msdn.microsoft.com/en-us/library/windows/hardware/dn653308(v=vs.85).aspx
32 http://msdn.microsoft.com/en-us/library/windows/hardware/dn653308(v=vs.85).aspx
31 * List of float or integer representing the waveform (mono)
33 * List of float or integer representing the waveform (mono)
32 * String containing the filename
34 * String containing the filename
33 * Bytestring containing raw PCM data or
35 * Bytestring containing raw PCM data or
34 * URL pointing to a file on the web.
36 * URL pointing to a file on the web.
35
37
36 If the array option is used, the waveform will be normalized.
38 If the array option is used, the waveform will be normalized.
37
39
38 If a filename or url is used, the format support will be browser
40 If a filename or url is used, the format support will be browser
39 dependent.
41 dependent.
40 url : unicode
42 url : unicode
41 A URL to download the data from.
43 A URL to download the data from.
42 filename : unicode
44 filename : unicode
43 Path to a local file to load the data from.
45 Path to a local file to load the data from.
44 embed : boolean
46 embed : boolean
45 Should the audio data be embedded using a data URI (True) or should
47 Should the audio data be embedded using a data URI (True) or should
46 the original source be referenced. Set this to True if you want the
48 the original source be referenced. Set this to True if you want the
47 audio to playable later with no internet connection in the notebook.
49 audio to playable later with no internet connection in the notebook.
48
50
49 Default is `True`, unless the keyword argument `url` is set, then
51 Default is `True`, unless the keyword argument `url` is set, then
50 default value is `False`.
52 default value is `False`.
51 rate : integer
53 rate : integer
52 The sampling rate of the raw data.
54 The sampling rate of the raw data.
53 Only required when data parameter is being used as an array
55 Only required when data parameter is being used as an array
54 autoplay : bool
56 autoplay : bool
55 Set to True if the audio should immediately start playing.
57 Set to True if the audio should immediately start playing.
56 Default is `False`.
58 Default is `False`.
57 normalize : bool
59 normalize : bool
58 Whether audio should be normalized (rescaled) to the maximum possible
60 Whether audio should be normalized (rescaled) to the maximum possible
59 range. Default is `True`. When set to `False`, `data` must be between
61 range. Default is `True`. When set to `False`, `data` must be between
60 -1 and 1 (inclusive), otherwise an error is raised.
62 -1 and 1 (inclusive), otherwise an error is raised.
61 Applies only when `data` is a list or array of samples; other types of
63 Applies only when `data` is a list or array of samples; other types of
62 audio are never normalized.
64 audio are never normalized.
63
65
64 Examples
66 Examples
65 --------
67 --------
66 ::
68 ::
67
69
68 # Generate a sound
70 # Generate a sound
69 import numpy as np
71 import numpy as np
70 framerate = 44100
72 framerate = 44100
71 t = np.linspace(0,5,framerate*5)
73 t = np.linspace(0,5,framerate*5)
72 data = np.sin(2*np.pi*220*t) + np.sin(2*np.pi*224*t)
74 data = np.sin(2*np.pi*220*t) + np.sin(2*np.pi*224*t)
73 Audio(data,rate=framerate)
75 Audio(data,rate=framerate)
74
76
75 # Can also do stereo or more channels
77 # Can also do stereo or more channels
76 dataleft = np.sin(2*np.pi*220*t)
78 dataleft = np.sin(2*np.pi*220*t)
77 dataright = np.sin(2*np.pi*224*t)
79 dataright = np.sin(2*np.pi*224*t)
78 Audio([dataleft, dataright],rate=framerate)
80 Audio([dataleft, dataright],rate=framerate)
79
81
80 Audio("http://www.nch.com.au/acm/8k16bitpcm.wav") # From URL
82 Audio("http://www.nch.com.au/acm/8k16bitpcm.wav") # From URL
81 Audio(url="http://www.w3schools.com/html/horse.ogg")
83 Audio(url="http://www.w3schools.com/html/horse.ogg")
82
84
83 Audio('/path/to/sound.wav') # From file
85 Audio('/path/to/sound.wav') # From file
84 Audio(filename='/path/to/sound.ogg')
86 Audio(filename='/path/to/sound.ogg')
85
87
86 Audio(b'RAW_WAV_DATA..) # From bytes
88 Audio(b'RAW_WAV_DATA..) # From bytes
87 Audio(data=b'RAW_WAV_DATA..)
89 Audio(data=b'RAW_WAV_DATA..)
88
90
89 See Also
91 See Also
90 --------
92 --------
91
93
92 See also the ``Audio`` widgets form the ``ipywidget`` package for more flexibility and options.
94 See also the ``Audio`` widgets form the ``ipywidget`` package for more flexibility and options.
93
95
94 """
96 """
95 _read_flags = 'rb'
97 _read_flags = 'rb'
96
98
97 def __init__(self, data=None, filename=None, url=None, embed=None, rate=None, autoplay=False, normalize=True, *,
99 def __init__(self, data=None, filename=None, url=None, embed=None, rate=None, autoplay=False, normalize=True, *,
98 element_id=None):
100 element_id=None):
99 if filename is None and url is None and data is None:
101 if filename is None and url is None and data is None:
100 raise ValueError("No audio data found. Expecting filename, url, or data.")
102 raise ValueError("No audio data found. Expecting filename, url, or data.")
101 if embed is False and url is None:
103 if embed is False and url is None:
102 raise ValueError("No url found. Expecting url when embed=False")
104 raise ValueError("No url found. Expecting url when embed=False")
103
105
104 if url is not None and embed is not True:
106 if url is not None and embed is not True:
105 self.embed = False
107 self.embed = False
106 else:
108 else:
107 self.embed = True
109 self.embed = True
108 self.autoplay = autoplay
110 self.autoplay = autoplay
109 self.element_id = element_id
111 self.element_id = element_id
110 super(Audio, self).__init__(data=data, url=url, filename=filename)
112 super(Audio, self).__init__(data=data, url=url, filename=filename)
111
113
112 if self.data is not None and not isinstance(self.data, bytes):
114 if self.data is not None and not isinstance(self.data, bytes):
113 if rate is None:
115 if rate is None:
114 raise ValueError("rate must be specified when data is a numpy array or list of audio samples.")
116 raise ValueError("rate must be specified when data is a numpy array or list of audio samples.")
115 self.data = Audio._make_wav(data, rate, normalize)
117 self.data = Audio._make_wav(data, rate, normalize)
116
118
117 def reload(self):
119 def reload(self):
118 """Reload the raw data from file or URL."""
120 """Reload the raw data from file or URL."""
119 import mimetypes
121 import mimetypes
120 if self.embed:
122 if self.embed:
121 super(Audio, self).reload()
123 super(Audio, self).reload()
122
124
123 if self.filename is not None:
125 if self.filename is not None:
124 self.mimetype = mimetypes.guess_type(self.filename)[0]
126 self.mimetype = mimetypes.guess_type(self.filename)[0]
125 elif self.url is not None:
127 elif self.url is not None:
126 self.mimetype = mimetypes.guess_type(self.url)[0]
128 self.mimetype = mimetypes.guess_type(self.url)[0]
127 else:
129 else:
128 self.mimetype = "audio/wav"
130 self.mimetype = "audio/wav"
129
131
130 @staticmethod
132 @staticmethod
131 def _make_wav(data, rate, normalize):
133 def _make_wav(data, rate, normalize):
132 """ Transform a numpy array to a PCM bytestring """
134 """ Transform a numpy array to a PCM bytestring """
133 from io import BytesIO
135 from io import BytesIO
134 import wave
136 import wave
135
137
136 try:
138 try:
137 scaled, nchan = Audio._validate_and_normalize_with_numpy(data, normalize)
139 scaled, nchan = Audio._validate_and_normalize_with_numpy(data, normalize)
138 except ImportError:
140 except ImportError:
139 scaled, nchan = Audio._validate_and_normalize_without_numpy(data, normalize)
141 scaled, nchan = Audio._validate_and_normalize_without_numpy(data, normalize)
140
142
141 fp = BytesIO()
143 fp = BytesIO()
142 waveobj = wave.open(fp,mode='wb')
144 waveobj = wave.open(fp,mode='wb')
143 waveobj.setnchannels(nchan)
145 waveobj.setnchannels(nchan)
144 waveobj.setframerate(rate)
146 waveobj.setframerate(rate)
145 waveobj.setsampwidth(2)
147 waveobj.setsampwidth(2)
146 waveobj.setcomptype('NONE','NONE')
148 waveobj.setcomptype('NONE','NONE')
147 waveobj.writeframes(scaled)
149 waveobj.writeframes(scaled)
148 val = fp.getvalue()
150 val = fp.getvalue()
149 waveobj.close()
151 waveobj.close()
150
152
151 return val
153 return val
152
154
153 @staticmethod
155 @staticmethod
154 def _validate_and_normalize_with_numpy(data, normalize):
156 def _validate_and_normalize_with_numpy(data, normalize) -> Tuple[bytes, int]:
155 import numpy as np
157 import numpy as np
156
158
157 data = np.array(data, dtype=float)
159 data = np.array(data, dtype=float)
158 if len(data.shape) == 1:
160 if len(data.shape) == 1:
159 nchan = 1
161 nchan = 1
160 elif len(data.shape) == 2:
162 elif len(data.shape) == 2:
161 # In wave files,channels are interleaved. E.g.,
163 # In wave files,channels are interleaved. E.g.,
162 # "L1R1L2R2..." for stereo. See
164 # "L1R1L2R2..." for stereo. See
163 # http://msdn.microsoft.com/en-us/library/windows/hardware/dn653308(v=vs.85).aspx
165 # http://msdn.microsoft.com/en-us/library/windows/hardware/dn653308(v=vs.85).aspx
164 # for channel ordering
166 # for channel ordering
165 nchan = data.shape[0]
167 nchan = data.shape[0]
166 data = data.T.ravel()
168 data = data.T.ravel()
167 else:
169 else:
168 raise ValueError('Array audio input must be a 1D or 2D array')
170 raise ValueError('Array audio input must be a 1D or 2D array')
169
171
170 max_abs_value = np.max(np.abs(data))
172 max_abs_value = np.max(np.abs(data))
171 normalization_factor = Audio._get_normalization_factor(max_abs_value, normalize)
173 normalization_factor = Audio._get_normalization_factor(max_abs_value, normalize)
172 scaled = data / normalization_factor * 32767
174 scaled = data / normalization_factor * 32767
173 return scaled.astype('<h').tostring(), nchan
175 return scaled.astype("<h").tobytes(), nchan
174
175
176
176 @staticmethod
177 @staticmethod
177 def _validate_and_normalize_without_numpy(data, normalize):
178 def _validate_and_normalize_without_numpy(data, normalize):
178 import array
179 import array
179 import sys
180 import sys
180
181
181 data = array.array('f', data)
182 data = array.array('f', data)
182
183
183 try:
184 try:
184 max_abs_value = float(max([abs(x) for x in data]))
185 max_abs_value = float(max([abs(x) for x in data]))
185 except TypeError:
186 except TypeError:
186 raise TypeError('Only lists of mono audio are '
187 raise TypeError('Only lists of mono audio are '
187 'supported if numpy is not installed')
188 'supported if numpy is not installed')
188
189
189 normalization_factor = Audio._get_normalization_factor(max_abs_value, normalize)
190 normalization_factor = Audio._get_normalization_factor(max_abs_value, normalize)
190 scaled = array.array('h', [int(x / normalization_factor * 32767) for x in data])
191 scaled = array.array('h', [int(x / normalization_factor * 32767) for x in data])
191 if sys.byteorder == 'big':
192 if sys.byteorder == 'big':
192 scaled.byteswap()
193 scaled.byteswap()
193 nchan = 1
194 nchan = 1
194 return scaled.tobytes(), nchan
195 return scaled.tobytes(), nchan
195
196
196 @staticmethod
197 @staticmethod
197 def _get_normalization_factor(max_abs_value, normalize):
198 def _get_normalization_factor(max_abs_value, normalize):
198 if not normalize and max_abs_value > 1:
199 if not normalize and max_abs_value > 1:
199 raise ValueError('Audio data must be between -1 and 1 when normalize=False.')
200 raise ValueError('Audio data must be between -1 and 1 when normalize=False.')
200 return max_abs_value if normalize else 1
201 return max_abs_value if normalize else 1
201
202
202 def _data_and_metadata(self):
203 def _data_and_metadata(self):
203 """shortcut for returning metadata with url information, if defined"""
204 """shortcut for returning metadata with url information, if defined"""
204 md = {}
205 md = {}
205 if self.url:
206 if self.url:
206 md['url'] = self.url
207 md['url'] = self.url
207 if md:
208 if md:
208 return self.data, md
209 return self.data, md
209 else:
210 else:
210 return self.data
211 return self.data
211
212
212 def _repr_html_(self):
213 def _repr_html_(self):
213 src = """
214 src = """
214 <audio {element_id} controls="controls" {autoplay}>
215 <audio {element_id} controls="controls" {autoplay}>
215 <source src="{src}" type="{type}" />
216 <source src="{src}" type="{type}" />
216 Your browser does not support the audio element.
217 Your browser does not support the audio element.
217 </audio>
218 </audio>
218 """
219 """
219 return src.format(src=self.src_attr(), type=self.mimetype, autoplay=self.autoplay_attr(),
220 return src.format(src=self.src_attr(), type=self.mimetype, autoplay=self.autoplay_attr(),
220 element_id=self.element_id_attr())
221 element_id=self.element_id_attr())
221
222
222 def src_attr(self):
223 def src_attr(self):
223 import base64
224 import base64
224 if self.embed and (self.data is not None):
225 if self.embed and (self.data is not None):
225 data = base64=base64.b64encode(self.data).decode('ascii')
226 data = base64=base64.b64encode(self.data).decode('ascii')
226 return """data:{type};base64,{base64}""".format(type=self.mimetype,
227 return """data:{type};base64,{base64}""".format(type=self.mimetype,
227 base64=data)
228 base64=data)
228 elif self.url is not None:
229 elif self.url is not None:
229 return self.url
230 return self.url
230 else:
231 else:
231 return ""
232 return ""
232
233
233 def autoplay_attr(self):
234 def autoplay_attr(self):
234 if(self.autoplay):
235 if(self.autoplay):
235 return 'autoplay="autoplay"'
236 return 'autoplay="autoplay"'
236 else:
237 else:
237 return ''
238 return ''
238
239
239 def element_id_attr(self):
240 def element_id_attr(self):
240 if (self.element_id):
241 if (self.element_id):
241 return 'id="{element_id}"'.format(element_id=self.element_id)
242 return 'id="{element_id}"'.format(element_id=self.element_id)
242 else:
243 else:
243 return ''
244 return ''
244
245
245 class IFrame(object):
246 class IFrame(object):
246 """
247 """
247 Generic class to embed an iframe in an IPython notebook
248 Generic class to embed an iframe in an IPython notebook
248 """
249 """
249
250
250 iframe = """
251 iframe = """
251 <iframe
252 <iframe
252 width="{width}"
253 width="{width}"
253 height="{height}"
254 height="{height}"
254 src="{src}{params}"
255 src="{src}{params}"
255 frameborder="0"
256 frameborder="0"
256 allowfullscreen
257 allowfullscreen
257 ></iframe>
258 ></iframe>
258 """
259 """
259
260
260 def __init__(self, src, width, height, **kwargs):
261 def __init__(self, src, width, height, **kwargs):
261 self.src = src
262 self.src = src
262 self.width = width
263 self.width = width
263 self.height = height
264 self.height = height
264 self.params = kwargs
265 self.params = kwargs
265
266
266 def _repr_html_(self):
267 def _repr_html_(self):
267 """return the embed iframe"""
268 """return the embed iframe"""
268 if self.params:
269 if self.params:
269 try:
270 try:
270 from urllib.parse import urlencode # Py 3
271 from urllib.parse import urlencode # Py 3
271 except ImportError:
272 except ImportError:
272 from urllib import urlencode
273 from urllib import urlencode
273 params = "?" + urlencode(self.params)
274 params = "?" + urlencode(self.params)
274 else:
275 else:
275 params = ""
276 params = ""
276 return self.iframe.format(src=self.src,
277 return self.iframe.format(src=self.src,
277 width=self.width,
278 width=self.width,
278 height=self.height,
279 height=self.height,
279 params=params)
280 params=params)
280
281
281 class YouTubeVideo(IFrame):
282 class YouTubeVideo(IFrame):
282 """Class for embedding a YouTube Video in an IPython session, based on its video id.
283 """Class for embedding a YouTube Video in an IPython session, based on its video id.
283
284
284 e.g. to embed the video from https://www.youtube.com/watch?v=foo , you would
285 e.g. to embed the video from https://www.youtube.com/watch?v=foo , you would
285 do::
286 do::
286
287
287 vid = YouTubeVideo("foo")
288 vid = YouTubeVideo("foo")
288 display(vid)
289 display(vid)
289
290
290 To start from 30 seconds::
291 To start from 30 seconds::
291
292
292 vid = YouTubeVideo("abc", start=30)
293 vid = YouTubeVideo("abc", start=30)
293 display(vid)
294 display(vid)
294
295
295 To calculate seconds from time as hours, minutes, seconds use
296 To calculate seconds from time as hours, minutes, seconds use
296 :class:`datetime.timedelta`::
297 :class:`datetime.timedelta`::
297
298
298 start=int(timedelta(hours=1, minutes=46, seconds=40).total_seconds())
299 start=int(timedelta(hours=1, minutes=46, seconds=40).total_seconds())
299
300
300 Other parameters can be provided as documented at
301 Other parameters can be provided as documented at
301 https://developers.google.com/youtube/player_parameters#Parameters
302 https://developers.google.com/youtube/player_parameters#Parameters
302
303
303 When converting the notebook using nbconvert, a jpeg representation of the video
304 When converting the notebook using nbconvert, a jpeg representation of the video
304 will be inserted in the document.
305 will be inserted in the document.
305 """
306 """
306
307
307 def __init__(self, id, width=400, height=300, **kwargs):
308 def __init__(self, id, width=400, height=300, **kwargs):
308 self.id=id
309 self.id=id
309 src = "https://www.youtube.com/embed/{0}".format(id)
310 src = "https://www.youtube.com/embed/{0}".format(id)
310 super(YouTubeVideo, self).__init__(src, width, height, **kwargs)
311 super(YouTubeVideo, self).__init__(src, width, height, **kwargs)
311
312
312 def _repr_jpeg_(self):
313 def _repr_jpeg_(self):
313 # Deferred import
314 # Deferred import
314 from urllib.request import urlopen
315 from urllib.request import urlopen
315
316
316 try:
317 try:
317 return urlopen("https://img.youtube.com/vi/{id}/hqdefault.jpg".format(id=self.id)).read()
318 return urlopen("https://img.youtube.com/vi/{id}/hqdefault.jpg".format(id=self.id)).read()
318 except IOError:
319 except IOError:
319 return None
320 return None
320
321
321 class VimeoVideo(IFrame):
322 class VimeoVideo(IFrame):
322 """
323 """
323 Class for embedding a Vimeo video in an IPython session, based on its video id.
324 Class for embedding a Vimeo video in an IPython session, based on its video id.
324 """
325 """
325
326
326 def __init__(self, id, width=400, height=300, **kwargs):
327 def __init__(self, id, width=400, height=300, **kwargs):
327 src="https://player.vimeo.com/video/{0}".format(id)
328 src="https://player.vimeo.com/video/{0}".format(id)
328 super(VimeoVideo, self).__init__(src, width, height, **kwargs)
329 super(VimeoVideo, self).__init__(src, width, height, **kwargs)
329
330
330 class ScribdDocument(IFrame):
331 class ScribdDocument(IFrame):
331 """
332 """
332 Class for embedding a Scribd document in an IPython session
333 Class for embedding a Scribd document in an IPython session
333
334
334 Use the start_page params to specify a starting point in the document
335 Use the start_page params to specify a starting point in the document
335 Use the view_mode params to specify display type one off scroll | slideshow | book
336 Use the view_mode params to specify display type one off scroll | slideshow | book
336
337
337 e.g to Display Wes' foundational paper about PANDAS in book mode from page 3
338 e.g to Display Wes' foundational paper about PANDAS in book mode from page 3
338
339
339 ScribdDocument(71048089, width=800, height=400, start_page=3, view_mode="book")
340 ScribdDocument(71048089, width=800, height=400, start_page=3, view_mode="book")
340 """
341 """
341
342
342 def __init__(self, id, width=400, height=300, **kwargs):
343 def __init__(self, id, width=400, height=300, **kwargs):
343 src="https://www.scribd.com/embeds/{0}/content".format(id)
344 src="https://www.scribd.com/embeds/{0}/content".format(id)
344 super(ScribdDocument, self).__init__(src, width, height, **kwargs)
345 super(ScribdDocument, self).__init__(src, width, height, **kwargs)
345
346
346 class FileLink(object):
347 class FileLink(object):
347 """Class for embedding a local file link in an IPython session, based on path
348 """Class for embedding a local file link in an IPython session, based on path
348
349
349 e.g. to embed a link that was generated in the IPython notebook as my/data.txt
350 e.g. to embed a link that was generated in the IPython notebook as my/data.txt
350
351
351 you would do::
352 you would do::
352
353
353 local_file = FileLink("my/data.txt")
354 local_file = FileLink("my/data.txt")
354 display(local_file)
355 display(local_file)
355
356
356 or in the HTML notebook, just::
357 or in the HTML notebook, just::
357
358
358 FileLink("my/data.txt")
359 FileLink("my/data.txt")
359 """
360 """
360
361
361 html_link_str = "<a href='%s' target='_blank'>%s</a>"
362 html_link_str = "<a href='%s' target='_blank'>%s</a>"
362
363
363 def __init__(self,
364 def __init__(self,
364 path,
365 path,
365 url_prefix='',
366 url_prefix='',
366 result_html_prefix='',
367 result_html_prefix='',
367 result_html_suffix='<br>'):
368 result_html_suffix='<br>'):
368 """
369 """
369 Parameters
370 Parameters
370 ----------
371 ----------
371 path : str
372 path : str
372 path to the file or directory that should be formatted
373 path to the file or directory that should be formatted
373 url_prefix : str
374 url_prefix : str
374 prefix to be prepended to all files to form a working link [default:
375 prefix to be prepended to all files to form a working link [default:
375 '']
376 '']
376 result_html_prefix : str
377 result_html_prefix : str
377 text to append to beginning to link [default: '']
378 text to append to beginning to link [default: '']
378 result_html_suffix : str
379 result_html_suffix : str
379 text to append at the end of link [default: '<br>']
380 text to append at the end of link [default: '<br>']
380 """
381 """
381 if isdir(path):
382 if isdir(path):
382 raise ValueError("Cannot display a directory using FileLink. "
383 raise ValueError("Cannot display a directory using FileLink. "
383 "Use FileLinks to display '%s'." % path)
384 "Use FileLinks to display '%s'." % path)
384 self.path = fsdecode(path)
385 self.path = fsdecode(path)
385 self.url_prefix = url_prefix
386 self.url_prefix = url_prefix
386 self.result_html_prefix = result_html_prefix
387 self.result_html_prefix = result_html_prefix
387 self.result_html_suffix = result_html_suffix
388 self.result_html_suffix = result_html_suffix
388
389
389 def _format_path(self):
390 def _format_path(self):
390 fp = ''.join([self.url_prefix, html_escape(self.path)])
391 fp = ''.join([self.url_prefix, html_escape(self.path)])
391 return ''.join([self.result_html_prefix,
392 return ''.join([self.result_html_prefix,
392 self.html_link_str % \
393 self.html_link_str % \
393 (fp, html_escape(self.path, quote=False)),
394 (fp, html_escape(self.path, quote=False)),
394 self.result_html_suffix])
395 self.result_html_suffix])
395
396
396 def _repr_html_(self):
397 def _repr_html_(self):
397 """return html link to file
398 """return html link to file
398 """
399 """
399 if not exists(self.path):
400 if not exists(self.path):
400 return ("Path (<tt>%s</tt>) doesn't exist. "
401 return ("Path (<tt>%s</tt>) doesn't exist. "
401 "It may still be in the process of "
402 "It may still be in the process of "
402 "being generated, or you may have the "
403 "being generated, or you may have the "
403 "incorrect path." % self.path)
404 "incorrect path." % self.path)
404
405
405 return self._format_path()
406 return self._format_path()
406
407
407 def __repr__(self):
408 def __repr__(self):
408 """return absolute path to file
409 """return absolute path to file
409 """
410 """
410 return abspath(self.path)
411 return abspath(self.path)
411
412
412 class FileLinks(FileLink):
413 class FileLinks(FileLink):
413 """Class for embedding local file links in an IPython session, based on path
414 """Class for embedding local file links in an IPython session, based on path
414
415
415 e.g. to embed links to files that were generated in the IPython notebook
416 e.g. to embed links to files that were generated in the IPython notebook
416 under ``my/data``, you would do::
417 under ``my/data``, you would do::
417
418
418 local_files = FileLinks("my/data")
419 local_files = FileLinks("my/data")
419 display(local_files)
420 display(local_files)
420
421
421 or in the HTML notebook, just::
422 or in the HTML notebook, just::
422
423
423 FileLinks("my/data")
424 FileLinks("my/data")
424 """
425 """
425 def __init__(self,
426 def __init__(self,
426 path,
427 path,
427 url_prefix='',
428 url_prefix='',
428 included_suffixes=None,
429 included_suffixes=None,
429 result_html_prefix='',
430 result_html_prefix='',
430 result_html_suffix='<br>',
431 result_html_suffix='<br>',
431 notebook_display_formatter=None,
432 notebook_display_formatter=None,
432 terminal_display_formatter=None,
433 terminal_display_formatter=None,
433 recursive=True):
434 recursive=True):
434 """
435 """
435 See :class:`FileLink` for the ``path``, ``url_prefix``,
436 See :class:`FileLink` for the ``path``, ``url_prefix``,
436 ``result_html_prefix`` and ``result_html_suffix`` parameters.
437 ``result_html_prefix`` and ``result_html_suffix`` parameters.
437
438
438 included_suffixes : list
439 included_suffixes : list
439 Filename suffixes to include when formatting output [default: include
440 Filename suffixes to include when formatting output [default: include
440 all files]
441 all files]
441
442
442 notebook_display_formatter : function
443 notebook_display_formatter : function
443 Used to format links for display in the notebook. See discussion of
444 Used to format links for display in the notebook. See discussion of
444 formatter functions below.
445 formatter functions below.
445
446
446 terminal_display_formatter : function
447 terminal_display_formatter : function
447 Used to format links for display in the terminal. See discussion of
448 Used to format links for display in the terminal. See discussion of
448 formatter functions below.
449 formatter functions below.
449
450
450 Formatter functions must be of the form::
451 Formatter functions must be of the form::
451
452
452 f(dirname, fnames, included_suffixes)
453 f(dirname, fnames, included_suffixes)
453
454
454 dirname : str
455 dirname : str
455 The name of a directory
456 The name of a directory
456 fnames : list
457 fnames : list
457 The files in that directory
458 The files in that directory
458 included_suffixes : list
459 included_suffixes : list
459 The file suffixes that should be included in the output (passing None
460 The file suffixes that should be included in the output (passing None
460 meansto include all suffixes in the output in the built-in formatters)
461 meansto include all suffixes in the output in the built-in formatters)
461 recursive : boolean
462 recursive : boolean
462 Whether to recurse into subdirectories. Default is True.
463 Whether to recurse into subdirectories. Default is True.
463
464
464 The function should return a list of lines that will be printed in the
465 The function should return a list of lines that will be printed in the
465 notebook (if passing notebook_display_formatter) or the terminal (if
466 notebook (if passing notebook_display_formatter) or the terminal (if
466 passing terminal_display_formatter). This function is iterated over for
467 passing terminal_display_formatter). This function is iterated over for
467 each directory in self.path. Default formatters are in place, can be
468 each directory in self.path. Default formatters are in place, can be
468 passed here to support alternative formatting.
469 passed here to support alternative formatting.
469
470
470 """
471 """
471 if isfile(path):
472 if isfile(path):
472 raise ValueError("Cannot display a file using FileLinks. "
473 raise ValueError("Cannot display a file using FileLinks. "
473 "Use FileLink to display '%s'." % path)
474 "Use FileLink to display '%s'." % path)
474 self.included_suffixes = included_suffixes
475 self.included_suffixes = included_suffixes
475 # remove trailing slashes for more consistent output formatting
476 # remove trailing slashes for more consistent output formatting
476 path = path.rstrip('/')
477 path = path.rstrip('/')
477
478
478 self.path = path
479 self.path = path
479 self.url_prefix = url_prefix
480 self.url_prefix = url_prefix
480 self.result_html_prefix = result_html_prefix
481 self.result_html_prefix = result_html_prefix
481 self.result_html_suffix = result_html_suffix
482 self.result_html_suffix = result_html_suffix
482
483
483 self.notebook_display_formatter = \
484 self.notebook_display_formatter = \
484 notebook_display_formatter or self._get_notebook_display_formatter()
485 notebook_display_formatter or self._get_notebook_display_formatter()
485 self.terminal_display_formatter = \
486 self.terminal_display_formatter = \
486 terminal_display_formatter or self._get_terminal_display_formatter()
487 terminal_display_formatter or self._get_terminal_display_formatter()
487
488
488 self.recursive = recursive
489 self.recursive = recursive
489
490
490 def _get_display_formatter(self,
491 def _get_display_formatter(self,
491 dirname_output_format,
492 dirname_output_format,
492 fname_output_format,
493 fname_output_format,
493 fp_format,
494 fp_format,
494 fp_cleaner=None):
495 fp_cleaner=None):
495 """ generate built-in formatter function
496 """ generate built-in formatter function
496
497
497 this is used to define both the notebook and terminal built-in
498 this is used to define both the notebook and terminal built-in
498 formatters as they only differ by some wrapper text for each entry
499 formatters as they only differ by some wrapper text for each entry
499
500
500 dirname_output_format: string to use for formatting directory
501 dirname_output_format: string to use for formatting directory
501 names, dirname will be substituted for a single "%s" which
502 names, dirname will be substituted for a single "%s" which
502 must appear in this string
503 must appear in this string
503 fname_output_format: string to use for formatting file names,
504 fname_output_format: string to use for formatting file names,
504 if a single "%s" appears in the string, fname will be substituted
505 if a single "%s" appears in the string, fname will be substituted
505 if two "%s" appear in the string, the path to fname will be
506 if two "%s" appear in the string, the path to fname will be
506 substituted for the first and fname will be substituted for the
507 substituted for the first and fname will be substituted for the
507 second
508 second
508 fp_format: string to use for formatting filepaths, must contain
509 fp_format: string to use for formatting filepaths, must contain
509 exactly two "%s" and the dirname will be substituted for the first
510 exactly two "%s" and the dirname will be substituted for the first
510 and fname will be substituted for the second
511 and fname will be substituted for the second
511 """
512 """
512 def f(dirname, fnames, included_suffixes=None):
513 def f(dirname, fnames, included_suffixes=None):
513 result = []
514 result = []
514 # begin by figuring out which filenames, if any,
515 # begin by figuring out which filenames, if any,
515 # are going to be displayed
516 # are going to be displayed
516 display_fnames = []
517 display_fnames = []
517 for fname in fnames:
518 for fname in fnames:
518 if (isfile(join(dirname,fname)) and
519 if (isfile(join(dirname,fname)) and
519 (included_suffixes is None or
520 (included_suffixes is None or
520 splitext(fname)[1] in included_suffixes)):
521 splitext(fname)[1] in included_suffixes)):
521 display_fnames.append(fname)
522 display_fnames.append(fname)
522
523
523 if len(display_fnames) == 0:
524 if len(display_fnames) == 0:
524 # if there are no filenames to display, don't print anything
525 # if there are no filenames to display, don't print anything
525 # (not even the directory name)
526 # (not even the directory name)
526 pass
527 pass
527 else:
528 else:
528 # otherwise print the formatted directory name followed by
529 # otherwise print the formatted directory name followed by
529 # the formatted filenames
530 # the formatted filenames
530 dirname_output_line = dirname_output_format % dirname
531 dirname_output_line = dirname_output_format % dirname
531 result.append(dirname_output_line)
532 result.append(dirname_output_line)
532 for fname in display_fnames:
533 for fname in display_fnames:
533 fp = fp_format % (dirname,fname)
534 fp = fp_format % (dirname,fname)
534 if fp_cleaner is not None:
535 if fp_cleaner is not None:
535 fp = fp_cleaner(fp)
536 fp = fp_cleaner(fp)
536 try:
537 try:
537 # output can include both a filepath and a filename...
538 # output can include both a filepath and a filename...
538 fname_output_line = fname_output_format % (fp, fname)
539 fname_output_line = fname_output_format % (fp, fname)
539 except TypeError:
540 except TypeError:
540 # ... or just a single filepath
541 # ... or just a single filepath
541 fname_output_line = fname_output_format % fname
542 fname_output_line = fname_output_format % fname
542 result.append(fname_output_line)
543 result.append(fname_output_line)
543 return result
544 return result
544 return f
545 return f
545
546
546 def _get_notebook_display_formatter(self,
547 def _get_notebook_display_formatter(self,
547 spacer="&nbsp;&nbsp;"):
548 spacer="&nbsp;&nbsp;"):
548 """ generate function to use for notebook formatting
549 """ generate function to use for notebook formatting
549 """
550 """
550 dirname_output_format = \
551 dirname_output_format = \
551 self.result_html_prefix + "%s/" + self.result_html_suffix
552 self.result_html_prefix + "%s/" + self.result_html_suffix
552 fname_output_format = \
553 fname_output_format = \
553 self.result_html_prefix + spacer + self.html_link_str + self.result_html_suffix
554 self.result_html_prefix + spacer + self.html_link_str + self.result_html_suffix
554 fp_format = self.url_prefix + '%s/%s'
555 fp_format = self.url_prefix + '%s/%s'
555 if sep == "\\":
556 if sep == "\\":
556 # Working on a platform where the path separator is "\", so
557 # Working on a platform where the path separator is "\", so
557 # must convert these to "/" for generating a URI
558 # must convert these to "/" for generating a URI
558 def fp_cleaner(fp):
559 def fp_cleaner(fp):
559 # Replace all occurrences of backslash ("\") with a forward
560 # Replace all occurrences of backslash ("\") with a forward
560 # slash ("/") - this is necessary on windows when a path is
561 # slash ("/") - this is necessary on windows when a path is
561 # provided as input, but we must link to a URI
562 # provided as input, but we must link to a URI
562 return fp.replace('\\','/')
563 return fp.replace('\\','/')
563 else:
564 else:
564 fp_cleaner = None
565 fp_cleaner = None
565
566
566 return self._get_display_formatter(dirname_output_format,
567 return self._get_display_formatter(dirname_output_format,
567 fname_output_format,
568 fname_output_format,
568 fp_format,
569 fp_format,
569 fp_cleaner)
570 fp_cleaner)
570
571
571 def _get_terminal_display_formatter(self,
572 def _get_terminal_display_formatter(self,
572 spacer=" "):
573 spacer=" "):
573 """ generate function to use for terminal formatting
574 """ generate function to use for terminal formatting
574 """
575 """
575 dirname_output_format = "%s/"
576 dirname_output_format = "%s/"
576 fname_output_format = spacer + "%s"
577 fname_output_format = spacer + "%s"
577 fp_format = '%s/%s'
578 fp_format = '%s/%s'
578
579
579 return self._get_display_formatter(dirname_output_format,
580 return self._get_display_formatter(dirname_output_format,
580 fname_output_format,
581 fname_output_format,
581 fp_format)
582 fp_format)
582
583
583 def _format_path(self):
584 def _format_path(self):
584 result_lines = []
585 result_lines = []
585 if self.recursive:
586 if self.recursive:
586 walked_dir = list(walk(self.path))
587 walked_dir = list(walk(self.path))
587 else:
588 else:
588 walked_dir = [next(walk(self.path))]
589 walked_dir = [next(walk(self.path))]
589 walked_dir.sort()
590 walked_dir.sort()
590 for dirname, subdirs, fnames in walked_dir:
591 for dirname, subdirs, fnames in walked_dir:
591 result_lines += self.notebook_display_formatter(dirname, fnames, self.included_suffixes)
592 result_lines += self.notebook_display_formatter(dirname, fnames, self.included_suffixes)
592 return '\n'.join(result_lines)
593 return '\n'.join(result_lines)
593
594
594 def __repr__(self):
595 def __repr__(self):
595 """return newline-separated absolute paths
596 """return newline-separated absolute paths
596 """
597 """
597 result_lines = []
598 result_lines = []
598 if self.recursive:
599 if self.recursive:
599 walked_dir = list(walk(self.path))
600 walked_dir = list(walk(self.path))
600 else:
601 else:
601 walked_dir = [next(walk(self.path))]
602 walked_dir = [next(walk(self.path))]
602 walked_dir.sort()
603 walked_dir.sort()
603 for dirname, subdirs, fnames in walked_dir:
604 for dirname, subdirs, fnames in walked_dir:
604 result_lines += self.terminal_display_formatter(dirname, fnames, self.included_suffixes)
605 result_lines += self.terminal_display_formatter(dirname, fnames, self.included_suffixes)
605 return '\n'.join(result_lines)
606 return '\n'.join(result_lines)
606
607
607
608
608 class Code(TextDisplayObject):
609 class Code(TextDisplayObject):
609 """Display syntax-highlighted source code.
610 """Display syntax-highlighted source code.
610
611
611 This uses Pygments to highlight the code for HTML and Latex output.
612 This uses Pygments to highlight the code for HTML and Latex output.
612
613
613 Parameters
614 Parameters
614 ----------
615 ----------
615 data : str
616 data : str
616 The code as a string
617 The code as a string
617 url : str
618 url : str
618 A URL to fetch the code from
619 A URL to fetch the code from
619 filename : str
620 filename : str
620 A local filename to load the code from
621 A local filename to load the code from
621 language : str
622 language : str
622 The short name of a Pygments lexer to use for highlighting.
623 The short name of a Pygments lexer to use for highlighting.
623 If not specified, it will guess the lexer based on the filename
624 If not specified, it will guess the lexer based on the filename
624 or the code. Available lexers: http://pygments.org/docs/lexers/
625 or the code. Available lexers: http://pygments.org/docs/lexers/
625 """
626 """
626 def __init__(self, data=None, url=None, filename=None, language=None):
627 def __init__(self, data=None, url=None, filename=None, language=None):
627 self.language = language
628 self.language = language
628 super().__init__(data=data, url=url, filename=filename)
629 super().__init__(data=data, url=url, filename=filename)
629
630
630 def _get_lexer(self):
631 def _get_lexer(self):
631 if self.language:
632 if self.language:
632 from pygments.lexers import get_lexer_by_name
633 from pygments.lexers import get_lexer_by_name
633 return get_lexer_by_name(self.language)
634 return get_lexer_by_name(self.language)
634 elif self.filename:
635 elif self.filename:
635 from pygments.lexers import get_lexer_for_filename
636 from pygments.lexers import get_lexer_for_filename
636 return get_lexer_for_filename(self.filename)
637 return get_lexer_for_filename(self.filename)
637 else:
638 else:
638 from pygments.lexers import guess_lexer
639 from pygments.lexers import guess_lexer
639 return guess_lexer(self.data)
640 return guess_lexer(self.data)
640
641
641 def __repr__(self):
642 def __repr__(self):
642 return self.data
643 return self.data
643
644
644 def _repr_html_(self):
645 def _repr_html_(self):
645 from pygments import highlight
646 from pygments import highlight
646 from pygments.formatters import HtmlFormatter
647 from pygments.formatters import HtmlFormatter
647 fmt = HtmlFormatter()
648 fmt = HtmlFormatter()
648 style = '<style>{}</style>'.format(fmt.get_style_defs('.output_html'))
649 style = '<style>{}</style>'.format(fmt.get_style_defs('.output_html'))
649 return style + highlight(self.data, self._get_lexer(), fmt)
650 return style + highlight(self.data, self._get_lexer(), fmt)
650
651
651 def _repr_latex_(self):
652 def _repr_latex_(self):
652 from pygments import highlight
653 from pygments import highlight
653 from pygments.formatters import LatexFormatter
654 from pygments.formatters import LatexFormatter
654 return highlight(self.data, self._get_lexer(), LatexFormatter())
655 return highlight(self.data, self._get_lexer(), LatexFormatter())
@@ -1,1280 +1,1282 b''
1 ============
1 ============
2 7.x Series
2 7.x Series
3 ============
3 ============
4
4
5 .. _version 7.22:
5 .. _version 7.22:
6 =================
6
7 IPython 7.22
8 ============
7
9
8
10
9 Thanks
11 Thanks
10 ------
12 ------
11
13
12 We have a new team member that you should see more often on the IPython
14 We have a new team member that you should see more often on the IPython
13 repository, BΕ‚aΕΌej Michalik (@MrMino) have been doing regular contributions to
15 repository, BΕ‚aΕΌej Michalik (@MrMino) have been doing regular contributions to
14 IPython, and spent time replying to many issues and guiding new users to the
16 IPython, and spent time replying to many issues and guiding new users to the
15 codebase; they now have triage permissions to the IPython repository and we'll
17 codebase; they now have triage permissions to the IPython repository and we'll
16 work toward giving them more permission in the future.
18 work toward giving them more permission in the future.
17
19
18 Many thanks to all the contributors to this release you can find all individual
20 Many thanks to all the contributors to this release you can find all individual
19 contributions to this milestone `on github <https://github.com/ipython/ipython/milestone/XX>`_.
21 contributions to this milestone `on github <https://github.com/ipython/ipython/milestone/XX>`__.
20
22
21 Thanks as well to organisations, QuantStack for working on debugger
23 Thanks as well to organisations, QuantStack for working on debugger
22 compatibility for Xeus_python, and the `D. E. Shaw group
24 compatibility for Xeus_python, and the `D. E. Shaw group
23 <https://deshaw.com/>` for sponsoring work on IPython and related libraries.
25 <https://deshaw.com/>` for sponsoring work on IPython and related libraries.
24
26
25 .. _version 721:
27 .. _version 721:
26
28
27 IPython 7.21
29 IPython 7.21
28 ============
30 ============
29
31
30 IPython 7.21 is the first release we have back on schedule of one release every
32 IPython 7.21 is the first release we have back on schedule of one release every
31 month; it contains a number of minor fixes and improvements, notably, the new
33 month; it contains a number of minor fixes and improvements, notably, the new
32 context command for ipdb
34 context command for ipdb
33
35
34
36
35 New "context" command in ipdb
37 New "context" command in ipdb
36 -----------------------------
38 -----------------------------
37
39
38 It is now possible to change the number of lines shown in the backtrace
40 It is now possible to change the number of lines shown in the backtrace
39 information in ipdb using "context" command. :ghpull:`12826`
41 information in ipdb using "context" command. :ghpull:`12826`
40
42
41 (thanks @MrMino, there are other improvement from them on master).
43 (thanks @MrMino, there are other improvement from them on master).
42
44
43 Other notable changes in IPython 7.21
45 Other notable changes in IPython 7.21
44 -------------------------------------
46 -------------------------------------
45
47
46 - Fix some issues on new osx-arm64 :ghpull:`12804`, :ghpull:`12807`.
48 - Fix some issues on new osx-arm64 :ghpull:`12804`, :ghpull:`12807`.
47 - Compatibility with Xeus-Python for debugger protocol, :ghpull:`12809`
49 - Compatibility with Xeus-Python for debugger protocol, :ghpull:`12809`
48 - Misc docs fixes for compatibility and uniformity with Numpydoc.
50 - Misc docs fixes for compatibility and uniformity with Numpydoc.
49 :ghpull:`12824`
51 :ghpull:`12824`
50
52
51
53
52 Thanks
54 Thanks
53 ------
55 ------
54
56
55 Many thanks to all the contributors to this release you can find all individual
57 Many thanks to all the contributors to this release you can find all individual
56 contribution to this milestone `on github <https://github.com/ipython/ipython/milestone/83>`_.
58 contribution to this milestone `on github <https://github.com/ipython/ipython/milestone/83>`__.
57
59
58
60
59 .. _version 720:
61 .. _version 720:
60
62
61 IPython 7.20
63 IPython 7.20
62 ============
64 ============
63
65
64 IPython 7.20 is the accumulation of 3 month of work on IPython, spacing between
66 IPython 7.20 is the accumulation of 3 month of work on IPython, spacing between
65 IPython release have been increased from the usual once a month for various
67 IPython release have been increased from the usual once a month for various
66 reason.
68 reason.
67
69
68 - Mainly as I'm too busy and the effectively sole maintainer, and
70 - Mainly as I'm too busy and the effectively sole maintainer, and
69 - Second because not much changes happened before mid December.
71 - Second because not much changes happened before mid December.
70
72
71 The main driver for this release was the new version of Jedi 0.18 breaking API;
73 The main driver for this release was the new version of Jedi 0.18 breaking API;
72 which was taken care of in the master branch early in 2020 but not in 7.x as I
74 which was taken care of in the master branch early in 2020 but not in 7.x as I
73 though that by now 8.0 would be out.
75 though that by now 8.0 would be out.
74
76
75 The inclusion of a resolver in pip did not help and actually made things worse.
77 The inclusion of a resolver in pip did not help and actually made things worse.
76 If usually I would have simply pinned Jedi to ``<0.18``; this is not a solution
78 If usually I would have simply pinned Jedi to ``<0.18``; this is not a solution
77 anymore as now pip is free to install Jedi 0.18, and downgrade IPython.
79 anymore as now pip is free to install Jedi 0.18, and downgrade IPython.
78
80
79 I'll do my best to keep the regular release, but as the 8.0-dev branch and 7.x
81 I'll do my best to keep the regular release, but as the 8.0-dev branch and 7.x
80 are starting to diverge this is becoming difficult in particular with my limited
82 are starting to diverge this is becoming difficult in particular with my limited
81 time, so if you have any cycles to spare I'll appreciate your help to respond to
83 time, so if you have any cycles to spare I'll appreciate your help to respond to
82 issues and pushing 8.0 forward.
84 issues and pushing 8.0 forward.
83
85
84 Here are thus some of the changes for IPython 7.20.
86 Here are thus some of the changes for IPython 7.20.
85
87
86 - Support for PyQt5 >= 5.11 :ghpull:`12715`
88 - Support for PyQt5 >= 5.11 :ghpull:`12715`
87 - ``%reset`` remove imports more agressively :ghpull:`12718`
89 - ``%reset`` remove imports more agressively :ghpull:`12718`
88 - fix the ``%conda`` magic :ghpull:`12739`
90 - fix the ``%conda`` magic :ghpull:`12739`
89 - compatibility with Jedi 0.18, and bump minimum Jedi version. :ghpull:`12793`
91 - compatibility with Jedi 0.18, and bump minimum Jedi version. :ghpull:`12793`
90
92
91
93
92 .. _version 719:
94 .. _version 719:
93
95
94 IPython 7.19
96 IPython 7.19
95 ============
97 ============
96
98
97 IPython 7.19 accumulative two month of works, bug fixes and improvements, there
99 IPython 7.19 accumulative two month of works, bug fixes and improvements, there
98 was exceptionally no release last month.
100 was exceptionally no release last month.
99
101
100 - Fix to restore the ability to specify more than one extension using command
102 - Fix to restore the ability to specify more than one extension using command
101 line flags when using traitlets 5.0 :ghpull:`12543`
103 line flags when using traitlets 5.0 :ghpull:`12543`
102 - Docs docs formatting that make the install commands work on zsh
104 - Docs docs formatting that make the install commands work on zsh
103 :ghpull:`12587`
105 :ghpull:`12587`
104 - Always display the last frame in tracebacks even if hidden with
106 - Always display the last frame in tracebacks even if hidden with
105 ``__traceback_hide__`` :ghpull:`12601`
107 ``__traceback_hide__`` :ghpull:`12601`
106 - Avoid an issue where a callback can be registered multiple times.
108 - Avoid an issue where a callback can be registered multiple times.
107 :ghpull:`12625`
109 :ghpull:`12625`
108 - Avoid an issue in debugger mode where frames changes could be lost.
110 - Avoid an issue in debugger mode where frames changes could be lost.
109 :ghpull:`12627`
111 :ghpull:`12627`
110
112
111 - Never hide the frames that invoke a debugger, even if marked as hidden by
113 - Never hide the frames that invoke a debugger, even if marked as hidden by
112 ``__traceback_hide__`` :ghpull:`12631`
114 ``__traceback_hide__`` :ghpull:`12631`
113 - Fix calling the debugger in a recursive manner :ghpull:`12659`
115 - Fix calling the debugger in a recursive manner :ghpull:`12659`
114
116
115
117
116 A number of code changes have landed on master and we are getting close to
118 A number of code changes have landed on master and we are getting close to
117 enough new features and codebase improvement that a 8.0 start to make sens.
119 enough new features and codebase improvement that a 8.0 start to make sens.
118 For downstream packages, please start working on migrating downstream testing
120 For downstream packages, please start working on migrating downstream testing
119 away from iptest and using pytest, as nose will not work on Python 3.10 and we
121 away from iptest and using pytest, as nose will not work on Python 3.10 and we
120 will likely start removing it as a dependency for testing.
122 will likely start removing it as a dependency for testing.
121
123
122 .. _version 718:
124 .. _version 718:
123
125
124 IPython 7.18
126 IPython 7.18
125 ============
127 ============
126
128
127 IPython 7.18 is a minor release that mostly contains bugfixes.
129 IPython 7.18 is a minor release that mostly contains bugfixes.
128
130
129 - ``CRLF`` is now handled by magics my default; solving some issues due to copy
131 - ``CRLF`` is now handled by magics my default; solving some issues due to copy
130 pasting on windows. :ghpull:`12475`
132 pasting on windows. :ghpull:`12475`
131
133
132 - Requiring pexpect ``>=4.3`` as we are Python 3.7+ only and earlier version of
134 - Requiring pexpect ``>=4.3`` as we are Python 3.7+ only and earlier version of
133 pexpect will be incompatible. :ghpull:`12510`
135 pexpect will be incompatible. :ghpull:`12510`
134
136
135 - Minimum jedi version is now 0.16. :ghpull:`12488`
137 - Minimum jedi version is now 0.16. :ghpull:`12488`
136
138
137
139
138
140
139 .. _version 717:
141 .. _version 717:
140
142
141 IPython 7.17
143 IPython 7.17
142 ============
144 ============
143
145
144 IPython 7.17 brings a couple of new improvements to API and a couple of user
146 IPython 7.17 brings a couple of new improvements to API and a couple of user
145 facing changes to make the terminal experience more user friendly.
147 facing changes to make the terminal experience more user friendly.
146
148
147 :ghpull:`12407` introduces the ability to pass extra argument to the IPython
149 :ghpull:`12407` introduces the ability to pass extra argument to the IPython
148 debugger class; this is to help a new project from ``kmaork``
150 debugger class; this is to help a new project from ``kmaork``
149 (https://github.com/kmaork/madbg) to feature a fully remote debugger.
151 (https://github.com/kmaork/madbg) to feature a fully remote debugger.
150
152
151 :ghpull:`12410` finally remove support for 3.6, while the codebase is still
153 :ghpull:`12410` finally remove support for 3.6, while the codebase is still
152 technically compatible; IPython will not install on Python 3.6.
154 technically compatible; IPython will not install on Python 3.6.
153
155
154 lots of work on the debugger and hidden frames from ``@impact27`` in
156 lots of work on the debugger and hidden frames from ``@impact27`` in
155 :ghpull:`12437`, :ghpull:`12445`, :ghpull:`12460` and in particular
157 :ghpull:`12437`, :ghpull:`12445`, :ghpull:`12460` and in particular
156 :ghpull:`12453` which make the debug magic more robust at handling spaces.
158 :ghpull:`12453` which make the debug magic more robust at handling spaces.
157
159
158 Biggest API addition is code transformation which is done before code execution;
160 Biggest API addition is code transformation which is done before code execution;
159 IPython allows a number of hooks to catch non-valid Python syntax (magic, prompt
161 IPython allows a number of hooks to catch non-valid Python syntax (magic, prompt
160 stripping...etc). Transformers are usually called many time; typically:
162 stripping...etc). Transformers are usually called many time; typically:
161
163
162 - When trying to figure out whether the code is complete and valid (should we
164 - When trying to figure out whether the code is complete and valid (should we
163 insert a new line or execute ?)
165 insert a new line or execute ?)
164 - During actual code execution pass before giving the code to Python's
166 - During actual code execution pass before giving the code to Python's
165 ``exec``.
167 ``exec``.
166
168
167 This lead to issues when transformer might have had side effects; or do external
169 This lead to issues when transformer might have had side effects; or do external
168 queries. Starting with IPython 7.17 you can expect your transformer to be called
170 queries. Starting with IPython 7.17 you can expect your transformer to be called
169 less time.
171 less time.
170
172
171 Input transformers are now called only once in the execution path of
173 Input transformers are now called only once in the execution path of
172 `InteractiveShell`, allowing to register transformer that potentially have side
174 `InteractiveShell`, allowing to register transformer that potentially have side
173 effects (note that this is not recommended). Internal methods `should_run_async`, and
175 effects (note that this is not recommended). Internal methods `should_run_async`, and
174 `run_cell_async` now take a recommended optional `transformed_cell`, and
176 `run_cell_async` now take a recommended optional `transformed_cell`, and
175 `preprocessing_exc_tuple` parameters that will become mandatory at some point in
177 `preprocessing_exc_tuple` parameters that will become mandatory at some point in
176 the future; that is to say cells need to be explicitly transformed to be valid
178 the future; that is to say cells need to be explicitly transformed to be valid
177 Python syntax ahead of trying to run them. :ghpull:`12440`;
179 Python syntax ahead of trying to run them. :ghpull:`12440`;
178
180
179 ``input_transformers`` can now also have an attribute ``has_side_effects`` set
181 ``input_transformers`` can now also have an attribute ``has_side_effects`` set
180 to `True`, when this attribute is present; this will prevent the transformers
182 to `True`, when this attribute is present; this will prevent the transformers
181 from being ran when IPython is trying to guess whether the user input is
183 from being ran when IPython is trying to guess whether the user input is
182 complete. Note that this may means you will need to explicitly execute in some
184 complete. Note that this may means you will need to explicitly execute in some
183 case where your transformations are now not ran; but will not affect users with
185 case where your transformations are now not ran; but will not affect users with
184 no custom extensions.
186 no custom extensions.
185
187
186
188
187 API Changes
189 API Changes
188 -----------
190 -----------
189
191
190 Change of API and exposed objects automatically detected using `frappuccino
192 Change of API and exposed objects automatically detected using `frappuccino
191 <https://pypi.org/project/frappuccino/>`_
193 <https://pypi.org/project/frappuccino/>`_
192
194
193
195
194 The following items are new since 7.16.0::
196 The following items are new since 7.16.0::
195
197
196 + IPython.core.interactiveshell.InteractiveShell.get_local_scope(self, stack_depth)
198 + IPython.core.interactiveshell.InteractiveShell.get_local_scope(self, stack_depth)
197
199
198 The following signatures differ since 7.16.0::
200 The following signatures differ since 7.16.0::
199
201
200 - IPython.core.interactiveshell.InteractiveShell.run_cell_async(self, raw_cell, store_history=False, silent=False, shell_futures=True)
202 - IPython.core.interactiveshell.InteractiveShell.run_cell_async(self, raw_cell, store_history=False, silent=False, shell_futures=True)
201 + IPython.core.interactiveshell.InteractiveShell.run_cell_async(self, raw_cell, store_history=False, silent=False, shell_futures=True, *, transformed_cell=None, preprocessing_exc_tuple=None)
203 + IPython.core.interactiveshell.InteractiveShell.run_cell_async(self, raw_cell, store_history=False, silent=False, shell_futures=True, *, transformed_cell=None, preprocessing_exc_tuple=None)
202
204
203 - IPython.core.interactiveshell.InteractiveShell.should_run_async(self, raw_cell)
205 - IPython.core.interactiveshell.InteractiveShell.should_run_async(self, raw_cell)
204 + IPython.core.interactiveshell.InteractiveShell.should_run_async(self, raw_cell, *, transformed_cell=None, preprocessing_exc_tuple=None)
206 + IPython.core.interactiveshell.InteractiveShell.should_run_async(self, raw_cell, *, transformed_cell=None, preprocessing_exc_tuple=None)
205
207
206 - IPython.terminal.debugger.TerminalPdb.pt_init(self)
208 - IPython.terminal.debugger.TerminalPdb.pt_init(self)
207 + IPython.terminal.debugger.TerminalPdb.pt_init(self, pt_session_options=None)
209 + IPython.terminal.debugger.TerminalPdb.pt_init(self, pt_session_options=None)
208
210
209 This method was added::
211 This method was added::
210
212
211 + IPython.core.interactiveshell.InteractiveShell.get_local_scope
213 + IPython.core.interactiveshell.InteractiveShell.get_local_scope
212
214
213 Which is now also present on subclasses::
215 Which is now also present on subclasses::
214
216
215 + IPython.terminal.embed.InteractiveShellEmbed.get_local_scope
217 + IPython.terminal.embed.InteractiveShellEmbed.get_local_scope
216 + IPython.terminal.interactiveshell.TerminalInteractiveShell.get_local_scope
218 + IPython.terminal.interactiveshell.TerminalInteractiveShell.get_local_scope
217
219
218
220
219 .. _version 716:
221 .. _version 716:
220
222
221 IPython 7.16
223 IPython 7.16
222 ============
224 ============
223
225
224
226
225 The default traceback mode will now skip frames that are marked with
227 The default traceback mode will now skip frames that are marked with
226 ``__tracebackhide__ = True`` and show how many traceback frames have been
228 ``__tracebackhide__ = True`` and show how many traceback frames have been
227 skipped. This can be toggled by using :magic:`xmode` with the ``--show`` or
229 skipped. This can be toggled by using :magic:`xmode` with the ``--show`` or
228 ``--hide`` attribute. It will have no effect on non verbose traceback modes.
230 ``--hide`` attribute. It will have no effect on non verbose traceback modes.
229
231
230 The ipython debugger also now understands ``__tracebackhide__`` as well and will
232 The ipython debugger also now understands ``__tracebackhide__`` as well and will
231 skip hidden frames when displaying. Movement up and down the stack will skip the
233 skip hidden frames when displaying. Movement up and down the stack will skip the
232 hidden frames and will show how many frames were hidden. Internal IPython frames
234 hidden frames and will show how many frames were hidden. Internal IPython frames
233 are also now hidden by default. The behavior can be changed with the
235 are also now hidden by default. The behavior can be changed with the
234 ``skip_hidden`` while in the debugger, command and accepts "yes", "no", "true"
236 ``skip_hidden`` while in the debugger, command and accepts "yes", "no", "true"
235 and "false" case insensitive parameters.
237 and "false" case insensitive parameters.
236
238
237
239
238 Misc Noticeable changes:
240 Misc Noticeable changes:
239 ------------------------
241 ------------------------
240
242
241 - Exceptions are now (re)raised when running notebooks via the :magic:`%run`, helping to catch issues in workflows and
243 - Exceptions are now (re)raised when running notebooks via the :magic:`%run`, helping to catch issues in workflows and
242 pipelines. :ghpull:`12301`
244 pipelines. :ghpull:`12301`
243 - Fix inputhook for qt 5.15.0 :ghpull:`12355`
245 - Fix inputhook for qt 5.15.0 :ghpull:`12355`
244 - Fix wx inputhook :ghpull:`12375`
246 - Fix wx inputhook :ghpull:`12375`
245 - Add handling for malformed pathext env var (Windows) :ghpull:`12367`
247 - Add handling for malformed pathext env var (Windows) :ghpull:`12367`
246 - use $SHELL in system_piped :ghpull:`12360` for uniform behavior with
248 - use $SHELL in system_piped :ghpull:`12360` for uniform behavior with
247 ipykernel.
249 ipykernel.
248
250
249 Reproducible Build
251 Reproducible Build
250 ------------------
252 ------------------
251
253
252 IPython 7.15 reproducible build did not work, so we try again this month
254 IPython 7.15 reproducible build did not work, so we try again this month
253 :ghpull:`12358`.
255 :ghpull:`12358`.
254
256
255
257
256 API Changes
258 API Changes
257 -----------
259 -----------
258
260
259 Change of API and exposed objects automatically detected using `frappuccino
261 Change of API and exposed objects automatically detected using `frappuccino
260 <https://pypi.org/project/frappuccino/>`_ (still in beta):
262 <https://pypi.org/project/frappuccino/>`_ (still in beta):
261
263
262
264
263 The following items are new and mostly related to understanding ``__tracebackbhide__``::
265 The following items are new and mostly related to understanding ``__tracebackbhide__``::
264
266
265 + IPython.core.debugger.Pdb.do_down(self, arg)
267 + IPython.core.debugger.Pdb.do_down(self, arg)
266 + IPython.core.debugger.Pdb.do_skip_hidden(self, arg)
268 + IPython.core.debugger.Pdb.do_skip_hidden(self, arg)
267 + IPython.core.debugger.Pdb.do_up(self, arg)
269 + IPython.core.debugger.Pdb.do_up(self, arg)
268 + IPython.core.debugger.Pdb.hidden_frames(self, stack)
270 + IPython.core.debugger.Pdb.hidden_frames(self, stack)
269 + IPython.core.debugger.Pdb.stop_here(self, frame)
271 + IPython.core.debugger.Pdb.stop_here(self, frame)
270
272
271
273
272 The following items have been removed::
274 The following items have been removed::
273
275
274 - IPython.core.debugger.Pdb.new_do_down
276 - IPython.core.debugger.Pdb.new_do_down
275 - IPython.core.debugger.Pdb.new_do_up
277 - IPython.core.debugger.Pdb.new_do_up
276
278
277 Those were implementation details.
279 Those were implementation details.
278
280
279
281
280 .. _version 715:
282 .. _version 715:
281
283
282 IPython 7.15
284 IPython 7.15
283 ============
285 ============
284
286
285 IPython 7.15 brings a number of bug fixes and user facing improvements.
287 IPython 7.15 brings a number of bug fixes and user facing improvements.
286
288
287 Misc Noticeable changes:
289 Misc Noticeable changes:
288 ------------------------
290 ------------------------
289
291
290 - Long completion name have better elision in terminal :ghpull:`12284`
292 - Long completion name have better elision in terminal :ghpull:`12284`
291 - I've started to test on Python 3.9 :ghpull:`12307` and fix some errors.
293 - I've started to test on Python 3.9 :ghpull:`12307` and fix some errors.
292 - Hi DPI scaling of figures when using qt eventloop :ghpull:`12314`
294 - Hi DPI scaling of figures when using qt eventloop :ghpull:`12314`
293 - Document the ability to have systemwide configuration for IPython.
295 - Document the ability to have systemwide configuration for IPython.
294 :ghpull:`12328`
296 :ghpull:`12328`
295 - Fix issues with input autoformatting :ghpull:`12336`
297 - Fix issues with input autoformatting :ghpull:`12336`
296 - ``IPython.core.debugger.Pdb`` is now interruptible (:ghpull:`12168`, in 7.14
298 - ``IPython.core.debugger.Pdb`` is now interruptible (:ghpull:`12168`, in 7.14
297 but forgotten in release notes)
299 but forgotten in release notes)
298 - Video HTML attributes (:ghpull:`12212`, in 7.14 but forgotten in release
300 - Video HTML attributes (:ghpull:`12212`, in 7.14 but forgotten in release
299 notes)
301 notes)
300
302
301 Reproducible Build
303 Reproducible Build
302 ------------------
304 ------------------
303
305
304 Starting with IPython 7.15, I am attempting to provide reproducible builds,
306 Starting with IPython 7.15, I am attempting to provide reproducible builds,
305 that is to say you should be able from the source tree to generate an sdist
307 that is to say you should be able from the source tree to generate an sdist
306 and wheel that are identical byte for byte with the publish version on PyPI.
308 and wheel that are identical byte for byte with the publish version on PyPI.
307
309
308 I've only tested on a couple of machines so far and the process is relatively
310 I've only tested on a couple of machines so far and the process is relatively
309 straightforward, so this mean that IPython not only have a deterministic build
311 straightforward, so this mean that IPython not only have a deterministic build
310 process, but also I have either removed, or put under control all effects of
312 process, but also I have either removed, or put under control all effects of
311 the build environments on the final artifact. I encourage you to attempt the
313 the build environments on the final artifact. I encourage you to attempt the
312 build process on your machine as documented in :ref:`core_developer_guide`
314 build process on your machine as documented in :ref:`core_developer_guide`
313 and let me know if you do not obtain an identical artifact.
315 and let me know if you do not obtain an identical artifact.
314
316
315 While reproducible builds is critical to check that the supply chain of (open
317 While reproducible builds is critical to check that the supply chain of (open
316 source) software has not been compromised, it can also help to speedup many
318 source) software has not been compromised, it can also help to speedup many
317 of the build processes in large environment (conda, apt...) by allowing
319 of the build processes in large environment (conda, apt...) by allowing
318 better caching of intermediate build steps.
320 better caching of intermediate build steps.
319
321
320 Learn more on `<https://reproducible-builds.org/>`_. `Reflections on trusting
322 Learn more on `<https://reproducible-builds.org/>`_. `Reflections on trusting
321 trust <https://dl.acm.org/doi/10.1145/358198.358210>`_ is also one of the
323 trust <https://dl.acm.org/doi/10.1145/358198.358210>`_ is also one of the
322 cornerstone and recommended reads on this subject.
324 cornerstone and recommended reads on this subject.
323
325
324 .. note::
326 .. note::
325
327
326 The build commit from which the sdist is generated is also `signed
328 The build commit from which the sdist is generated is also `signed
327 <https://en.wikipedia.org/wiki/Digital_signature>`_, so you should be able to
329 <https://en.wikipedia.org/wiki/Digital_signature>`_, so you should be able to
328 check it has not been compromised, and the git repository is a `merkle-tree
330 check it has not been compromised, and the git repository is a `merkle-tree
329 <https://en.wikipedia.org/wiki/Merkle_tree>`_, you can check the consistency
331 <https://en.wikipedia.org/wiki/Merkle_tree>`_, you can check the consistency
330 with `git-fsck <https://git-scm.com/docs/git-fsck>`_ which you likely `want
332 with `git-fsck <https://git-scm.com/docs/git-fsck>`_ which you likely `want
331 to enable by default
333 to enable by default
332 <https://gist.github.com/mbbx6spp/14b86437e794bffb4120>`_.
334 <https://gist.github.com/mbbx6spp/14b86437e794bffb4120>`_.
333
335
334 NEP29: Last version to support Python 3.6
336 NEP29: Last version to support Python 3.6
335 -----------------------------------------
337 -----------------------------------------
336
338
337 IPython 7.15 will be the Last IPython version to officially support Python
339 IPython 7.15 will be the Last IPython version to officially support Python
338 3.6, as stated by `NumPy Enhancement Proposal 29
340 3.6, as stated by `NumPy Enhancement Proposal 29
339 <https://numpy.org/neps/nep-0029-deprecation_policy.html>`_. Starting with
341 <https://numpy.org/neps/nep-0029-deprecation_policy.html>`_. Starting with
340 next minor version of IPython I may stop testing on Python 3.6 and may stop
342 next minor version of IPython I may stop testing on Python 3.6 and may stop
341 publishing release artifacts that install on Python 3.6
343 publishing release artifacts that install on Python 3.6
342
344
343 Highlighted features
345 Highlighted features
344 --------------------
346 --------------------
345
347
346 Highlighted features are not new, but seem to not be widely known, this
348 Highlighted features are not new, but seem to not be widely known, this
347 section will help you discover in more narrative form what you can do with
349 section will help you discover in more narrative form what you can do with
348 IPython.
350 IPython.
349
351
350 Increase Tab Completion Menu Height
352 Increase Tab Completion Menu Height
351 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
353 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
352
354
353 In terminal IPython it is possible to increase the hight of the tab-completion
355 In terminal IPython it is possible to increase the hight of the tab-completion
354 menu. To do so set the value of
356 menu. To do so set the value of
355 :configtrait:`TerminalInteractiveShell.space_for_menu`, this will reserve more
357 :configtrait:`TerminalInteractiveShell.space_for_menu`, this will reserve more
356 space at the bottom of the screen for various kind of menus in IPython including
358 space at the bottom of the screen for various kind of menus in IPython including
357 tab completion and searching in history.
359 tab completion and searching in history.
358
360
359 Autoformat Code in the terminal
361 Autoformat Code in the terminal
360 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
362 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
361
363
362 If you have a preferred code formatter, you can configure IPython to
364 If you have a preferred code formatter, you can configure IPython to
363 reformat your code. Set the value of
365 reformat your code. Set the value of
364 :configtrait:`TerminalInteractiveShell.autoformatter` to for example ``'black'``
366 :configtrait:`TerminalInteractiveShell.autoformatter` to for example ``'black'``
365 and IPython will auto format your code when possible.
367 and IPython will auto format your code when possible.
366
368
367
369
368 .. _version 714:
370 .. _version 714:
369
371
370 IPython 7.14
372 IPython 7.14
371 ============
373 ============
372
374
373 IPython 7.14 is a minor release that fix a couple of bugs and prepare
375 IPython 7.14 is a minor release that fix a couple of bugs and prepare
374 compatibility with new or future versions of some libraries.
376 compatibility with new or future versions of some libraries.
375
377
376 Important changes:
378 Important changes:
377 ------------------
379 ------------------
378
380
379 - Fix compatibility with Sphinx 3+ :ghpull:`12235`
381 - Fix compatibility with Sphinx 3+ :ghpull:`12235`
380 - Remove deprecated matplotlib parameter usage, compatibility with matplotlib
382 - Remove deprecated matplotlib parameter usage, compatibility with matplotlib
381 3.3+ :`122250`
383 3.3+ :`122250`
382
384
383 Misc Changes
385 Misc Changes
384 ------------
386 ------------
385
387
386 - set ``.py`` extension when editing current buffer in vi/emacs. :ghpull:`12167`
388 - set ``.py`` extension when editing current buffer in vi/emacs. :ghpull:`12167`
387 - support for unicode identifiers in ``?``/``??`` :ghpull:`12208`
389 - support for unicode identifiers in ``?``/``??`` :ghpull:`12208`
388 - add extra options to the ``Video`` Rich objects :ghpull:`12212`
390 - add extra options to the ``Video`` Rich objects :ghpull:`12212`
389 - add pretty-printing to ``SimpleNamespace`` :ghpull:`12230`
391 - add pretty-printing to ``SimpleNamespace`` :ghpull:`12230`
390
392
391 IPython.core.debugger.Pdb is now interruptible
393 IPython.core.debugger.Pdb is now interruptible
392 ----------------------------------------------
394 ----------------------------------------------
393
395
394 A ``KeyboardInterrupt`` will now interrupt IPython's extended debugger, in order to make Jupyter able to interrupt it. (:ghpull:`12168`)
396 A ``KeyboardInterrupt`` will now interrupt IPython's extended debugger, in order to make Jupyter able to interrupt it. (:ghpull:`12168`)
395
397
396 Video HTML attributes
398 Video HTML attributes
397 ---------------------
399 ---------------------
398
400
399 Add an option to `IPython.display.Video` to change the attributes of the HTML display of the video (:ghpull:`12212`)
401 Add an option to `IPython.display.Video` to change the attributes of the HTML display of the video (:ghpull:`12212`)
400
402
401
403
402 Pending deprecated imports
404 Pending deprecated imports
403 --------------------------
405 --------------------------
404
406
405 Many object present in ``IPython.core.display`` are there for internal use only,
407 Many object present in ``IPython.core.display`` are there for internal use only,
406 and should already been imported from ``IPython.display`` by users and external
408 and should already been imported from ``IPython.display`` by users and external
407 libraries. Trying to import those from ``IPython.core.display`` is still possible
409 libraries. Trying to import those from ``IPython.core.display`` is still possible
408 but will trigger a
410 but will trigger a
409 deprecation warning in later versions of IPython and will become errors in the
411 deprecation warning in later versions of IPython and will become errors in the
410 future.
412 future.
411
413
412 This will simplify compatibility with other Python kernels (like Xeus-Python),
414 This will simplify compatibility with other Python kernels (like Xeus-Python),
413 and simplify code base.
415 and simplify code base.
414
416
415
417
416
418
417
419
418 .. _version 713:
420 .. _version 713:
419
421
420 IPython 7.13
422 IPython 7.13
421 ============
423 ============
422
424
423 IPython 7.13 is the final release of the 7.x branch since master is diverging
425 IPython 7.13 is the final release of the 7.x branch since master is diverging
424 toward an 8.0. Exiting new features have already been merged in 8.0 and will
426 toward an 8.0. Exiting new features have already been merged in 8.0 and will
425 not be available on the 7.x branch. All the changes below have been backported
427 not be available on the 7.x branch. All the changes below have been backported
426 from the master branch.
428 from the master branch.
427
429
428
430
429 - Fix inability to run PDB when inside an event loop :ghpull:`12141`
431 - Fix inability to run PDB when inside an event loop :ghpull:`12141`
430 - Fix ability to interrupt some processes on windows :ghpull:`12137`
432 - Fix ability to interrupt some processes on windows :ghpull:`12137`
431 - Fix debugger shortcuts :ghpull:`12132`
433 - Fix debugger shortcuts :ghpull:`12132`
432 - improve tab completion when inside a string by removing irrelevant elements :ghpull:`12128`
434 - improve tab completion when inside a string by removing irrelevant elements :ghpull:`12128`
433 - Fix display of filename tab completion when the path is long :ghpull:`12122`
435 - Fix display of filename tab completion when the path is long :ghpull:`12122`
434 - Many removal of Python 2 specific code path :ghpull:`12110`
436 - Many removal of Python 2 specific code path :ghpull:`12110`
435 - displaying wav files do not require NumPy anymore, and is 5x to 30x faster :ghpull:`12113`
437 - displaying wav files do not require NumPy anymore, and is 5x to 30x faster :ghpull:`12113`
436
438
437 See the list of all closed issues and pull request on `github
439 See the list of all closed issues and pull request on `github
438 <https://github.com/ipython/ipython/pulls?q=is%3Aclosed+milestone%3A7.13>`_.
440 <https://github.com/ipython/ipython/pulls?q=is%3Aclosed+milestone%3A7.13>`_.
439
441
440 .. _version 712:
442 .. _version 712:
441
443
442 IPython 7.12
444 IPython 7.12
443 ============
445 ============
444
446
445 IPython 7.12 is a minor update that mostly brings code cleanup, removal of
447 IPython 7.12 is a minor update that mostly brings code cleanup, removal of
446 longtime deprecated function and a couple update to documentation cleanup as well.
448 longtime deprecated function and a couple update to documentation cleanup as well.
447
449
448 Notable changes are the following:
450 Notable changes are the following:
449
451
450 - Exit non-zero when ipython is given a file path to run that doesn't exist :ghpull:`12074`
452 - Exit non-zero when ipython is given a file path to run that doesn't exist :ghpull:`12074`
451 - Test PR on ARM64 with Travis-CI :ghpull:`12073`
453 - Test PR on ARM64 with Travis-CI :ghpull:`12073`
452 - Update CI to work with latest Pytest :ghpull:`12086`
454 - Update CI to work with latest Pytest :ghpull:`12086`
453 - Add infrastructure to run ipykernel eventloop via trio :ghpull:`12097`
455 - Add infrastructure to run ipykernel eventloop via trio :ghpull:`12097`
454 - Support git blame ignore revs :ghpull:`12091`
456 - Support git blame ignore revs :ghpull:`12091`
455 - Start multi-line ``__repr__`` s on their own line :ghpull:`12099`
457 - Start multi-line ``__repr__`` s on their own line :ghpull:`12099`
456
458
457 .. _version 7111:
459 .. _version 7111:
458
460
459 IPython 7.11.1
461 IPython 7.11.1
460 ==============
462 ==============
461
463
462 A couple of deprecated functions (no-op) have been reintroduces in py3compat as
464 A couple of deprecated functions (no-op) have been reintroduces in py3compat as
463 Cython was still relying on them, and will be removed in a couple of versions.
465 Cython was still relying on them, and will be removed in a couple of versions.
464
466
465 .. _version 711:
467 .. _version 711:
466
468
467 IPython 7.11
469 IPython 7.11
468 ============
470 ============
469
471
470 IPython 7.11 received a couple of compatibility fixes and code cleanup.
472 IPython 7.11 received a couple of compatibility fixes and code cleanup.
471
473
472 A number of function in the ``py3compat`` have been removed; a number of types
474 A number of function in the ``py3compat`` have been removed; a number of types
473 in the IPython code base are now non-ambiguous and now always ``unicode``
475 in the IPython code base are now non-ambiguous and now always ``unicode``
474 instead of ``Union[Unicode,bytes]``; many of the relevant code path have thus
476 instead of ``Union[Unicode,bytes]``; many of the relevant code path have thus
475 been simplified/cleaned and types annotation added.
477 been simplified/cleaned and types annotation added.
476
478
477 IPython support several verbosity level from exceptions. ``xmode plain`` now
479 IPython support several verbosity level from exceptions. ``xmode plain`` now
478 support chained exceptions. :ghpull:`11999`
480 support chained exceptions. :ghpull:`11999`
479
481
480 We are starting to remove ``shell=True`` in some usages of subprocess. While not directly
482 We are starting to remove ``shell=True`` in some usages of subprocess. While not directly
481 a security issue (as IPython is made to run arbitrary code anyway) it is not good
483 a security issue (as IPython is made to run arbitrary code anyway) it is not good
482 practice and we'd like to show the example. :ghissue:`12023`. This discussion
484 practice and we'd like to show the example. :ghissue:`12023`. This discussion
483 was started by ``@mschwager`` thanks to a new auditing tool they are working on
485 was started by ``@mschwager`` thanks to a new auditing tool they are working on
484 with duo-labs (`dlint <https://github.com/duo-labs/dlint>`_).
486 with duo-labs (`dlint <https://github.com/duo-labs/dlint>`_).
485
487
486 Work around some bugs in Python 3.9 tokenizer :ghpull:`12057`
488 Work around some bugs in Python 3.9 tokenizer :ghpull:`12057`
487
489
488 IPython will now print its version after a crash. :ghpull:`11986`
490 IPython will now print its version after a crash. :ghpull:`11986`
489
491
490 This is likely the last release from the 7.x series that will see new feature.
492 This is likely the last release from the 7.x series that will see new feature.
491 The master branch will soon accept large code changes and thrilling new
493 The master branch will soon accept large code changes and thrilling new
492 features; the 7.x branch will only start to accept critical bug fixes, and
494 features; the 7.x branch will only start to accept critical bug fixes, and
493 update dependencies.
495 update dependencies.
494
496
495 .. _version 7102:
497 .. _version 7102:
496
498
497 IPython 7.10.2
499 IPython 7.10.2
498 ==============
500 ==============
499
501
500 IPython 7.10.2 fix a couple of extra incompatibility between IPython, ipdb,
502 IPython 7.10.2 fix a couple of extra incompatibility between IPython, ipdb,
501 asyncio and Prompt Toolkit 3.
503 asyncio and Prompt Toolkit 3.
502
504
503 .. _version 7101:
505 .. _version 7101:
504
506
505 IPython 7.10.1
507 IPython 7.10.1
506 ==============
508 ==============
507
509
508 IPython 7.10.1 fix a couple of incompatibilities with Prompt toolkit 3 (please
510 IPython 7.10.1 fix a couple of incompatibilities with Prompt toolkit 3 (please
509 update Prompt toolkit to 3.0.2 at least), and fixes some interaction with
511 update Prompt toolkit to 3.0.2 at least), and fixes some interaction with
510 headless IPython.
512 headless IPython.
511
513
512 .. _version 7100:
514 .. _version 7100:
513
515
514 IPython 7.10.0
516 IPython 7.10.0
515 ==============
517 ==============
516
518
517 IPython 7.10 is the first double digit minor release in the last decade, and
519 IPython 7.10 is the first double digit minor release in the last decade, and
518 first since the release of IPython 1.0, previous double digit minor release was
520 first since the release of IPython 1.0, previous double digit minor release was
519 in August 2009.
521 in August 2009.
520
522
521 We've been trying to give you regular release on the last Friday of every month
523 We've been trying to give you regular release on the last Friday of every month
522 for a guaranty of rapid access to bug fixes and new features.
524 for a guaranty of rapid access to bug fixes and new features.
523
525
524 Unlike the previous first few releases that have seen only a couple of code
526 Unlike the previous first few releases that have seen only a couple of code
525 changes, 7.10 bring a number of changes, new features and bugfixes.
527 changes, 7.10 bring a number of changes, new features and bugfixes.
526
528
527 Stop Support for Python 3.5 – Adopt NEP 29
529 Stop Support for Python 3.5 – Adopt NEP 29
528 ------------------------------------------
530 ------------------------------------------
529
531
530 IPython has decided to follow the informational `NEP 29
532 IPython has decided to follow the informational `NEP 29
531 <https://numpy.org/neps/nep-0029-deprecation_policy.html>`_ which layout a clear
533 <https://numpy.org/neps/nep-0029-deprecation_policy.html>`_ which layout a clear
532 policy as to which version of (C)Python and NumPy are supported.
534 policy as to which version of (C)Python and NumPy are supported.
533
535
534 We thus dropped support for Python 3.5, and cleaned up a number of code path
536 We thus dropped support for Python 3.5, and cleaned up a number of code path
535 that were Python-version dependant. If you are on 3.5 or earlier pip should
537 that were Python-version dependant. If you are on 3.5 or earlier pip should
536 automatically give you the latest compatible version of IPython so you do not
538 automatically give you the latest compatible version of IPython so you do not
537 need to pin to a given version.
539 need to pin to a given version.
538
540
539 Support for Prompt Toolkit 3.0
541 Support for Prompt Toolkit 3.0
540 ------------------------------
542 ------------------------------
541
543
542 Prompt Toolkit 3.0 was release a week before IPython 7.10 and introduces a few
544 Prompt Toolkit 3.0 was release a week before IPython 7.10 and introduces a few
543 breaking changes. We believe IPython 7.10 should be compatible with both Prompt
545 breaking changes. We believe IPython 7.10 should be compatible with both Prompt
544 Toolkit 2.x and 3.x, though it has not been extensively tested with 3.x so
546 Toolkit 2.x and 3.x, though it has not been extensively tested with 3.x so
545 please report any issues.
547 please report any issues.
546
548
547
549
548 Prompt Rendering Performance improvements
550 Prompt Rendering Performance improvements
549 -----------------------------------------
551 -----------------------------------------
550
552
551 Pull Request :ghpull:`11933` introduced an optimisation in the prompt rendering
553 Pull Request :ghpull:`11933` introduced an optimisation in the prompt rendering
552 logic that should decrease the resource usage of IPython when using the
554 logic that should decrease the resource usage of IPython when using the
553 _default_ configuration but could potentially introduce a regression of
555 _default_ configuration but could potentially introduce a regression of
554 functionalities if you are using a custom prompt.
556 functionalities if you are using a custom prompt.
555
557
556 We know assume if you haven't changed the default keybindings that the prompt
558 We know assume if you haven't changed the default keybindings that the prompt
557 **will not change** during the duration of your input – which is for example
559 **will not change** during the duration of your input – which is for example
558 not true when using vi insert mode that switches between `[ins]` and `[nor]`
560 not true when using vi insert mode that switches between `[ins]` and `[nor]`
559 for the current mode.
561 for the current mode.
560
562
561 If you are experiencing any issue let us know.
563 If you are experiencing any issue let us know.
562
564
563 Code autoformatting
565 Code autoformatting
564 -------------------
566 -------------------
565
567
566 The IPython terminal can now auto format your code just before entering a new
568 The IPython terminal can now auto format your code just before entering a new
567 line or executing a command. To do so use the
569 line or executing a command. To do so use the
568 ``--TerminalInteractiveShell.autoformatter`` option and set it to ``'black'``;
570 ``--TerminalInteractiveShell.autoformatter`` option and set it to ``'black'``;
569 if black is installed IPython will use black to format your code when possible.
571 if black is installed IPython will use black to format your code when possible.
570
572
571 IPython cannot always properly format your code; in particular it will
573 IPython cannot always properly format your code; in particular it will
572 auto formatting with *black* will only work if:
574 auto formatting with *black* will only work if:
573
575
574 - Your code does not contains magics or special python syntax.
576 - Your code does not contains magics or special python syntax.
575
577
576 - There is no code after your cursor.
578 - There is no code after your cursor.
577
579
578 The Black API is also still in motion; so this may not work with all versions of
580 The Black API is also still in motion; so this may not work with all versions of
579 black.
581 black.
580
582
581 It should be possible to register custom formatter, though the API is till in
583 It should be possible to register custom formatter, though the API is till in
582 flux.
584 flux.
583
585
584 Arbitrary Mimetypes Handing in Terminal (Aka inline images in terminal)
586 Arbitrary Mimetypes Handing in Terminal (Aka inline images in terminal)
585 -----------------------------------------------------------------------
587 -----------------------------------------------------------------------
586
588
587 When using IPython terminal it is now possible to register function to handle
589 When using IPython terminal it is now possible to register function to handle
588 arbitrary mimetypes. While rendering non-text based representation was possible in
590 arbitrary mimetypes. While rendering non-text based representation was possible in
589 many jupyter frontend; it was not possible in terminal IPython, as usually
591 many jupyter frontend; it was not possible in terminal IPython, as usually
590 terminal are limited to displaying text. As many terminal these days provide
592 terminal are limited to displaying text. As many terminal these days provide
591 escape sequences to display non-text; bringing this loved feature to IPython CLI
593 escape sequences to display non-text; bringing this loved feature to IPython CLI
592 made a lot of sens. This functionality will not only allow inline images; but
594 made a lot of sens. This functionality will not only allow inline images; but
593 allow opening of external program; for example ``mplayer`` to "display" sound
595 allow opening of external program; for example ``mplayer`` to "display" sound
594 files.
596 files.
595
597
596 So far only the hooks necessary for this are in place, but no default mime
598 So far only the hooks necessary for this are in place, but no default mime
597 renderers added; so inline images will only be available via extensions. We will
599 renderers added; so inline images will only be available via extensions. We will
598 progressively enable these features by default in the next few releases, and
600 progressively enable these features by default in the next few releases, and
599 contribution is welcomed.
601 contribution is welcomed.
600
602
601 We welcome any feedback on the API. See :ref:`shell_mimerenderer` for more
603 We welcome any feedback on the API. See :ref:`shell_mimerenderer` for more
602 informations.
604 informations.
603
605
604 This is originally based on work form in :ghpull:`10610` from @stephanh42
606 This is originally based on work form in :ghpull:`10610` from @stephanh42
605 started over two years ago, and still a lot need to be done.
607 started over two years ago, and still a lot need to be done.
606
608
607 MISC
609 MISC
608 ----
610 ----
609
611
610 - Completions can define their own ordering :ghpull:`11855`
612 - Completions can define their own ordering :ghpull:`11855`
611 - Enable Plotting in the same cell than the one that import matplotlib
613 - Enable Plotting in the same cell than the one that import matplotlib
612 :ghpull:`11916`
614 :ghpull:`11916`
613 - Allow to store and restore multiple variables at once :ghpull:`11930`
615 - Allow to store and restore multiple variables at once :ghpull:`11930`
614
616
615 You can see `all pull-requests <https://github.com/ipython/ipython/pulls?q=is%3Apr+milestone%3A7.10+is%3Aclosed>`_ for this release.
617 You can see `all pull-requests <https://github.com/ipython/ipython/pulls?q=is%3Apr+milestone%3A7.10+is%3Aclosed>`_ for this release.
616
618
617 API Changes
619 API Changes
618 -----------
620 -----------
619
621
620 Change of API and exposed objects automatically detected using `frappuccino <https://pypi.org/project/frappuccino/>`_ (still in beta):
622 Change of API and exposed objects automatically detected using `frappuccino <https://pypi.org/project/frappuccino/>`_ (still in beta):
621
623
622 The following items are new in IPython 7.10::
624 The following items are new in IPython 7.10::
623
625
624 + IPython.terminal.shortcuts.reformat_text_before_cursor(buffer, document, shell)
626 + IPython.terminal.shortcuts.reformat_text_before_cursor(buffer, document, shell)
625 + IPython.terminal.interactiveshell.PTK3
627 + IPython.terminal.interactiveshell.PTK3
626 + IPython.terminal.interactiveshell.black_reformat_handler(text_before_cursor)
628 + IPython.terminal.interactiveshell.black_reformat_handler(text_before_cursor)
627 + IPython.terminal.prompts.RichPromptDisplayHook.write_format_data(self, format_dict, md_dict='None')
629 + IPython.terminal.prompts.RichPromptDisplayHook.write_format_data(self, format_dict, md_dict='None')
628
630
629 The following items have been removed in 7.10::
631 The following items have been removed in 7.10::
630
632
631 - IPython.lib.pretty.DICT_IS_ORDERED
633 - IPython.lib.pretty.DICT_IS_ORDERED
632
634
633 The following signatures differ between versions::
635 The following signatures differ between versions::
634
636
635 - IPython.extensions.storemagic.restore_aliases(ip)
637 - IPython.extensions.storemagic.restore_aliases(ip)
636 + IPython.extensions.storemagic.restore_aliases(ip, alias='None')
638 + IPython.extensions.storemagic.restore_aliases(ip, alias='None')
637
639
638 Special Thanks
640 Special Thanks
639 --------------
641 --------------
640
642
641 - @stephanh42 who started the work on inline images in terminal 2 years ago
643 - @stephanh42 who started the work on inline images in terminal 2 years ago
642 - @augustogoulart who spent a lot of time triaging issues and responding to
644 - @augustogoulart who spent a lot of time triaging issues and responding to
643 users.
645 users.
644 - @con-f-use who is my (@Carreau) first sponsor on GitHub, as a reminder if you
646 - @con-f-use who is my (@Carreau) first sponsor on GitHub, as a reminder if you
645 like IPython, Jupyter and many other library of the SciPy stack you can
647 like IPython, Jupyter and many other library of the SciPy stack you can
646 donate to numfocus.org non profit
648 donate to numfocus.org non profit
647
649
648 .. _version 790:
650 .. _version 790:
649
651
650 IPython 7.9.0
652 IPython 7.9.0
651 =============
653 =============
652
654
653 IPython 7.9 is a small release with a couple of improvement and bug fixes.
655 IPython 7.9 is a small release with a couple of improvement and bug fixes.
654
656
655 - Xterm terminal title should be restored on exit :ghpull:`11910`
657 - Xterm terminal title should be restored on exit :ghpull:`11910`
656 - special variables ``_``,``__``, ``___`` are not set anymore when cache size
658 - special variables ``_``,``__``, ``___`` are not set anymore when cache size
657 is 0 or less. :ghpull:`11877`
659 is 0 or less. :ghpull:`11877`
658 - Autoreload should have regained some speed by using a new heuristic logic to
660 - Autoreload should have regained some speed by using a new heuristic logic to
659 find all objects needing reload. This should avoid large objects traversal
661 find all objects needing reload. This should avoid large objects traversal
660 like pandas dataframes. :ghpull:`11876`
662 like pandas dataframes. :ghpull:`11876`
661 - Get ready for Python 4. :ghpull:`11874`
663 - Get ready for Python 4. :ghpull:`11874`
662 - `%env` Magic now has heuristic to hide potentially sensitive values :ghpull:`11896`
664 - `%env` Magic now has heuristic to hide potentially sensitive values :ghpull:`11896`
663
665
664 This is a small release despite a number of Pull Request Pending that need to
666 This is a small release despite a number of Pull Request Pending that need to
665 be reviewed/worked on. Many of the core developers have been busy outside of
667 be reviewed/worked on. Many of the core developers have been busy outside of
666 IPython/Jupyter and we thanks all contributor for their patience; we'll work on
668 IPython/Jupyter and we thanks all contributor for their patience; we'll work on
667 these as soon as we have time.
669 these as soon as we have time.
668
670
669
671
670 .. _version780:
672 .. _version780:
671
673
672 IPython 7.8.0
674 IPython 7.8.0
673 =============
675 =============
674
676
675 IPython 7.8.0 contain a few bugfix and 2 new APIs:
677 IPython 7.8.0 contain a few bugfix and 2 new APIs:
676
678
677 - Enable changing the font color for LaTeX rendering :ghpull:`11840`
679 - Enable changing the font color for LaTeX rendering :ghpull:`11840`
678 - and Re-Expose some PDB API (see below)
680 - and Re-Expose some PDB API (see below)
679
681
680 Expose Pdb API
682 Expose Pdb API
681 --------------
683 --------------
682
684
683 Expose the built-in ``pdb.Pdb`` API. ``Pdb`` constructor arguments are generically
685 Expose the built-in ``pdb.Pdb`` API. ``Pdb`` constructor arguments are generically
684 exposed, regardless of python version.
686 exposed, regardless of python version.
685 Newly exposed arguments:
687 Newly exposed arguments:
686
688
687 - ``skip`` - Python 3.1+
689 - ``skip`` - Python 3.1+
688 - ``nosiginnt`` - Python 3.2+
690 - ``nosiginnt`` - Python 3.2+
689 - ``readrc`` - Python 3.6+
691 - ``readrc`` - Python 3.6+
690
692
691 Try it out::
693 Try it out::
692
694
693 from IPython.terminal.debugger import TerminalPdb
695 from IPython.terminal.debugger import TerminalPdb
694 pdb = TerminalPdb(skip=["skipthismodule"])
696 pdb = TerminalPdb(skip=["skipthismodule"])
695
697
696
698
697 See :ghpull:`11840`
699 See :ghpull:`11840`
698
700
699 .. _version770:
701 .. _version770:
700
702
701 IPython 7.7.0
703 IPython 7.7.0
702 =============
704 =============
703
705
704 IPython 7.7.0 contain multiple bug fixes and documentation updates; Here are a
706 IPython 7.7.0 contain multiple bug fixes and documentation updates; Here are a
705 few of the outstanding issue fixed:
707 few of the outstanding issue fixed:
706
708
707 - Fix a bug introduced in 7.6 where the ``%matplotlib`` magic would fail on
709 - Fix a bug introduced in 7.6 where the ``%matplotlib`` magic would fail on
708 previously acceptable arguments :ghpull:`11814`.
710 previously acceptable arguments :ghpull:`11814`.
709 - Fix the manage location on freebsd :ghpull:`11808`.
711 - Fix the manage location on freebsd :ghpull:`11808`.
710 - Fix error message about aliases after ``%reset`` call in ipykernel
712 - Fix error message about aliases after ``%reset`` call in ipykernel
711 :ghpull:`11806`
713 :ghpull:`11806`
712 - Fix Duplication completions in emacs :ghpull:`11803`
714 - Fix Duplication completions in emacs :ghpull:`11803`
713
715
714 We are planning to adopt `NEP29 <https://github.com/numpy/numpy/pull/14086>`_
716 We are planning to adopt `NEP29 <https://github.com/numpy/numpy/pull/14086>`_
715 (still currently in draft) which may make this minor version of IPython the
717 (still currently in draft) which may make this minor version of IPython the
716 last one to support Python 3.5 and will make the code base more aggressive
718 last one to support Python 3.5 and will make the code base more aggressive
717 toward removing compatibility with older versions of Python.
719 toward removing compatibility with older versions of Python.
718
720
719 GitHub now support to give only "Triage" permissions to users; if you'd like to
721 GitHub now support to give only "Triage" permissions to users; if you'd like to
720 help close stale issues and labels issues please reach to us with your GitHub
722 help close stale issues and labels issues please reach to us with your GitHub
721 Username and we'll add you to the triage team. It is a great way to start
723 Username and we'll add you to the triage team. It is a great way to start
722 contributing and a path toward getting commit rights.
724 contributing and a path toward getting commit rights.
723
725
724 .. _version761:
726 .. _version761:
725
727
726 IPython 7.6.1
728 IPython 7.6.1
727 =============
729 =============
728
730
729 IPython 7.6.1 contain a critical bugfix in the ``%timeit`` magic, which would
731 IPython 7.6.1 contain a critical bugfix in the ``%timeit`` magic, which would
730 crash on some inputs as a side effect of :ghpull:`11716`. See :ghpull:`11812`
732 crash on some inputs as a side effect of :ghpull:`11716`. See :ghpull:`11812`
731
733
732
734
733 .. _whatsnew760:
735 .. _whatsnew760:
734
736
735 IPython 7.6.0
737 IPython 7.6.0
736 =============
738 =============
737
739
738 IPython 7.6.0 contains a couple of bug fixes and number of small features
740 IPython 7.6.0 contains a couple of bug fixes and number of small features
739 additions as well as some compatibility with the current development version of
741 additions as well as some compatibility with the current development version of
740 Python 3.8.
742 Python 3.8.
741
743
742 - Add a ``-l`` option to :magic:`psearch` to list the available search
744 - Add a ``-l`` option to :magic:`psearch` to list the available search
743 types. :ghpull:`11672`
745 types. :ghpull:`11672`
744 - Support ``PathLike`` for ``DisplayObject`` and ``Image``. :ghpull:`11764`
746 - Support ``PathLike`` for ``DisplayObject`` and ``Image``. :ghpull:`11764`
745 - Configurability of timeout in the test suite for slow platforms.
747 - Configurability of timeout in the test suite for slow platforms.
746 :ghpull:`11756`
748 :ghpull:`11756`
747 - Accept any casing for matplotlib backend. :ghpull:`121748`
749 - Accept any casing for matplotlib backend. :ghpull:`121748`
748 - Properly skip test that requires numpy to be installed :ghpull:`11723`
750 - Properly skip test that requires numpy to be installed :ghpull:`11723`
749 - More support for Python 3.8 and positional only arguments (pep570)
751 - More support for Python 3.8 and positional only arguments (pep570)
750 :ghpull:`11720`
752 :ghpull:`11720`
751 - Unicode names for the completion are loaded lazily on first use which
753 - Unicode names for the completion are loaded lazily on first use which
752 should decrease startup time. :ghpull:`11693`
754 should decrease startup time. :ghpull:`11693`
753 - Autoreload now update the types of reloaded objects; this for example allow
755 - Autoreload now update the types of reloaded objects; this for example allow
754 pickling of reloaded objects. :ghpull:`11644`
756 pickling of reloaded objects. :ghpull:`11644`
755 - Fix a bug where ``%%time`` magic would suppress cell output. :ghpull:`11716`
757 - Fix a bug where ``%%time`` magic would suppress cell output. :ghpull:`11716`
756
758
757
759
758 Prepare migration to pytest (instead of nose) for testing
760 Prepare migration to pytest (instead of nose) for testing
759 ---------------------------------------------------------
761 ---------------------------------------------------------
760
762
761 Most of the work between 7.5 and 7.6 was to prepare the migration from our
763 Most of the work between 7.5 and 7.6 was to prepare the migration from our
762 testing framework to pytest. Most of the test suite should now work by simply
764 testing framework to pytest. Most of the test suite should now work by simply
763 issuing ``pytest`` from the root of the repository.
765 issuing ``pytest`` from the root of the repository.
764
766
765 The migration to pytest is just at its beginning. Many of our test still rely
767 The migration to pytest is just at its beginning. Many of our test still rely
766 on IPython-specific plugins for nose using pytest (doctest using IPython syntax
768 on IPython-specific plugins for nose using pytest (doctest using IPython syntax
767 is one example of this where test appear as "passing", while no code has been
769 is one example of this where test appear as "passing", while no code has been
768 ran). Many test also need to be updated like ``yield-test`` to be properly
770 ran). Many test also need to be updated like ``yield-test`` to be properly
769 parametrized tests.
771 parametrized tests.
770
772
771 Migration to pytest allowed me to discover a number of issues in our test
773 Migration to pytest allowed me to discover a number of issues in our test
772 suite; which was hiding a number of subtle issues – or not actually running
774 suite; which was hiding a number of subtle issues – or not actually running
773 some of the tests in our test suite – I have thus corrected many of those; like
775 some of the tests in our test suite – I have thus corrected many of those; like
774 improperly closed resources; or used of deprecated features. I also made use of
776 improperly closed resources; or used of deprecated features. I also made use of
775 the ``pytest --durations=...`` to find some of our slowest test and speed them
777 the ``pytest --durations=...`` to find some of our slowest test and speed them
776 up (our test suite can now be up to 10% faster). Pytest as also a variety of
778 up (our test suite can now be up to 10% faster). Pytest as also a variety of
777 plugins and flags which will make the code quality of IPython and the testing
779 plugins and flags which will make the code quality of IPython and the testing
778 experience better.
780 experience better.
779
781
780 Misc
782 Misc
781 ----
783 ----
782
784
783 We skipped the release of 7.6 at the end of May, but will attempt to get back
785 We skipped the release of 7.6 at the end of May, but will attempt to get back
784 on schedule. We are starting to think about making introducing backward
786 on schedule. We are starting to think about making introducing backward
785 incompatible change and start the 8.0 series.
787 incompatible change and start the 8.0 series.
786
788
787 Special Thanks to Gabriel (@gpotter2 on GitHub), who among other took care many
789 Special Thanks to Gabriel (@gpotter2 on GitHub), who among other took care many
788 of the remaining task for 7.4 and 7.5, like updating the website.
790 of the remaining task for 7.4 and 7.5, like updating the website.
789
791
790 .. _whatsnew750:
792 .. _whatsnew750:
791
793
792 IPython 7.5.0
794 IPython 7.5.0
793 =============
795 =============
794
796
795 IPython 7.5.0 consist mostly of bug-fixes, and documentation updates, with one
797 IPython 7.5.0 consist mostly of bug-fixes, and documentation updates, with one
796 minor new feature. The `Audio` display element can now be assigned an element
798 minor new feature. The `Audio` display element can now be assigned an element
797 id when displayed in browser. See :ghpull:`11670`
799 id when displayed in browser. See :ghpull:`11670`
798
800
799 The major outstanding bug fix correct a change of behavior that was introduce
801 The major outstanding bug fix correct a change of behavior that was introduce
800 in 7.4.0 where some cell magics would not be able to access or modify global
802 in 7.4.0 where some cell magics would not be able to access or modify global
801 scope when using the ``@needs_local_scope`` decorator. This was typically
803 scope when using the ``@needs_local_scope`` decorator. This was typically
802 encountered with the ``%%time`` and ``%%timeit`` magics. See :ghissue:`11659`
804 encountered with the ``%%time`` and ``%%timeit`` magics. See :ghissue:`11659`
803 and :ghpull:`11698`.
805 and :ghpull:`11698`.
804
806
805 .. _whatsnew740:
807 .. _whatsnew740:
806
808
807 IPython 7.4.0
809 IPython 7.4.0
808 =============
810 =============
809
811
810 Unicode name completions
812 Unicode name completions
811 ------------------------
813 ------------------------
812
814
813 Previously, we provided completion for a unicode name with its relative symbol.
815 Previously, we provided completion for a unicode name with its relative symbol.
814 With this, now IPython provides complete suggestions to unicode name symbols.
816 With this, now IPython provides complete suggestions to unicode name symbols.
815
817
816 As on the PR, if user types ``\LAT<tab>``, IPython provides a list of
818 As on the PR, if user types ``\LAT<tab>``, IPython provides a list of
817 possible completions. In this case, it would be something like::
819 possible completions. In this case, it would be something like::
818
820
819 'LATIN CAPITAL LETTER A',
821 'LATIN CAPITAL LETTER A',
820 'LATIN CAPITAL LETTER B',
822 'LATIN CAPITAL LETTER B',
821 'LATIN CAPITAL LETTER C',
823 'LATIN CAPITAL LETTER C',
822 'LATIN CAPITAL LETTER D',
824 'LATIN CAPITAL LETTER D',
823 ....
825 ....
824
826
825 This help to type unicode character that do not have short latex aliases, and
827 This help to type unicode character that do not have short latex aliases, and
826 have long unicode names. for example ``Ν°``, ``\GREEK CAPITAL LETTER HETA``.
828 have long unicode names. for example ``Ν°``, ``\GREEK CAPITAL LETTER HETA``.
827
829
828 This feature was contributed by Luciana Marques :ghpull:`11583`.
830 This feature was contributed by Luciana Marques :ghpull:`11583`.
829
831
830 Make audio normalization optional
832 Make audio normalization optional
831 ---------------------------------
833 ---------------------------------
832
834
833 Added 'normalize' argument to `IPython.display.Audio`. This argument applies
835 Added 'normalize' argument to `IPython.display.Audio`. This argument applies
834 when audio data is given as an array of samples. The default of `normalize=True`
836 when audio data is given as an array of samples. The default of `normalize=True`
835 preserves prior behavior of normalizing the audio to the maximum possible range.
837 preserves prior behavior of normalizing the audio to the maximum possible range.
836 Setting to `False` disables normalization.
838 Setting to `False` disables normalization.
837
839
838
840
839 Miscellaneous
841 Miscellaneous
840 -------------
842 -------------
841
843
842 - Fix improper acceptation of ``return`` outside of functions. :ghpull:`11641`.
844 - Fix improper acceptation of ``return`` outside of functions. :ghpull:`11641`.
843 - Fixed PyQt 5.11 backwards incompatibility causing sip import failure.
845 - Fixed PyQt 5.11 backwards incompatibility causing sip import failure.
844 :ghpull:`11613`.
846 :ghpull:`11613`.
845 - Fix Bug where ``type?`` would crash IPython. :ghpull:`1608`.
847 - Fix Bug where ``type?`` would crash IPython. :ghpull:`1608`.
846 - Allow to apply ``@needs_local_scope`` to cell magics for convenience.
848 - Allow to apply ``@needs_local_scope`` to cell magics for convenience.
847 :ghpull:`11542`.
849 :ghpull:`11542`.
848
850
849 .. _whatsnew730:
851 .. _whatsnew730:
850
852
851 IPython 7.3.0
853 IPython 7.3.0
852 =============
854 =============
853
855
854 .. _whatsnew720:
856 .. _whatsnew720:
855
857
856 IPython 7.3.0 bring several bug fixes and small improvements that you will
858 IPython 7.3.0 bring several bug fixes and small improvements that you will
857 described bellow.
859 described bellow.
858
860
859 The biggest change to this release is the implementation of the ``%conda`` and
861 The biggest change to this release is the implementation of the ``%conda`` and
860 ``%pip`` magics, that will attempt to install packages in the **current
862 ``%pip`` magics, that will attempt to install packages in the **current
861 environment**. You may still need to restart your interpreter or kernel for the
863 environment**. You may still need to restart your interpreter or kernel for the
862 change to be taken into account, but it should simplify installation of packages
864 change to be taken into account, but it should simplify installation of packages
863 into remote environment. Installing using pip/conda from the command line is
865 into remote environment. Installing using pip/conda from the command line is
864 still the prefer method.
866 still the prefer method.
865
867
866 The ``%pip`` magic was already present, but was only printing a warning; now it
868 The ``%pip`` magic was already present, but was only printing a warning; now it
867 will actually forward commands to pip.
869 will actually forward commands to pip.
868
870
869 Misc bug fixes and improvements:
871 Misc bug fixes and improvements:
870
872
871 - Compatibility with Python 3.8.
873 - Compatibility with Python 3.8.
872 - Do not expand shell variable in execution magics, and added the
874 - Do not expand shell variable in execution magics, and added the
873 ``no_var_expand`` decorator for magic requiring a similar functionality
875 ``no_var_expand`` decorator for magic requiring a similar functionality
874 :ghpull:`11516`
876 :ghpull:`11516`
875 - Add ``%pip`` and ``%conda`` magic :ghpull:`11524`
877 - Add ``%pip`` and ``%conda`` magic :ghpull:`11524`
876 - Re-initialize posix aliases after a ``%reset`` :ghpull:`11528`
878 - Re-initialize posix aliases after a ``%reset`` :ghpull:`11528`
877 - Allow the IPython command line to run ``*.ipynb`` files :ghpull:`11529`
879 - Allow the IPython command line to run ``*.ipynb`` files :ghpull:`11529`
878
880
879 IPython 7.2.0
881 IPython 7.2.0
880 =============
882 =============
881
883
882 IPython 7.2.0 brings minor bugfixes, improvements, and new configuration options:
884 IPython 7.2.0 brings minor bugfixes, improvements, and new configuration options:
883
885
884 - Fix a bug preventing PySide2 GUI integration from working :ghpull:`11464`
886 - Fix a bug preventing PySide2 GUI integration from working :ghpull:`11464`
885 - Run CI on Mac OS ! :ghpull:`11471`
887 - Run CI on Mac OS ! :ghpull:`11471`
886 - Fix IPython "Demo" mode. :ghpull:`11498`
888 - Fix IPython "Demo" mode. :ghpull:`11498`
887 - Fix ``%run`` magic with path in name :ghpull:`11499`
889 - Fix ``%run`` magic with path in name :ghpull:`11499`
888 - Fix: add CWD to sys.path *after* stdlib :ghpull:`11502`
890 - Fix: add CWD to sys.path *after* stdlib :ghpull:`11502`
889 - Better rendering of signatures, especially long ones. :ghpull:`11505`
891 - Better rendering of signatures, especially long ones. :ghpull:`11505`
890 - Re-enable jedi by default if it's installed :ghpull:`11506`
892 - Re-enable jedi by default if it's installed :ghpull:`11506`
891 - Add New ``minimal`` exception reporting mode (useful for educational purpose). See :ghpull:`11509`
893 - Add New ``minimal`` exception reporting mode (useful for educational purpose). See :ghpull:`11509`
892
894
893
895
894 Added ability to show subclasses when using pinfo and other utilities
896 Added ability to show subclasses when using pinfo and other utilities
895 ---------------------------------------------------------------------
897 ---------------------------------------------------------------------
896
898
897 When using ``?``/``??`` on a class, IPython will now list the first 10 subclasses.
899 When using ``?``/``??`` on a class, IPython will now list the first 10 subclasses.
898
900
899 Special Thanks to Chris Mentzel of the Moore Foundation for this feature. Chris
901 Special Thanks to Chris Mentzel of the Moore Foundation for this feature. Chris
900 is one of the people who played a critical role in IPython/Jupyter getting
902 is one of the people who played a critical role in IPython/Jupyter getting
901 funding.
903 funding.
902
904
903 We are grateful for all the help Chris has given us over the years,
905 We are grateful for all the help Chris has given us over the years,
904 and we're now proud to have code contributed by Chris in IPython.
906 and we're now proud to have code contributed by Chris in IPython.
905
907
906 OSMagics.cd_force_quiet configuration option
908 OSMagics.cd_force_quiet configuration option
907 --------------------------------------------
909 --------------------------------------------
908
910
909 You can set this option to force the %cd magic to behave as if ``-q`` was passed:
911 You can set this option to force the %cd magic to behave as if ``-q`` was passed:
910 ::
912 ::
911
913
912 In [1]: cd /
914 In [1]: cd /
913 /
915 /
914
916
915 In [2]: %config OSMagics.cd_force_quiet = True
917 In [2]: %config OSMagics.cd_force_quiet = True
916
918
917 In [3]: cd /tmp
919 In [3]: cd /tmp
918
920
919 In [4]:
921 In [4]:
920
922
921 See :ghpull:`11491`
923 See :ghpull:`11491`
922
924
923 In vi editing mode, whether the prompt includes the current vi mode can now be configured
925 In vi editing mode, whether the prompt includes the current vi mode can now be configured
924 -----------------------------------------------------------------------------------------
926 -----------------------------------------------------------------------------------------
925
927
926 Set the ``TerminalInteractiveShell.prompt_includes_vi_mode`` to a boolean value
928 Set the ``TerminalInteractiveShell.prompt_includes_vi_mode`` to a boolean value
927 (default: True) to control this feature. See :ghpull:`11492`
929 (default: True) to control this feature. See :ghpull:`11492`
928
930
929 .. _whatsnew710:
931 .. _whatsnew710:
930
932
931 IPython 7.1.0
933 IPython 7.1.0
932 =============
934 =============
933
935
934 IPython 7.1.0 is the first minor release after 7.0.0 and mostly brings fixes to
936 IPython 7.1.0 is the first minor release after 7.0.0 and mostly brings fixes to
935 new features, internal refactoring, and fixes for regressions that happened during the 6.x->7.x
937 new features, internal refactoring, and fixes for regressions that happened during the 6.x->7.x
936 transition. It also brings **Compatibility with Python 3.7.1**, as we're
938 transition. It also brings **Compatibility with Python 3.7.1**, as we're
937 unwillingly relying on a bug in CPython.
939 unwillingly relying on a bug in CPython.
938
940
939 New Core Dev:
941 New Core Dev:
940
942
941 - We welcome Jonathan Slenders to the commiters. Jonathan has done a fantastic
943 - We welcome Jonathan Slenders to the commiters. Jonathan has done a fantastic
942 work on prompt_toolkit, and we'd like to recognise his impact by giving him
944 work on prompt_toolkit, and we'd like to recognise his impact by giving him
943 commit rights. :ghissue:`11397`
945 commit rights. :ghissue:`11397`
944
946
945 Notable Changes
947 Notable Changes
946
948
947 - Major update of "latex to unicode" tab completion map (see below)
949 - Major update of "latex to unicode" tab completion map (see below)
948
950
949 Notable New Features:
951 Notable New Features:
950
952
951 - Restore functionality and documentation of the **sphinx directive**, which
953 - Restore functionality and documentation of the **sphinx directive**, which
952 is now stricter (fail on error by daefault), has new configuration options,
954 is now stricter (fail on error by daefault), has new configuration options,
953 has a brand new documentation page :ref:`ipython_directive` (which needs
955 has a brand new documentation page :ref:`ipython_directive` (which needs
954 some cleanup). It is also now *tested* so we hope to have less regressions.
956 some cleanup). It is also now *tested* so we hope to have less regressions.
955 :ghpull:`11402`
957 :ghpull:`11402`
956
958
957 - ``IPython.display.Video`` now supports ``width`` and ``height`` arguments,
959 - ``IPython.display.Video`` now supports ``width`` and ``height`` arguments,
958 allowing a custom width and height to be set instead of using the video's
960 allowing a custom width and height to be set instead of using the video's
959 width and height. :ghpull:`11353`
961 width and height. :ghpull:`11353`
960
962
961 - Warn when using ``HTML('<iframe>')`` instead of ``IFrame`` :ghpull:`11350`
963 - Warn when using ``HTML('<iframe>')`` instead of ``IFrame`` :ghpull:`11350`
962
964
963 - Allow Dynamic switching of editing mode between vi/emacs and show
965 - Allow Dynamic switching of editing mode between vi/emacs and show
964 normal/input mode in prompt when using vi. :ghpull:`11390`. Use ``%config
966 normal/input mode in prompt when using vi. :ghpull:`11390`. Use ``%config
965 TerminalInteractiveShell.editing_mode = 'vi'`` or ``%config
967 TerminalInteractiveShell.editing_mode = 'vi'`` or ``%config
966 TerminalInteractiveShell.editing_mode = 'emacs'`` to dynamically switch
968 TerminalInteractiveShell.editing_mode = 'emacs'`` to dynamically switch
967 between modes.
969 between modes.
968
970
969
971
970 Notable Fixes:
972 Notable Fixes:
971
973
972 - Fix entering of **multi-line blocks in terminal** IPython, and various
974 - Fix entering of **multi-line blocks in terminal** IPython, and various
973 crashes in the new input transformation machinery :ghpull:`11354`,
975 crashes in the new input transformation machinery :ghpull:`11354`,
974 :ghpull:`11356`, :ghpull:`11358`. These also fix a **Compatibility bug
976 :ghpull:`11356`, :ghpull:`11358`. These also fix a **Compatibility bug
975 with Python 3.7.1**.
977 with Python 3.7.1**.
976
978
977 - Fix moving through generator stack in ipdb :ghpull:`11266`
979 - Fix moving through generator stack in ipdb :ghpull:`11266`
978
980
979 - %Magic command arguments now support quoting. :ghpull:`11330`
981 - %Magic command arguments now support quoting. :ghpull:`11330`
980
982
981 - Re-add ``rprint`` and ``rprinte`` aliases. :ghpull:`11331`
983 - Re-add ``rprint`` and ``rprinte`` aliases. :ghpull:`11331`
982
984
983 - Remove implicit dependency on ``ipython_genutils`` :ghpull:`11317`
985 - Remove implicit dependency on ``ipython_genutils`` :ghpull:`11317`
984
986
985 - Make ``nonlocal`` raise ``SyntaxError`` instead of silently failing in async
987 - Make ``nonlocal`` raise ``SyntaxError`` instead of silently failing in async
986 mode. :ghpull:`11382`
988 mode. :ghpull:`11382`
987
989
988 - Fix mishandling of magics and ``= !`` assignment just after a dedent in
990 - Fix mishandling of magics and ``= !`` assignment just after a dedent in
989 nested code blocks :ghpull:`11418`
991 nested code blocks :ghpull:`11418`
990
992
991 - Fix instructions for custom shortcuts :ghpull:`11426`
993 - Fix instructions for custom shortcuts :ghpull:`11426`
992
994
993
995
994 Notable Internals improvements:
996 Notable Internals improvements:
995
997
996 - Use of ``os.scandir`` (Python 3 only) to speed up some file system operations.
998 - Use of ``os.scandir`` (Python 3 only) to speed up some file system operations.
997 :ghpull:`11365`
999 :ghpull:`11365`
998
1000
999 - use ``perf_counter`` instead of ``clock`` for more precise
1001 - use ``perf_counter`` instead of ``clock`` for more precise
1000 timing results with ``%time`` :ghpull:`11376`
1002 timing results with ``%time`` :ghpull:`11376`
1001
1003
1002 Many thanks to all the contributors and in particular to ``bartskowron`` and
1004 Many thanks to all the contributors and in particular to ``bartskowron`` and
1003 ``tonyfast`` who handled some pretty complicated bugs in the input machinery. We
1005 ``tonyfast`` who handled some pretty complicated bugs in the input machinery. We
1004 had a number of first time contributors and maybe hacktoberfest participants that
1006 had a number of first time contributors and maybe hacktoberfest participants that
1005 made significant contributions and helped us free some time to focus on more
1007 made significant contributions and helped us free some time to focus on more
1006 complicated bugs.
1008 complicated bugs.
1007
1009
1008 You
1010 You
1009 can see all the closed issues and Merged PR, new features and fixes `here
1011 can see all the closed issues and Merged PR, new features and fixes `here
1010 <https://github.com/ipython/ipython/issues?utf8=%E2%9C%93&q=+is%3Aclosed+milestone%3A7.1+>`_.
1012 <https://github.com/ipython/ipython/issues?utf8=%E2%9C%93&q=+is%3Aclosed+milestone%3A7.1+>`_.
1011
1013
1012 Unicode Completion update
1014 Unicode Completion update
1013 -------------------------
1015 -------------------------
1014
1016
1015 In IPython 7.1 the Unicode completion map has been updated and synchronized with
1017 In IPython 7.1 the Unicode completion map has been updated and synchronized with
1016 the Julia language.
1018 the Julia language.
1017
1019
1018 Added and removed character characters:
1020 Added and removed character characters:
1019
1021
1020 ``\jmath`` (``Θ·``), ``\\underleftrightarrow`` (U+034D, combining) have been
1022 ``\jmath`` (``Θ·``), ``\\underleftrightarrow`` (U+034D, combining) have been
1021 added, while ``\\textasciicaron`` have been removed
1023 added, while ``\\textasciicaron`` have been removed
1022
1024
1023 Some sequences have seen their prefix removed:
1025 Some sequences have seen their prefix removed:
1024
1026
1025 - 6 characters ``\text...<tab>`` should now be inputed with ``\...<tab>`` directly,
1027 - 6 characters ``\text...<tab>`` should now be inputed with ``\...<tab>`` directly,
1026 - 45 characters ``\Elz...<tab>`` should now be inputed with ``\...<tab>`` directly,
1028 - 45 characters ``\Elz...<tab>`` should now be inputed with ``\...<tab>`` directly,
1027 - 65 characters ``\B...<tab>`` should now be inputed with ``\...<tab>`` directly,
1029 - 65 characters ``\B...<tab>`` should now be inputed with ``\...<tab>`` directly,
1028 - 450 characters ``\m...<tab>`` should now be inputed with ``\...<tab>`` directly,
1030 - 450 characters ``\m...<tab>`` should now be inputed with ``\...<tab>`` directly,
1029
1031
1030 Some sequences have seen their prefix shortened:
1032 Some sequences have seen their prefix shortened:
1031
1033
1032 - 5 characters ``\mitBbb...<tab>`` should now be inputed with ``\bbi...<tab>`` directly,
1034 - 5 characters ``\mitBbb...<tab>`` should now be inputed with ``\bbi...<tab>`` directly,
1033 - 52 characters ``\mit...<tab>`` should now be inputed with ``\i...<tab>`` directly,
1035 - 52 characters ``\mit...<tab>`` should now be inputed with ``\i...<tab>`` directly,
1034 - 216 characters ``\mbfit...<tab>`` should now be inputed with ``\bi...<tab>`` directly,
1036 - 216 characters ``\mbfit...<tab>`` should now be inputed with ``\bi...<tab>`` directly,
1035 - 222 characters ``\mbf...<tab>`` should now be inputed with ``\b...<tab>`` directly,
1037 - 222 characters ``\mbf...<tab>`` should now be inputed with ``\b...<tab>`` directly,
1036
1038
1037 A couple of characters had their sequence simplified:
1039 A couple of characters had their sequence simplified:
1038
1040
1039 - ``Γ°``, type ``\dh<tab>``, instead of ``\eth<tab>``
1041 - ``Γ°``, type ``\dh<tab>``, instead of ``\eth<tab>``
1040 - ``Δ§``, type ``\hbar<tab>``, instead of ``\Elzxh<tab>``
1042 - ``Δ§``, type ``\hbar<tab>``, instead of ``\Elzxh<tab>``
1041 - ``ΙΈ``, type ``\ltphi<tab>``, instead of ``\textphi<tab>``
1043 - ``ΙΈ``, type ``\ltphi<tab>``, instead of ``\textphi<tab>``
1042 - ``Ο΄``, type ``\varTheta<tab>``, instead of ``\textTheta<tab>``
1044 - ``Ο΄``, type ``\varTheta<tab>``, instead of ``\textTheta<tab>``
1043 - ``ℇ``, type ``\eulermascheroni<tab>``, instead of ``\Eulerconst<tab>``
1045 - ``ℇ``, type ``\eulermascheroni<tab>``, instead of ``\Eulerconst<tab>``
1044 - ``β„Ž``, type ``\planck<tab>``, instead of ``\Planckconst<tab>``
1046 - ``β„Ž``, type ``\planck<tab>``, instead of ``\Planckconst<tab>``
1045
1047
1046 - U+0336 (COMBINING LONG STROKE OVERLAY), type ``\strike<tab>``, instead of ``\Elzbar<tab>``.
1048 - U+0336 (COMBINING LONG STROKE OVERLAY), type ``\strike<tab>``, instead of ``\Elzbar<tab>``.
1047
1049
1048 A couple of sequences have been updated:
1050 A couple of sequences have been updated:
1049
1051
1050 - ``\varepsilon`` now gives ``Ι›`` (GREEK SMALL LETTER EPSILON) instead of ``Ξ΅`` (GREEK LUNATE EPSILON SYMBOL),
1052 - ``\varepsilon`` now gives ``Ι›`` (GREEK SMALL LETTER EPSILON) instead of ``Ξ΅`` (GREEK LUNATE EPSILON SYMBOL),
1051 - ``\underbar`` now gives U+0331 (COMBINING MACRON BELOW) instead of U+0332 (COMBINING LOW LINE).
1053 - ``\underbar`` now gives U+0331 (COMBINING MACRON BELOW) instead of U+0332 (COMBINING LOW LINE).
1052
1054
1053
1055
1054 .. _whatsnew700:
1056 .. _whatsnew700:
1055
1057
1056 IPython 7.0.0
1058 IPython 7.0.0
1057 =============
1059 =============
1058
1060
1059 Released Thursday September 27th, 2018
1061 Released Thursday September 27th, 2018
1060
1062
1061 IPython 7 includes major feature improvements.
1063 IPython 7 includes major feature improvements.
1062 This is also the second major version of IPython to support only
1064 This is also the second major version of IPython to support only
1063 Python 3 – starting at Python 3.4. Python 2 is still community-supported
1065 Python 3 – starting at Python 3.4. Python 2 is still community-supported
1064 on the bugfix only 5.x branch, but we remind you that Python 2 "end of life"
1066 on the bugfix only 5.x branch, but we remind you that Python 2 "end of life"
1065 is on Jan 1st 2020.
1067 is on Jan 1st 2020.
1066
1068
1067 We were able to backport bug fixes to the 5.x branch thanks to our backport bot which
1069 We were able to backport bug fixes to the 5.x branch thanks to our backport bot which
1068 backported more than `70 Pull-Requests
1070 backported more than `70 Pull-Requests
1069 <https://github.com/ipython/ipython/pulls?page=3&q=is%3Apr+sort%3Aupdated-desc+author%3Aapp%2Fmeeseeksdev++5.x&utf8=%E2%9C%93>`_, but there are still many PRs that required manual work. This is an area of the project where you can easily contribute by looking for `PRs that still need manual backport <https://github.com/ipython/ipython/issues?q=label%3A%22Still+Needs+Manual+Backport%22+is%3Aclosed+sort%3Aupdated-desc>`_
1071 <https://github.com/ipython/ipython/pulls?page=3&q=is%3Apr+sort%3Aupdated-desc+author%3Aapp%2Fmeeseeksdev++5.x&utf8=%E2%9C%93>`_, but there are still many PRs that required manual work. This is an area of the project where you can easily contribute by looking for `PRs that still need manual backport <https://github.com/ipython/ipython/issues?q=label%3A%22Still+Needs+Manual+Backport%22+is%3Aclosed+sort%3Aupdated-desc>`_
1070
1072
1071 The IPython 6.x branch will likely not see any further release unless critical
1073 The IPython 6.x branch will likely not see any further release unless critical
1072 bugs are found.
1074 bugs are found.
1073
1075
1074 Make sure you have pip > 9.0 before upgrading. You should be able to update by running:
1076 Make sure you have pip > 9.0 before upgrading. You should be able to update by running:
1075
1077
1076 .. code::
1078 .. code::
1077
1079
1078 pip install ipython --upgrade
1080 pip install ipython --upgrade
1079
1081
1080 .. only:: ipydev
1082 .. only:: ipydev
1081
1083
1082 If you are trying to install or update an ``alpha``, ``beta``, or ``rc``
1084 If you are trying to install or update an ``alpha``, ``beta``, or ``rc``
1083 version, use pip ``--pre`` flag.
1085 version, use pip ``--pre`` flag.
1084
1086
1085 .. code::
1087 .. code::
1086
1088
1087 pip install ipython --upgrade --pre
1089 pip install ipython --upgrade --pre
1088
1090
1089
1091
1090 Or, if you have conda installed:
1092 Or, if you have conda installed:
1091
1093
1092 .. code::
1094 .. code::
1093
1095
1094 conda install ipython
1096 conda install ipython
1095
1097
1096
1098
1097
1099
1098 Prompt Toolkit 2.0
1100 Prompt Toolkit 2.0
1099 ------------------
1101 ------------------
1100
1102
1101 IPython 7.0+ now uses ``prompt_toolkit 2.0``. If you still need to use an earlier
1103 IPython 7.0+ now uses ``prompt_toolkit 2.0``. If you still need to use an earlier
1102 ``prompt_toolkit`` version, you may need to pin IPython to ``<7.0``.
1104 ``prompt_toolkit`` version, you may need to pin IPython to ``<7.0``.
1103
1105
1104 Autowait: Asynchronous REPL
1106 Autowait: Asynchronous REPL
1105 ---------------------------
1107 ---------------------------
1106
1108
1107 Staring with IPython 7.0 on Python 3.6+, IPython can automatically ``await``
1109 Staring with IPython 7.0 on Python 3.6+, IPython can automatically ``await``
1108 top level code. You should not need to access an event loop or runner
1110 top level code. You should not need to access an event loop or runner
1109 yourself. To learn more, read the :ref:`autoawait` section of our docs, see
1111 yourself. To learn more, read the :ref:`autoawait` section of our docs, see
1110 :ghpull:`11265`, or try the following code::
1112 :ghpull:`11265`, or try the following code::
1111
1113
1112 Python 3.6.0
1114 Python 3.6.0
1113 Type 'copyright', 'credits' or 'license' for more information
1115 Type 'copyright', 'credits' or 'license' for more information
1114 IPython 7.0.0 -- An enhanced Interactive Python. Type '?' for help.
1116 IPython 7.0.0 -- An enhanced Interactive Python. Type '?' for help.
1115
1117
1116 In [1]: import aiohttp
1118 In [1]: import aiohttp
1117 ...: result = aiohttp.get('https://api.github.com')
1119 ...: result = aiohttp.get('https://api.github.com')
1118
1120
1119 In [2]: response = await result
1121 In [2]: response = await result
1120 <pause for a few 100s ms>
1122 <pause for a few 100s ms>
1121
1123
1122 In [3]: await response.json()
1124 In [3]: await response.json()
1123 Out[3]:
1125 Out[3]:
1124 {'authorizations_url': 'https://api.github.com/authorizations',
1126 {'authorizations_url': 'https://api.github.com/authorizations',
1125 'code_search_url': 'https://api.github.com/search/code?q={query}{&page,per_page,sort,order}',
1127 'code_search_url': 'https://api.github.com/search/code?q={query}{&page,per_page,sort,order}',
1126 ...
1128 ...
1127 }
1129 }
1128
1130
1129 .. note::
1131 .. note::
1130
1132
1131 Async integration is experimental code, behavior may change or be removed
1133 Async integration is experimental code, behavior may change or be removed
1132 between Python and IPython versions without warnings.
1134 between Python and IPython versions without warnings.
1133
1135
1134 Integration is by default with `asyncio`, but other libraries can be configured --
1136 Integration is by default with `asyncio`, but other libraries can be configured --
1135 like ``curio`` or ``trio`` -- to improve concurrency in the REPL::
1137 like ``curio`` or ``trio`` -- to improve concurrency in the REPL::
1136
1138
1137 In [1]: %autoawait trio
1139 In [1]: %autoawait trio
1138
1140
1139 In [2]: import trio
1141 In [2]: import trio
1140
1142
1141 In [3]: async def child(i):
1143 In [3]: async def child(i):
1142 ...: print(" child %s goes to sleep"%i)
1144 ...: print(" child %s goes to sleep"%i)
1143 ...: await trio.sleep(2)
1145 ...: await trio.sleep(2)
1144 ...: print(" child %s wakes up"%i)
1146 ...: print(" child %s wakes up"%i)
1145
1147
1146 In [4]: print('parent start')
1148 In [4]: print('parent start')
1147 ...: async with trio.open_nursery() as n:
1149 ...: async with trio.open_nursery() as n:
1148 ...: for i in range(3):
1150 ...: for i in range(3):
1149 ...: n.spawn(child, i)
1151 ...: n.spawn(child, i)
1150 ...: print('parent end')
1152 ...: print('parent end')
1151 parent start
1153 parent start
1152 child 2 goes to sleep
1154 child 2 goes to sleep
1153 child 0 goes to sleep
1155 child 0 goes to sleep
1154 child 1 goes to sleep
1156 child 1 goes to sleep
1155 <about 2 seconds pause>
1157 <about 2 seconds pause>
1156 child 2 wakes up
1158 child 2 wakes up
1157 child 1 wakes up
1159 child 1 wakes up
1158 child 0 wakes up
1160 child 0 wakes up
1159 parent end
1161 parent end
1160
1162
1161 See :ref:`autoawait` for more information.
1163 See :ref:`autoawait` for more information.
1162
1164
1163
1165
1164 Asynchronous code in a Notebook interface or any other frontend using the
1166 Asynchronous code in a Notebook interface or any other frontend using the
1165 Jupyter Protocol will require further updates to the IPykernel package.
1167 Jupyter Protocol will require further updates to the IPykernel package.
1166
1168
1167 Non-Asynchronous code
1169 Non-Asynchronous code
1168 ~~~~~~~~~~~~~~~~~~~~~
1170 ~~~~~~~~~~~~~~~~~~~~~
1169
1171
1170 As the internal API of IPython is now asynchronous, IPython needs to run under
1172 As the internal API of IPython is now asynchronous, IPython needs to run under
1171 an event loop. In order to allow many workflows, (like using the :magic:`%run`
1173 an event loop. In order to allow many workflows, (like using the :magic:`%run`
1172 magic, or copy-pasting code that explicitly starts/stop event loop), when
1174 magic, or copy-pasting code that explicitly starts/stop event loop), when
1173 top-level code is detected as not being asynchronous, IPython code is advanced
1175 top-level code is detected as not being asynchronous, IPython code is advanced
1174 via a pseudo-synchronous runner, and may not advance pending tasks.
1176 via a pseudo-synchronous runner, and may not advance pending tasks.
1175
1177
1176 Change to Nested Embed
1178 Change to Nested Embed
1177 ~~~~~~~~~~~~~~~~~~~~~~
1179 ~~~~~~~~~~~~~~~~~~~~~~
1178
1180
1179 The introduction of the ability to run async code had some effect on the
1181 The introduction of the ability to run async code had some effect on the
1180 ``IPython.embed()`` API. By default, embed will not allow you to run asynchronous
1182 ``IPython.embed()`` API. By default, embed will not allow you to run asynchronous
1181 code unless an event loop is specified.
1183 code unless an event loop is specified.
1182
1184
1183 Effects on Magics
1185 Effects on Magics
1184 ~~~~~~~~~~~~~~~~~
1186 ~~~~~~~~~~~~~~~~~
1185
1187
1186 Some magics will not work with async until they're updated.
1188 Some magics will not work with async until they're updated.
1187 Contributions welcome.
1189 Contributions welcome.
1188
1190
1189 Expected Future changes
1191 Expected Future changes
1190 ~~~~~~~~~~~~~~~~~~~~~~~
1192 ~~~~~~~~~~~~~~~~~~~~~~~
1191
1193
1192 We expect more internal but public IPython functions to become ``async``, and
1194 We expect more internal but public IPython functions to become ``async``, and
1193 will likely end up having a persistent event loop while IPython is running.
1195 will likely end up having a persistent event loop while IPython is running.
1194
1196
1195 Thanks
1197 Thanks
1196 ~~~~~~
1198 ~~~~~~
1197
1199
1198 This release took more than a year in the making.
1200 This release took more than a year in the making.
1199 The code was rebased a number of
1201 The code was rebased a number of
1200 times; leading to commit authorship that may have been lost in the final
1202 times; leading to commit authorship that may have been lost in the final
1201 Pull-Request. Huge thanks to many people for contribution, discussion, code,
1203 Pull-Request. Huge thanks to many people for contribution, discussion, code,
1202 documentation, use-cases: dalejung, danielballan, ellisonbg, fperez, gnestor,
1204 documentation, use-cases: dalejung, danielballan, ellisonbg, fperez, gnestor,
1203 minrk, njsmith, pganssle, tacaswell, takluyver , vidartf ... And many others.
1205 minrk, njsmith, pganssle, tacaswell, takluyver , vidartf ... And many others.
1204
1206
1205
1207
1206 Autoreload Improvement
1208 Autoreload Improvement
1207 ----------------------
1209 ----------------------
1208
1210
1209 The magic :magic:`%autoreload 2 <autoreload>` now captures new methods added to
1211 The magic :magic:`%autoreload 2 <autoreload>` now captures new methods added to
1210 classes. Earlier, only methods existing as of the initial import were being
1212 classes. Earlier, only methods existing as of the initial import were being
1211 tracked and updated.
1213 tracked and updated.
1212
1214
1213 This new feature helps dual environment development - Jupyter+IDE - where the
1215 This new feature helps dual environment development - Jupyter+IDE - where the
1214 code gradually moves from notebook cells to package files as it gets
1216 code gradually moves from notebook cells to package files as it gets
1215 structured.
1217 structured.
1216
1218
1217 **Example**: An instance of the class ``MyClass`` will be able to access the
1219 **Example**: An instance of the class ``MyClass`` will be able to access the
1218 method ``cube()`` after it is uncommented and the file ``file1.py`` is saved on
1220 method ``cube()`` after it is uncommented and the file ``file1.py`` is saved on
1219 disk.
1221 disk.
1220
1222
1221
1223
1222 .. code::
1224 .. code::
1223
1225
1224 # notebook
1226 # notebook
1225
1227
1226 from mymodule import MyClass
1228 from mymodule import MyClass
1227 first = MyClass(5)
1229 first = MyClass(5)
1228
1230
1229 .. code::
1231 .. code::
1230
1232
1231 # mymodule/file1.py
1233 # mymodule/file1.py
1232
1234
1233 class MyClass:
1235 class MyClass:
1234
1236
1235 def __init__(self, a=10):
1237 def __init__(self, a=10):
1236 self.a = a
1238 self.a = a
1237
1239
1238 def square(self):
1240 def square(self):
1239 print('compute square')
1241 print('compute square')
1240 return self.a*self.a
1242 return self.a*self.a
1241
1243
1242 # def cube(self):
1244 # def cube(self):
1243 # print('compute cube')
1245 # print('compute cube')
1244 # return self.a*self.a*self.a
1246 # return self.a*self.a*self.a
1245
1247
1246
1248
1247
1249
1248
1250
1249 Misc
1251 Misc
1250 ----
1252 ----
1251
1253
1252 The autoindent feature that was deprecated in 5.x was re-enabled and
1254 The autoindent feature that was deprecated in 5.x was re-enabled and
1253 un-deprecated in :ghpull:`11257`
1255 un-deprecated in :ghpull:`11257`
1254
1256
1255 Make :magic:`%run -n -i ... <run>` work correctly. Earlier, if :magic:`%run` was
1257 Make :magic:`%run -n -i ... <run>` work correctly. Earlier, if :magic:`%run` was
1256 passed both arguments, ``-n`` would be silently ignored. See :ghpull:`10308`
1258 passed both arguments, ``-n`` would be silently ignored. See :ghpull:`10308`
1257
1259
1258
1260
1259 The :cellmagic:`%%script` (as well as :cellmagic:`%%bash`,
1261 The :cellmagic:`%%script` (as well as :cellmagic:`%%bash`,
1260 :cellmagic:`%%ruby`... ) cell magics now raise by default if the return code of
1262 :cellmagic:`%%ruby`... ) cell magics now raise by default if the return code of
1261 the given code is non-zero (thus halting execution of further cells in a
1263 the given code is non-zero (thus halting execution of further cells in a
1262 notebook). The behavior can be disable by passing the ``--no-raise-error`` flag.
1264 notebook). The behavior can be disable by passing the ``--no-raise-error`` flag.
1263
1265
1264
1266
1265 Deprecations
1267 Deprecations
1266 ------------
1268 ------------
1267
1269
1268 A couple of unused functions and methods have been deprecated and will be removed
1270 A couple of unused functions and methods have been deprecated and will be removed
1269 in future versions:
1271 in future versions:
1270
1272
1271 - ``IPython.utils.io.raw_print_err``
1273 - ``IPython.utils.io.raw_print_err``
1272 - ``IPython.utils.io.raw_print``
1274 - ``IPython.utils.io.raw_print``
1273
1275
1274
1276
1275 Backwards incompatible changes
1277 Backwards incompatible changes
1276 ------------------------------
1278 ------------------------------
1277
1279
1278 * The API for transforming input before it is parsed as Python code has been
1280 * The API for transforming input before it is parsed as Python code has been
1279 completely redesigned: any custom input transformations will need to be
1281 completely redesigned: any custom input transformations will need to be
1280 rewritten. See :doc:`/config/inputtransforms` for details of the new API.
1282 rewritten. See :doc:`/config/inputtransforms` for details of the new API.
General Comments 0
You need to be logged in to leave comments. Login now