##// END OF EJS Templates
Fix Image when passing only data, and add tests....
Matthias Bussonnier -
Show More
@@ -1,980 +1,979 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Top-level display functions for displaying object in different formats."""
2 """Top-level display functions for displaying object in different formats."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 from __future__ import print_function
7 from __future__ import print_function
8
8
9 import json
9 import json
10 import mimetypes
10 import mimetypes
11 import os
11 import os
12 import struct
12 import struct
13 import warnings
13 import warnings
14
14
15 from IPython.core.formatters import _safe_get_formatter_method
16 from IPython.utils.py3compat import (string_types, cast_bytes_py2, cast_unicode,
15 from IPython.utils.py3compat import (string_types, cast_bytes_py2, cast_unicode,
17 unicode_type)
16 unicode_type)
18 from IPython.testing.skipdoctest import skip_doctest
17 from IPython.testing.skipdoctest import skip_doctest
19
18
20 __all__ = ['display', 'display_pretty', 'display_html', 'display_markdown',
19 __all__ = ['display', 'display_pretty', 'display_html', 'display_markdown',
21 'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
20 'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
22 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
21 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
23 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'JSON', 'Javascript',
22 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'JSON', 'Javascript',
24 'Image', 'clear_output', 'set_matplotlib_formats', 'set_matplotlib_close',
23 'Image', 'clear_output', 'set_matplotlib_formats', 'set_matplotlib_close',
25 'publish_display_data']
24 'publish_display_data']
26
25
27 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
28 # utility functions
27 # utility functions
29 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
30
29
31 def _safe_exists(path):
30 def _safe_exists(path):
32 """Check path, but don't let exceptions raise"""
31 """Check path, but don't let exceptions raise"""
33 try:
32 try:
34 return os.path.exists(path)
33 return os.path.exists(path)
35 except Exception:
34 except Exception:
36 return False
35 return False
37
36
38 def _merge(d1, d2):
37 def _merge(d1, d2):
39 """Like update, but merges sub-dicts instead of clobbering at the top level.
38 """Like update, but merges sub-dicts instead of clobbering at the top level.
40
39
41 Updates d1 in-place
40 Updates d1 in-place
42 """
41 """
43
42
44 if not isinstance(d2, dict) or not isinstance(d1, dict):
43 if not isinstance(d2, dict) or not isinstance(d1, dict):
45 return d2
44 return d2
46 for key, value in d2.items():
45 for key, value in d2.items():
47 d1[key] = _merge(d1.get(key), value)
46 d1[key] = _merge(d1.get(key), value)
48 return d1
47 return d1
49
48
50 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
49 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
51 """internal implementation of all display_foo methods
50 """internal implementation of all display_foo methods
52
51
53 Parameters
52 Parameters
54 ----------
53 ----------
55 mimetype : str
54 mimetype : str
56 The mimetype to be published (e.g. 'image/png')
55 The mimetype to be published (e.g. 'image/png')
57 objs : tuple of objects
56 objs : tuple of objects
58 The Python objects to display, or if raw=True raw text data to
57 The Python objects to display, or if raw=True raw text data to
59 display.
58 display.
60 raw : bool
59 raw : bool
61 Are the data objects raw data or Python objects that need to be
60 Are the data objects raw data or Python objects that need to be
62 formatted before display? [default: False]
61 formatted before display? [default: False]
63 metadata : dict (optional)
62 metadata : dict (optional)
64 Metadata to be associated with the specific mimetype output.
63 Metadata to be associated with the specific mimetype output.
65 """
64 """
66 if metadata:
65 if metadata:
67 metadata = {mimetype: metadata}
66 metadata = {mimetype: metadata}
68 if raw:
67 if raw:
69 # turn list of pngdata into list of { 'image/png': pngdata }
68 # turn list of pngdata into list of { 'image/png': pngdata }
70 objs = [ {mimetype: obj} for obj in objs ]
69 objs = [ {mimetype: obj} for obj in objs ]
71 display(*objs, raw=raw, metadata=metadata, include=[mimetype])
70 display(*objs, raw=raw, metadata=metadata, include=[mimetype])
72
71
73 #-----------------------------------------------------------------------------
72 #-----------------------------------------------------------------------------
74 # Main functions
73 # Main functions
75 #-----------------------------------------------------------------------------
74 #-----------------------------------------------------------------------------
76
75
77 def publish_display_data(data, metadata=None, source=None):
76 def publish_display_data(data, metadata=None, source=None):
78 """Publish data and metadata to all frontends.
77 """Publish data and metadata to all frontends.
79
78
80 See the ``display_data`` message in the messaging documentation for
79 See the ``display_data`` message in the messaging documentation for
81 more details about this message type.
80 more details about this message type.
82
81
83 The following MIME types are currently implemented:
82 The following MIME types are currently implemented:
84
83
85 * text/plain
84 * text/plain
86 * text/html
85 * text/html
87 * text/markdown
86 * text/markdown
88 * text/latex
87 * text/latex
89 * application/json
88 * application/json
90 * application/javascript
89 * application/javascript
91 * image/png
90 * image/png
92 * image/jpeg
91 * image/jpeg
93 * image/svg+xml
92 * image/svg+xml
94
93
95 Parameters
94 Parameters
96 ----------
95 ----------
97 data : dict
96 data : dict
98 A dictionary having keys that are valid MIME types (like
97 A dictionary having keys that are valid MIME types (like
99 'text/plain' or 'image/svg+xml') and values that are the data for
98 'text/plain' or 'image/svg+xml') and values that are the data for
100 that MIME type. The data itself must be a JSON'able data
99 that MIME type. The data itself must be a JSON'able data
101 structure. Minimally all data should have the 'text/plain' data,
100 structure. Minimally all data should have the 'text/plain' data,
102 which can be displayed by all frontends. If more than the plain
101 which can be displayed by all frontends. If more than the plain
103 text is given, it is up to the frontend to decide which
102 text is given, it is up to the frontend to decide which
104 representation to use.
103 representation to use.
105 metadata : dict
104 metadata : dict
106 A dictionary for metadata related to the data. This can contain
105 A dictionary for metadata related to the data. This can contain
107 arbitrary key, value pairs that frontends can use to interpret
106 arbitrary key, value pairs that frontends can use to interpret
108 the data. mime-type keys matching those in data can be used
107 the data. mime-type keys matching those in data can be used
109 to specify metadata about particular representations.
108 to specify metadata about particular representations.
110 source : str, deprecated
109 source : str, deprecated
111 Unused.
110 Unused.
112 """
111 """
113 from IPython.core.interactiveshell import InteractiveShell
112 from IPython.core.interactiveshell import InteractiveShell
114 InteractiveShell.instance().display_pub.publish(
113 InteractiveShell.instance().display_pub.publish(
115 data=data,
114 data=data,
116 metadata=metadata,
115 metadata=metadata,
117 )
116 )
118
117
119 def display(*objs, **kwargs):
118 def display(*objs, **kwargs):
120 """Display a Python object in all frontends.
119 """Display a Python object in all frontends.
121
120
122 By default all representations will be computed and sent to the frontends.
121 By default all representations will be computed and sent to the frontends.
123 Frontends can decide which representation is used and how.
122 Frontends can decide which representation is used and how.
124
123
125 Parameters
124 Parameters
126 ----------
125 ----------
127 objs : tuple of objects
126 objs : tuple of objects
128 The Python objects to display.
127 The Python objects to display.
129 raw : bool, optional
128 raw : bool, optional
130 Are the objects to be displayed already mimetype-keyed dicts of raw display data,
129 Are the objects to be displayed already mimetype-keyed dicts of raw display data,
131 or Python objects that need to be formatted before display? [default: False]
130 or Python objects that need to be formatted before display? [default: False]
132 include : list or tuple, optional
131 include : list or tuple, optional
133 A list of format type strings (MIME types) to include in the
132 A list of format type strings (MIME types) to include in the
134 format data dict. If this is set *only* the format types included
133 format data dict. If this is set *only* the format types included
135 in this list will be computed.
134 in this list will be computed.
136 exclude : list or tuple, optional
135 exclude : list or tuple, optional
137 A list of format type strings (MIME types) to exclude in the format
136 A list of format type strings (MIME types) to exclude in the format
138 data dict. If this is set all format types will be computed,
137 data dict. If this is set all format types will be computed,
139 except for those included in this argument.
138 except for those included in this argument.
140 metadata : dict, optional
139 metadata : dict, optional
141 A dictionary of metadata to associate with the output.
140 A dictionary of metadata to associate with the output.
142 mime-type keys in this dictionary will be associated with the individual
141 mime-type keys in this dictionary will be associated with the individual
143 representation formats, if they exist.
142 representation formats, if they exist.
144 """
143 """
145 raw = kwargs.get('raw', False)
144 raw = kwargs.get('raw', False)
146 include = kwargs.get('include')
145 include = kwargs.get('include')
147 exclude = kwargs.get('exclude')
146 exclude = kwargs.get('exclude')
148 metadata = kwargs.get('metadata')
147 metadata = kwargs.get('metadata')
149
148
150 from IPython.core.interactiveshell import InteractiveShell
149 from IPython.core.interactiveshell import InteractiveShell
151
150
152 if not raw:
151 if not raw:
153 format = InteractiveShell.instance().display_formatter.format
152 format = InteractiveShell.instance().display_formatter.format
154
153
155 for obj in objs:
154 for obj in objs:
156 if raw:
155 if raw:
157 publish_display_data(data=obj, metadata=metadata)
156 publish_display_data(data=obj, metadata=metadata)
158 else:
157 else:
159 format_dict, md_dict = format(obj, include=include, exclude=exclude)
158 format_dict, md_dict = format(obj, include=include, exclude=exclude)
160 if not format_dict:
159 if not format_dict:
161 # nothing to display (e.g. _ipython_display_ took over)
160 # nothing to display (e.g. _ipython_display_ took over)
162 continue
161 continue
163 if metadata:
162 if metadata:
164 # kwarg-specified metadata gets precedence
163 # kwarg-specified metadata gets precedence
165 _merge(md_dict, metadata)
164 _merge(md_dict, metadata)
166 publish_display_data(data=format_dict, metadata=md_dict)
165 publish_display_data(data=format_dict, metadata=md_dict)
167
166
168
167
169 def display_pretty(*objs, **kwargs):
168 def display_pretty(*objs, **kwargs):
170 """Display the pretty (default) representation of an object.
169 """Display the pretty (default) representation of an object.
171
170
172 Parameters
171 Parameters
173 ----------
172 ----------
174 objs : tuple of objects
173 objs : tuple of objects
175 The Python objects to display, or if raw=True raw text data to
174 The Python objects to display, or if raw=True raw text data to
176 display.
175 display.
177 raw : bool
176 raw : bool
178 Are the data objects raw data or Python objects that need to be
177 Are the data objects raw data or Python objects that need to be
179 formatted before display? [default: False]
178 formatted before display? [default: False]
180 metadata : dict (optional)
179 metadata : dict (optional)
181 Metadata to be associated with the specific mimetype output.
180 Metadata to be associated with the specific mimetype output.
182 """
181 """
183 _display_mimetype('text/plain', objs, **kwargs)
182 _display_mimetype('text/plain', objs, **kwargs)
184
183
185
184
186 def display_html(*objs, **kwargs):
185 def display_html(*objs, **kwargs):
187 """Display the HTML representation of an object.
186 """Display the HTML representation of an object.
188
187
189 Note: If raw=False and the object does not have a HTML
188 Note: If raw=False and the object does not have a HTML
190 representation, no HTML will be shown.
189 representation, no HTML will be shown.
191
190
192 Parameters
191 Parameters
193 ----------
192 ----------
194 objs : tuple of objects
193 objs : tuple of objects
195 The Python objects to display, or if raw=True raw HTML data to
194 The Python objects to display, or if raw=True raw HTML data to
196 display.
195 display.
197 raw : bool
196 raw : bool
198 Are the data objects raw data or Python objects that need to be
197 Are the data objects raw data or Python objects that need to be
199 formatted before display? [default: False]
198 formatted before display? [default: False]
200 metadata : dict (optional)
199 metadata : dict (optional)
201 Metadata to be associated with the specific mimetype output.
200 Metadata to be associated with the specific mimetype output.
202 """
201 """
203 _display_mimetype('text/html', objs, **kwargs)
202 _display_mimetype('text/html', objs, **kwargs)
204
203
205
204
206 def display_markdown(*objs, **kwargs):
205 def display_markdown(*objs, **kwargs):
207 """Displays the Markdown representation of an object.
206 """Displays the Markdown representation of an object.
208
207
209 Parameters
208 Parameters
210 ----------
209 ----------
211 objs : tuple of objects
210 objs : tuple of objects
212 The Python objects to display, or if raw=True raw markdown data to
211 The Python objects to display, or if raw=True raw markdown data to
213 display.
212 display.
214 raw : bool
213 raw : bool
215 Are the data objects raw data or Python objects that need to be
214 Are the data objects raw data or Python objects that need to be
216 formatted before display? [default: False]
215 formatted before display? [default: False]
217 metadata : dict (optional)
216 metadata : dict (optional)
218 Metadata to be associated with the specific mimetype output.
217 Metadata to be associated with the specific mimetype output.
219 """
218 """
220
219
221 _display_mimetype('text/markdown', objs, **kwargs)
220 _display_mimetype('text/markdown', objs, **kwargs)
222
221
223
222
224 def display_svg(*objs, **kwargs):
223 def display_svg(*objs, **kwargs):
225 """Display the SVG representation of an object.
224 """Display the SVG representation of an object.
226
225
227 Parameters
226 Parameters
228 ----------
227 ----------
229 objs : tuple of objects
228 objs : tuple of objects
230 The Python objects to display, or if raw=True raw svg data to
229 The Python objects to display, or if raw=True raw svg data to
231 display.
230 display.
232 raw : bool
231 raw : bool
233 Are the data objects raw data or Python objects that need to be
232 Are the data objects raw data or Python objects that need to be
234 formatted before display? [default: False]
233 formatted before display? [default: False]
235 metadata : dict (optional)
234 metadata : dict (optional)
236 Metadata to be associated with the specific mimetype output.
235 Metadata to be associated with the specific mimetype output.
237 """
236 """
238 _display_mimetype('image/svg+xml', objs, **kwargs)
237 _display_mimetype('image/svg+xml', objs, **kwargs)
239
238
240
239
241 def display_png(*objs, **kwargs):
240 def display_png(*objs, **kwargs):
242 """Display the PNG representation of an object.
241 """Display the PNG representation of an object.
243
242
244 Parameters
243 Parameters
245 ----------
244 ----------
246 objs : tuple of objects
245 objs : tuple of objects
247 The Python objects to display, or if raw=True raw png data to
246 The Python objects to display, or if raw=True raw png data to
248 display.
247 display.
249 raw : bool
248 raw : bool
250 Are the data objects raw data or Python objects that need to be
249 Are the data objects raw data or Python objects that need to be
251 formatted before display? [default: False]
250 formatted before display? [default: False]
252 metadata : dict (optional)
251 metadata : dict (optional)
253 Metadata to be associated with the specific mimetype output.
252 Metadata to be associated with the specific mimetype output.
254 """
253 """
255 _display_mimetype('image/png', objs, **kwargs)
254 _display_mimetype('image/png', objs, **kwargs)
256
255
257
256
258 def display_jpeg(*objs, **kwargs):
257 def display_jpeg(*objs, **kwargs):
259 """Display the JPEG representation of an object.
258 """Display the JPEG representation of an object.
260
259
261 Parameters
260 Parameters
262 ----------
261 ----------
263 objs : tuple of objects
262 objs : tuple of objects
264 The Python objects to display, or if raw=True raw JPEG data to
263 The Python objects to display, or if raw=True raw JPEG data to
265 display.
264 display.
266 raw : bool
265 raw : bool
267 Are the data objects raw data or Python objects that need to be
266 Are the data objects raw data or Python objects that need to be
268 formatted before display? [default: False]
267 formatted before display? [default: False]
269 metadata : dict (optional)
268 metadata : dict (optional)
270 Metadata to be associated with the specific mimetype output.
269 Metadata to be associated with the specific mimetype output.
271 """
270 """
272 _display_mimetype('image/jpeg', objs, **kwargs)
271 _display_mimetype('image/jpeg', objs, **kwargs)
273
272
274
273
275 def display_latex(*objs, **kwargs):
274 def display_latex(*objs, **kwargs):
276 """Display the LaTeX representation of an object.
275 """Display the LaTeX representation of an object.
277
276
278 Parameters
277 Parameters
279 ----------
278 ----------
280 objs : tuple of objects
279 objs : tuple of objects
281 The Python objects to display, or if raw=True raw latex data to
280 The Python objects to display, or if raw=True raw latex data to
282 display.
281 display.
283 raw : bool
282 raw : bool
284 Are the data objects raw data or Python objects that need to be
283 Are the data objects raw data or Python objects that need to be
285 formatted before display? [default: False]
284 formatted before display? [default: False]
286 metadata : dict (optional)
285 metadata : dict (optional)
287 Metadata to be associated with the specific mimetype output.
286 Metadata to be associated with the specific mimetype output.
288 """
287 """
289 _display_mimetype('text/latex', objs, **kwargs)
288 _display_mimetype('text/latex', objs, **kwargs)
290
289
291
290
292 def display_json(*objs, **kwargs):
291 def display_json(*objs, **kwargs):
293 """Display the JSON representation of an object.
292 """Display the JSON representation of an object.
294
293
295 Note that not many frontends support displaying JSON.
294 Note that not many frontends support displaying JSON.
296
295
297 Parameters
296 Parameters
298 ----------
297 ----------
299 objs : tuple of objects
298 objs : tuple of objects
300 The Python objects to display, or if raw=True raw json data to
299 The Python objects to display, or if raw=True raw json data to
301 display.
300 display.
302 raw : bool
301 raw : bool
303 Are the data objects raw data or Python objects that need to be
302 Are the data objects raw data or Python objects that need to be
304 formatted before display? [default: False]
303 formatted before display? [default: False]
305 metadata : dict (optional)
304 metadata : dict (optional)
306 Metadata to be associated with the specific mimetype output.
305 Metadata to be associated with the specific mimetype output.
307 """
306 """
308 _display_mimetype('application/json', objs, **kwargs)
307 _display_mimetype('application/json', objs, **kwargs)
309
308
310
309
311 def display_javascript(*objs, **kwargs):
310 def display_javascript(*objs, **kwargs):
312 """Display the Javascript representation of an object.
311 """Display the Javascript representation of an object.
313
312
314 Parameters
313 Parameters
315 ----------
314 ----------
316 objs : tuple of objects
315 objs : tuple of objects
317 The Python objects to display, or if raw=True raw javascript data to
316 The Python objects to display, or if raw=True raw javascript data to
318 display.
317 display.
319 raw : bool
318 raw : bool
320 Are the data objects raw data or Python objects that need to be
319 Are the data objects raw data or Python objects that need to be
321 formatted before display? [default: False]
320 formatted before display? [default: False]
322 metadata : dict (optional)
321 metadata : dict (optional)
323 Metadata to be associated with the specific mimetype output.
322 Metadata to be associated with the specific mimetype output.
324 """
323 """
325 _display_mimetype('application/javascript', objs, **kwargs)
324 _display_mimetype('application/javascript', objs, **kwargs)
326
325
327
326
328 def display_pdf(*objs, **kwargs):
327 def display_pdf(*objs, **kwargs):
329 """Display the PDF representation of an object.
328 """Display the PDF representation of an object.
330
329
331 Parameters
330 Parameters
332 ----------
331 ----------
333 objs : tuple of objects
332 objs : tuple of objects
334 The Python objects to display, or if raw=True raw javascript data to
333 The Python objects to display, or if raw=True raw javascript data to
335 display.
334 display.
336 raw : bool
335 raw : bool
337 Are the data objects raw data or Python objects that need to be
336 Are the data objects raw data or Python objects that need to be
338 formatted before display? [default: False]
337 formatted before display? [default: False]
339 metadata : dict (optional)
338 metadata : dict (optional)
340 Metadata to be associated with the specific mimetype output.
339 Metadata to be associated with the specific mimetype output.
341 """
340 """
342 _display_mimetype('application/pdf', objs, **kwargs)
341 _display_mimetype('application/pdf', objs, **kwargs)
343
342
344
343
345 #-----------------------------------------------------------------------------
344 #-----------------------------------------------------------------------------
346 # Smart classes
345 # Smart classes
347 #-----------------------------------------------------------------------------
346 #-----------------------------------------------------------------------------
348
347
349
348
350 class DisplayObject(object):
349 class DisplayObject(object):
351 """An object that wraps data to be displayed."""
350 """An object that wraps data to be displayed."""
352
351
353 _read_flags = 'r'
352 _read_flags = 'r'
354 _show_mem_addr = False
353 _show_mem_addr = False
355
354
356 def __init__(self, data=None, url=None, filename=None):
355 def __init__(self, data=None, url=None, filename=None):
357 """Create a display object given raw data.
356 """Create a display object given raw data.
358
357
359 When this object is returned by an expression or passed to the
358 When this object is returned by an expression or passed to the
360 display function, it will result in the data being displayed
359 display function, it will result in the data being displayed
361 in the frontend. The MIME type of the data should match the
360 in the frontend. The MIME type of the data should match the
362 subclasses used, so the Png subclass should be used for 'image/png'
361 subclasses used, so the Png subclass should be used for 'image/png'
363 data. If the data is a URL, the data will first be downloaded
362 data. If the data is a URL, the data will first be downloaded
364 and then displayed. If
363 and then displayed. If
365
364
366 Parameters
365 Parameters
367 ----------
366 ----------
368 data : unicode, str or bytes
367 data : unicode, str or bytes
369 The raw data or a URL or file to load the data from
368 The raw data or a URL or file to load the data from
370 url : unicode
369 url : unicode
371 A URL to download the data from.
370 A URL to download the data from.
372 filename : unicode
371 filename : unicode
373 Path to a local file to load the data from.
372 Path to a local file to load the data from.
374 """
373 """
375 if data is not None and isinstance(data, string_types):
374 if data is not None and isinstance(data, string_types):
376 if data.startswith('http') and url is None:
375 if data.startswith('http') and url is None:
377 url = data
376 url = data
378 filename = None
377 filename = None
379 data = None
378 data = None
380 elif _safe_exists(data) and filename is None:
379 elif _safe_exists(data) and filename is None:
381 url = None
380 url = None
382 filename = data
381 filename = data
383 data = None
382 data = None
384
383
385 self.data = data
384 self.data = data
386 self.url = url
385 self.url = url
387 self.filename = None if filename is None else unicode_type(filename)
386 self.filename = None if filename is None else unicode_type(filename)
388
387
389 self.reload()
388 self.reload()
390 self._check_data()
389 self._check_data()
391
390
392 def __repr__(self):
391 def __repr__(self):
393 if not self._show_mem_addr:
392 if not self._show_mem_addr:
394 cls = self.__class__
393 cls = self.__class__
395 r = "<%s.%s object>" % (cls.__module__, cls.__name__)
394 r = "<%s.%s object>" % (cls.__module__, cls.__name__)
396 else:
395 else:
397 r = super(DisplayObject, self).__repr__()
396 r = super(DisplayObject, self).__repr__()
398 return r
397 return r
399
398
400 def _check_data(self):
399 def _check_data(self):
401 """Override in subclasses if there's something to check."""
400 """Override in subclasses if there's something to check."""
402 pass
401 pass
403
402
404 def reload(self):
403 def reload(self):
405 """Reload the raw data from file or URL."""
404 """Reload the raw data from file or URL."""
406 if self.filename is not None:
405 if self.filename is not None:
407 with open(self.filename, self._read_flags) as f:
406 with open(self.filename, self._read_flags) as f:
408 self.data = f.read()
407 self.data = f.read()
409 elif self.url is not None:
408 elif self.url is not None:
410 try:
409 try:
411 try:
410 try:
412 from urllib.request import urlopen # Py3
411 from urllib.request import urlopen # Py3
413 except ImportError:
412 except ImportError:
414 from urllib2 import urlopen
413 from urllib2 import urlopen
415 response = urlopen(self.url)
414 response = urlopen(self.url)
416 self.data = response.read()
415 self.data = response.read()
417 # extract encoding from header, if there is one:
416 # extract encoding from header, if there is one:
418 encoding = None
417 encoding = None
419 for sub in response.headers['content-type'].split(';'):
418 for sub in response.headers['content-type'].split(';'):
420 sub = sub.strip()
419 sub = sub.strip()
421 if sub.startswith('charset'):
420 if sub.startswith('charset'):
422 encoding = sub.split('=')[-1].strip()
421 encoding = sub.split('=')[-1].strip()
423 break
422 break
424 # decode data, if an encoding was specified
423 # decode data, if an encoding was specified
425 if encoding:
424 if encoding:
426 self.data = self.data.decode(encoding, 'replace')
425 self.data = self.data.decode(encoding, 'replace')
427 except:
426 except:
428 self.data = None
427 self.data = None
429
428
430 class TextDisplayObject(DisplayObject):
429 class TextDisplayObject(DisplayObject):
431 """Validate that display data is text"""
430 """Validate that display data is text"""
432 def _check_data(self):
431 def _check_data(self):
433 if self.data is not None and not isinstance(self.data, string_types):
432 if self.data is not None and not isinstance(self.data, string_types):
434 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
433 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
435
434
436 class Pretty(TextDisplayObject):
435 class Pretty(TextDisplayObject):
437
436
438 def _repr_pretty_(self):
437 def _repr_pretty_(self):
439 return self.data
438 return self.data
440
439
441
440
442 class HTML(TextDisplayObject):
441 class HTML(TextDisplayObject):
443
442
444 def _repr_html_(self):
443 def _repr_html_(self):
445 return self.data
444 return self.data
446
445
447 def __html__(self):
446 def __html__(self):
448 """
447 """
449 This method exists to inform other HTML-using modules (e.g. Markupsafe,
448 This method exists to inform other HTML-using modules (e.g. Markupsafe,
450 htmltag, etc) that this object is HTML and does not need things like
449 htmltag, etc) that this object is HTML and does not need things like
451 special characters (<>&) escaped.
450 special characters (<>&) escaped.
452 """
451 """
453 return self._repr_html_()
452 return self._repr_html_()
454
453
455
454
456 class Markdown(TextDisplayObject):
455 class Markdown(TextDisplayObject):
457
456
458 def _repr_markdown_(self):
457 def _repr_markdown_(self):
459 return self.data
458 return self.data
460
459
461
460
462 class Math(TextDisplayObject):
461 class Math(TextDisplayObject):
463
462
464 def _repr_latex_(self):
463 def _repr_latex_(self):
465 s = self.data.strip('$')
464 s = self.data.strip('$')
466 return "$$%s$$" % s
465 return "$$%s$$" % s
467
466
468
467
469 class Latex(TextDisplayObject):
468 class Latex(TextDisplayObject):
470
469
471 def _repr_latex_(self):
470 def _repr_latex_(self):
472 return self.data
471 return self.data
473
472
474
473
475 class SVG(DisplayObject):
474 class SVG(DisplayObject):
476
475
477 # wrap data in a property, which extracts the <svg> tag, discarding
476 # wrap data in a property, which extracts the <svg> tag, discarding
478 # document headers
477 # document headers
479 _data = None
478 _data = None
480
479
481 @property
480 @property
482 def data(self):
481 def data(self):
483 return self._data
482 return self._data
484
483
485 @data.setter
484 @data.setter
486 def data(self, svg):
485 def data(self, svg):
487 if svg is None:
486 if svg is None:
488 self._data = None
487 self._data = None
489 return
488 return
490 # parse into dom object
489 # parse into dom object
491 from xml.dom import minidom
490 from xml.dom import minidom
492 svg = cast_bytes_py2(svg)
491 svg = cast_bytes_py2(svg)
493 x = minidom.parseString(svg)
492 x = minidom.parseString(svg)
494 # get svg tag (should be 1)
493 # get svg tag (should be 1)
495 found_svg = x.getElementsByTagName('svg')
494 found_svg = x.getElementsByTagName('svg')
496 if found_svg:
495 if found_svg:
497 svg = found_svg[0].toxml()
496 svg = found_svg[0].toxml()
498 else:
497 else:
499 # fallback on the input, trust the user
498 # fallback on the input, trust the user
500 # but this is probably an error.
499 # but this is probably an error.
501 pass
500 pass
502 svg = cast_unicode(svg)
501 svg = cast_unicode(svg)
503 self._data = svg
502 self._data = svg
504
503
505 def _repr_svg_(self):
504 def _repr_svg_(self):
506 return self.data
505 return self.data
507
506
508
507
509 class JSON(DisplayObject):
508 class JSON(DisplayObject):
510 """JSON expects a JSON-able dict or list
509 """JSON expects a JSON-able dict or list
511
510
512 not an already-serialized JSON string.
511 not an already-serialized JSON string.
513
512
514 Scalar types (None, number, string) are not allowed, only dict or list containers.
513 Scalar types (None, number, string) are not allowed, only dict or list containers.
515 """
514 """
516 # wrap data in a property, which warns about passing already-serialized JSON
515 # wrap data in a property, which warns about passing already-serialized JSON
517 _data = None
516 _data = None
518 def _check_data(self):
517 def _check_data(self):
519 if self.data is not None and not isinstance(self.data, (dict, list)):
518 if self.data is not None and not isinstance(self.data, (dict, list)):
520 raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
519 raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
521
520
522 @property
521 @property
523 def data(self):
522 def data(self):
524 return self._data
523 return self._data
525
524
526 @data.setter
525 @data.setter
527 def data(self, data):
526 def data(self, data):
528 if isinstance(data, string_types):
527 if isinstance(data, string_types):
529 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
528 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
530 data = json.loads(data)
529 data = json.loads(data)
531 self._data = data
530 self._data = data
532
531
533 def _repr_json_(self):
532 def _repr_json_(self):
534 return self.data
533 return self.data
535
534
536 css_t = """$("head").append($("<link/>").attr({
535 css_t = """$("head").append($("<link/>").attr({
537 rel: "stylesheet",
536 rel: "stylesheet",
538 type: "text/css",
537 type: "text/css",
539 href: "%s"
538 href: "%s"
540 }));
539 }));
541 """
540 """
542
541
543 lib_t1 = """$.getScript("%s", function () {
542 lib_t1 = """$.getScript("%s", function () {
544 """
543 """
545 lib_t2 = """});
544 lib_t2 = """});
546 """
545 """
547
546
548 class Javascript(TextDisplayObject):
547 class Javascript(TextDisplayObject):
549
548
550 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
549 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
551 """Create a Javascript display object given raw data.
550 """Create a Javascript display object given raw data.
552
551
553 When this object is returned by an expression or passed to the
552 When this object is returned by an expression or passed to the
554 display function, it will result in the data being displayed
553 display function, it will result in the data being displayed
555 in the frontend. If the data is a URL, the data will first be
554 in the frontend. If the data is a URL, the data will first be
556 downloaded and then displayed.
555 downloaded and then displayed.
557
556
558 In the Notebook, the containing element will be available as `element`,
557 In the Notebook, the containing element will be available as `element`,
559 and jQuery will be available. Content appended to `element` will be
558 and jQuery will be available. Content appended to `element` will be
560 visible in the output area.
559 visible in the output area.
561
560
562 Parameters
561 Parameters
563 ----------
562 ----------
564 data : unicode, str or bytes
563 data : unicode, str or bytes
565 The Javascript source code or a URL to download it from.
564 The Javascript source code or a URL to download it from.
566 url : unicode
565 url : unicode
567 A URL to download the data from.
566 A URL to download the data from.
568 filename : unicode
567 filename : unicode
569 Path to a local file to load the data from.
568 Path to a local file to load the data from.
570 lib : list or str
569 lib : list or str
571 A sequence of Javascript library URLs to load asynchronously before
570 A sequence of Javascript library URLs to load asynchronously before
572 running the source code. The full URLs of the libraries should
571 running the source code. The full URLs of the libraries should
573 be given. A single Javascript library URL can also be given as a
572 be given. A single Javascript library URL can also be given as a
574 string.
573 string.
575 css: : list or str
574 css: : list or str
576 A sequence of css files to load before running the source code.
575 A sequence of css files to load before running the source code.
577 The full URLs of the css files should be given. A single css URL
576 The full URLs of the css files should be given. A single css URL
578 can also be given as a string.
577 can also be given as a string.
579 """
578 """
580 if isinstance(lib, string_types):
579 if isinstance(lib, string_types):
581 lib = [lib]
580 lib = [lib]
582 elif lib is None:
581 elif lib is None:
583 lib = []
582 lib = []
584 if isinstance(css, string_types):
583 if isinstance(css, string_types):
585 css = [css]
584 css = [css]
586 elif css is None:
585 elif css is None:
587 css = []
586 css = []
588 if not isinstance(lib, (list,tuple)):
587 if not isinstance(lib, (list,tuple)):
589 raise TypeError('expected sequence, got: %r' % lib)
588 raise TypeError('expected sequence, got: %r' % lib)
590 if not isinstance(css, (list,tuple)):
589 if not isinstance(css, (list,tuple)):
591 raise TypeError('expected sequence, got: %r' % css)
590 raise TypeError('expected sequence, got: %r' % css)
592 self.lib = lib
591 self.lib = lib
593 self.css = css
592 self.css = css
594 super(Javascript, self).__init__(data=data, url=url, filename=filename)
593 super(Javascript, self).__init__(data=data, url=url, filename=filename)
595
594
596 def _repr_javascript_(self):
595 def _repr_javascript_(self):
597 r = ''
596 r = ''
598 for c in self.css:
597 for c in self.css:
599 r += css_t % c
598 r += css_t % c
600 for l in self.lib:
599 for l in self.lib:
601 r += lib_t1 % l
600 r += lib_t1 % l
602 r += self.data
601 r += self.data
603 r += lib_t2*len(self.lib)
602 r += lib_t2*len(self.lib)
604 return r
603 return r
605
604
606 # constants for identifying png/jpeg data
605 # constants for identifying png/jpeg data
607 _PNG = b'\x89PNG\r\n\x1a\n'
606 _PNG = b'\x89PNG\r\n\x1a\n'
608 _JPEG = b'\xff\xd8'
607 _JPEG = b'\xff\xd8'
609
608
610 def _pngxy(data):
609 def _pngxy(data):
611 """read the (width, height) from a PNG header"""
610 """read the (width, height) from a PNG header"""
612 ihdr = data.index(b'IHDR')
611 ihdr = data.index(b'IHDR')
613 # next 8 bytes are width/height
612 # next 8 bytes are width/height
614 w4h4 = data[ihdr+4:ihdr+12]
613 w4h4 = data[ihdr+4:ihdr+12]
615 return struct.unpack('>ii', w4h4)
614 return struct.unpack('>ii', w4h4)
616
615
617 def _jpegxy(data):
616 def _jpegxy(data):
618 """read the (width, height) from a JPEG header"""
617 """read the (width, height) from a JPEG header"""
619 # adapted from http://www.64lines.com/jpeg-width-height
618 # adapted from http://www.64lines.com/jpeg-width-height
620
619
621 idx = 4
620 idx = 4
622 while True:
621 while True:
623 block_size = struct.unpack('>H', data[idx:idx+2])[0]
622 block_size = struct.unpack('>H', data[idx:idx+2])[0]
624 idx = idx + block_size
623 idx = idx + block_size
625 if data[idx:idx+2] == b'\xFF\xC0':
624 if data[idx:idx+2] == b'\xFF\xC0':
626 # found Start of Frame
625 # found Start of Frame
627 iSOF = idx
626 iSOF = idx
628 break
627 break
629 else:
628 else:
630 # read another block
629 # read another block
631 idx += 2
630 idx += 2
632
631
633 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
632 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
634 return w, h
633 return w, h
635
634
636 class Image(DisplayObject):
635 class Image(DisplayObject):
637
636
638 _read_flags = 'rb'
637 _read_flags = 'rb'
639 _FMT_JPEG = u'jpeg'
638 _FMT_JPEG = u'jpeg'
640 _FMT_PNG = u'png'
639 _FMT_PNG = u'png'
641 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
640 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
642
641
643 def __init__(self, data=None, url=None, filename=None, format=None,
642 def __init__(self, data=None, url=None, filename=None, format=None,
644 embed=None, width=None, height=None, retina=False,
643 embed=None, width=None, height=None, retina=False,
645 unconfined=False, metadata=None):
644 unconfined=False, metadata=None):
646 """Create a PNG/JPEG image object given raw data.
645 """Create a PNG/JPEG image object given raw data.
647
646
648 When this object is returned by an input cell or passed to the
647 When this object is returned by an input cell or passed to the
649 display function, it will result in the image being displayed
648 display function, it will result in the image being displayed
650 in the frontend.
649 in the frontend.
651
650
652 Parameters
651 Parameters
653 ----------
652 ----------
654 data : unicode, str or bytes
653 data : unicode, str or bytes
655 The raw image data or a URL or filename to load the data from.
654 The raw image data or a URL or filename to load the data from.
656 This always results in embedded image data.
655 This always results in embedded image data.
657 url : unicode
656 url : unicode
658 A URL to download the data from. If you specify `url=`,
657 A URL to download the data from. If you specify `url=`,
659 the image data will not be embedded unless you also specify `embed=True`.
658 the image data will not be embedded unless you also specify `embed=True`.
660 filename : unicode
659 filename : unicode
661 Path to a local file to load the data from.
660 Path to a local file to load the data from.
662 Images from a file are always embedded.
661 Images from a file are always embedded.
663 format : unicode
662 format : unicode
664 The format of the image data (png/jpeg/jpg). If a filename or URL is given
663 The format of the image data (png/jpeg/jpg). If a filename or URL is given
665 for format will be inferred from the filename extension.
664 for format will be inferred from the filename extension.
666 embed : bool
665 embed : bool
667 Should the image data be embedded using a data URI (True) or be
666 Should the image data be embedded using a data URI (True) or be
668 loaded using an <img> tag. Set this to True if you want the image
667 loaded using an <img> tag. Set this to True if you want the image
669 to be viewable later with no internet connection in the notebook.
668 to be viewable later with no internet connection in the notebook.
670
669
671 Default is `True`, unless the keyword argument `url` is set, then
670 Default is `True`, unless the keyword argument `url` is set, then
672 default value is `False`.
671 default value is `False`.
673
672
674 Note that QtConsole is not able to display images if `embed` is set to `False`
673 Note that QtConsole is not able to display images if `embed` is set to `False`
675 width : int
674 width : int
676 Width to which to constrain the image in html
675 Width to which to constrain the image in html
677 height : int
676 height : int
678 Height to which to constrain the image in html
677 Height to which to constrain the image in html
679 retina : bool
678 retina : bool
680 Automatically set the width and height to half of the measured
679 Automatically set the width and height to half of the measured
681 width and height.
680 width and height.
682 This only works for embedded images because it reads the width/height
681 This only works for embedded images because it reads the width/height
683 from image data.
682 from image data.
684 For non-embedded images, you can just set the desired display width
683 For non-embedded images, you can just set the desired display width
685 and height directly.
684 and height directly.
686 unconfined: bool
685 unconfined: bool
687 Set unconfined=True to disable max-width confinement of the image.
686 Set unconfined=True to disable max-width confinement of the image.
688 metadata: dict
687 metadata: dict
689 Specify extra metadata to attach to the image.
688 Specify extra metadata to attach to the image.
690
689
691 Examples
690 Examples
692 --------
691 --------
693 # embedded image data, works in qtconsole and notebook
692 # embedded image data, works in qtconsole and notebook
694 # when passed positionally, the first arg can be any of raw image data,
693 # when passed positionally, the first arg can be any of raw image data,
695 # a URL, or a filename from which to load image data.
694 # a URL, or a filename from which to load image data.
696 # The result is always embedding image data for inline images.
695 # The result is always embedding image data for inline images.
697 Image('http://www.google.fr/images/srpr/logo3w.png')
696 Image('http://www.google.fr/images/srpr/logo3w.png')
698 Image('/path/to/image.jpg')
697 Image('/path/to/image.jpg')
699 Image(b'RAW_PNG_DATA...')
698 Image(b'RAW_PNG_DATA...')
700
699
701 # Specifying Image(url=...) does not embed the image data,
700 # Specifying Image(url=...) does not embed the image data,
702 # it only generates `<img>` tag with a link to the source.
701 # it only generates `<img>` tag with a link to the source.
703 # This will not work in the qtconsole or offline.
702 # This will not work in the qtconsole or offline.
704 Image(url='http://www.google.fr/images/srpr/logo3w.png')
703 Image(url='http://www.google.fr/images/srpr/logo3w.png')
705
704
706 """
705 """
707 if filename is not None:
706 if filename is not None:
708 ext = self._find_ext(filename)
707 ext = self._find_ext(filename)
709 elif url is not None:
708 elif url is not None:
710 ext = self._find_ext(url)
709 ext = self._find_ext(url)
711 elif data is None:
710 elif data is None:
712 raise ValueError("No image data found. Expecting filename, url, or data.")
711 raise ValueError("No image data found. Expecting filename, url, or data.")
713 elif isinstance(data, string_types) and (
712 elif isinstance(data, string_types) and (
714 data.startswith('http') or _safe_exists(data)
713 data.startswith('http') or _safe_exists(data)
715 ):
714 ):
716 ext = self._find_ext(data)
715 ext = self._find_ext(data)
717 else:
716 else:
718 ext = None
717 ext = None
719
718
720 if format is None:
719 if format is None:
721 if ext is not None:
720 if ext is not None:
722 if ext == u'jpg' or ext == u'jpeg':
721 if ext == u'jpg' or ext == u'jpeg':
723 format = self._FMT_JPEG
722 format = self._FMT_JPEG
724 if ext == u'png':
723 if ext == u'png':
725 format = self._FMT_PNG
724 format = self._FMT_PNG
726 else:
725 else:
727 format = ext.lower()
726 format = ext.lower()
728 elif isinstance(data, bytes):
727 elif isinstance(data, bytes):
729 # infer image type from image data header,
728 # infer image type from image data header,
730 # only if format has not been specified.
729 # only if format has not been specified.
731 if data[:2] == _JPEG:
730 if data[:2] == _JPEG:
732 format = self._FMT_JPEG
731 format = self._FMT_JPEG
733
732
734 if format.lower() == 'jpg':
735 # jpg->jpeg
736 format = self._FMT_JPEG
737
738 # failed to detect format, default png
733 # failed to detect format, default png
739 if format is None:
734 if format is None:
740 format = 'png'
735 format = 'png'
741
736
737 if format.lower() == 'jpg':
738 # jpg->jpeg
739 format = self._FMT_JPEG
740
742 self.format = unicode_type(format).lower()
741 self.format = unicode_type(format).lower()
743 self.embed = embed if embed is not None else (url is None)
742 self.embed = embed if embed is not None else (url is None)
744
743
745 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
744 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
746 raise ValueError("Cannot embed the '%s' image format" % (self.format))
745 raise ValueError("Cannot embed the '%s' image format" % (self.format))
747 self.width = width
746 self.width = width
748 self.height = height
747 self.height = height
749 self.retina = retina
748 self.retina = retina
750 self.unconfined = unconfined
749 self.unconfined = unconfined
751 self.metadata = metadata
750 self.metadata = metadata
752 super(Image, self).__init__(data=data, url=url, filename=filename)
751 super(Image, self).__init__(data=data, url=url, filename=filename)
753
752
754 if retina:
753 if retina:
755 self._retina_shape()
754 self._retina_shape()
756
755
757 def _retina_shape(self):
756 def _retina_shape(self):
758 """load pixel-doubled width and height from image data"""
757 """load pixel-doubled width and height from image data"""
759 if not self.embed:
758 if not self.embed:
760 return
759 return
761 if self.format == 'png':
760 if self.format == 'png':
762 w, h = _pngxy(self.data)
761 w, h = _pngxy(self.data)
763 elif self.format == 'jpeg':
762 elif self.format == 'jpeg':
764 w, h = _jpegxy(self.data)
763 w, h = _jpegxy(self.data)
765 else:
764 else:
766 # retina only supports png
765 # retina only supports png
767 return
766 return
768 self.width = w // 2
767 self.width = w // 2
769 self.height = h // 2
768 self.height = h // 2
770
769
771 def reload(self):
770 def reload(self):
772 """Reload the raw data from file or URL."""
771 """Reload the raw data from file or URL."""
773 if self.embed:
772 if self.embed:
774 super(Image,self).reload()
773 super(Image,self).reload()
775 if self.retina:
774 if self.retina:
776 self._retina_shape()
775 self._retina_shape()
777
776
778 def _repr_html_(self):
777 def _repr_html_(self):
779 if not self.embed:
778 if not self.embed:
780 width = height = klass = ''
779 width = height = klass = ''
781 if self.width:
780 if self.width:
782 width = ' width="%d"' % self.width
781 width = ' width="%d"' % self.width
783 if self.height:
782 if self.height:
784 height = ' height="%d"' % self.height
783 height = ' height="%d"' % self.height
785 if self.unconfined:
784 if self.unconfined:
786 klass = ' class="unconfined"'
785 klass = ' class="unconfined"'
787 return u'<img src="{url}"{width}{height}{klass}/>'.format(
786 return u'<img src="{url}"{width}{height}{klass}/>'.format(
788 url=self.url,
787 url=self.url,
789 width=width,
788 width=width,
790 height=height,
789 height=height,
791 klass=klass,
790 klass=klass,
792 )
791 )
793
792
794 def _data_and_metadata(self):
793 def _data_and_metadata(self):
795 """shortcut for returning metadata with shape information, if defined"""
794 """shortcut for returning metadata with shape information, if defined"""
796 md = {}
795 md = {}
797 if self.width:
796 if self.width:
798 md['width'] = self.width
797 md['width'] = self.width
799 if self.height:
798 if self.height:
800 md['height'] = self.height
799 md['height'] = self.height
801 if self.unconfined:
800 if self.unconfined:
802 md['unconfined'] = self.unconfined
801 md['unconfined'] = self.unconfined
803 if self.metadata:
802 if self.metadata:
804 md.update(self.metadata)
803 md.update(self.metadata)
805 if md:
804 if md:
806 return self.data, md
805 return self.data, md
807 else:
806 else:
808 return self.data
807 return self.data
809
808
810 def _repr_png_(self):
809 def _repr_png_(self):
811 if self.embed and self.format == u'png':
810 if self.embed and self.format == u'png':
812 return self._data_and_metadata()
811 return self._data_and_metadata()
813
812
814 def _repr_jpeg_(self):
813 def _repr_jpeg_(self):
815 if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
814 if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
816 return self._data_and_metadata()
815 return self._data_and_metadata()
817
816
818 def _find_ext(self, s):
817 def _find_ext(self, s):
819 return unicode_type(s.split('.')[-1].lower())
818 return unicode_type(s.split('.')[-1].lower())
820
819
821 class Video(DisplayObject):
820 class Video(DisplayObject):
822
821
823 def __init__(self, data=None, url=None, filename=None, embed=None, mimetype=None):
822 def __init__(self, data=None, url=None, filename=None, embed=None, mimetype=None):
824 """Create a video object given raw data or an URL.
823 """Create a video object given raw data or an URL.
825
824
826 When this object is returned by an input cell or passed to the
825 When this object is returned by an input cell or passed to the
827 display function, it will result in the video being displayed
826 display function, it will result in the video being displayed
828 in the frontend.
827 in the frontend.
829
828
830 Parameters
829 Parameters
831 ----------
830 ----------
832 data : unicode, str or bytes
831 data : unicode, str or bytes
833 The raw image data or a URL or filename to load the data from.
832 The raw image data or a URL or filename to load the data from.
834 This always results in embedded image data.
833 This always results in embedded image data.
835 url : unicode
834 url : unicode
836 A URL to download the data from. If you specify `url=`,
835 A URL to download the data from. If you specify `url=`,
837 the image data will not be embedded unless you also specify `embed=True`.
836 the image data will not be embedded unless you also specify `embed=True`.
838 filename : unicode
837 filename : unicode
839 Path to a local file to load the data from.
838 Path to a local file to load the data from.
840 Videos from a file are always embedded.
839 Videos from a file are always embedded.
841 embed : bool
840 embed : bool
842 Should the image data be embedded using a data URI (True) or be
841 Should the image data be embedded using a data URI (True) or be
843 loaded using an <img> tag. Set this to True if you want the image
842 loaded using an <img> tag. Set this to True if you want the image
844 to be viewable later with no internet connection in the notebook.
843 to be viewable later with no internet connection in the notebook.
845
844
846 Default is `True`, unless the keyword argument `url` is set, then
845 Default is `True`, unless the keyword argument `url` is set, then
847 default value is `False`.
846 default value is `False`.
848
847
849 Note that QtConsole is not able to display images if `embed` is set to `False`
848 Note that QtConsole is not able to display images if `embed` is set to `False`
850 mimetype: unicode
849 mimetype: unicode
851 Specify the mimetype in case you load in a encoded video.
850 Specify the mimetype in case you load in a encoded video.
852 Examples
851 Examples
853 --------
852 --------
854 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
853 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
855 Video('path/to/video.mp4')
854 Video('path/to/video.mp4')
856 Video('path/to/video.mp4', embed=False)
855 Video('path/to/video.mp4', embed=False)
857 """
856 """
858 if url is None and (data.startswith('http') or data.startswith('https')):
857 if url is None and (data.startswith('http') or data.startswith('https')):
859 url = data
858 url = data
860 data = None
859 data = None
861 embed = False
860 embed = False
862 elif os.path.exists(data):
861 elif os.path.exists(data):
863 filename = data
862 filename = data
864 data = None
863 data = None
865
864
866 self.mimetype = mimetype
865 self.mimetype = mimetype
867 self.embed = embed if embed is not None else (filename is not None)
866 self.embed = embed if embed is not None else (filename is not None)
868 super(Video, self).__init__(data=data, url=url, filename=filename)
867 super(Video, self).__init__(data=data, url=url, filename=filename)
869
868
870 def _repr_html_(self):
869 def _repr_html_(self):
871 # External URLs and potentially local files are not embedded into the
870 # External URLs and potentially local files are not embedded into the
872 # notebook output.
871 # notebook output.
873 if not self.embed:
872 if not self.embed:
874 url = self.url if self.url is not None else self.filename
873 url = self.url if self.url is not None else self.filename
875 output = """<video src="{0}" controls>
874 output = """<video src="{0}" controls>
876 Your browser does not support the <code>video</code> element.
875 Your browser does not support the <code>video</code> element.
877 </video>""".format(url)
876 </video>""".format(url)
878 return output
877 return output
879 # Embedded videos uses base64 encoded videos.
878 # Embedded videos uses base64 encoded videos.
880 if self.filename is not None:
879 if self.filename is not None:
881 mimetypes.init()
880 mimetypes.init()
882 mimetype, encoding = mimetypes.guess_type(self.filename)
881 mimetype, encoding = mimetypes.guess_type(self.filename)
883
882
884 video = open(self.filename, 'rb').read()
883 video = open(self.filename, 'rb').read()
885 video_encoded = video.encode('base64')
884 video_encoded = video.encode('base64')
886 else:
885 else:
887 video_encoded = self.data
886 video_encoded = self.data
888 mimetype = self.mimetype
887 mimetype = self.mimetype
889 output = """<video controls>
888 output = """<video controls>
890 <source src="data:{0};base64,{1}" type="{0}">
889 <source src="data:{0};base64,{1}" type="{0}">
891 Your browser does not support the video tag.
890 Your browser does not support the video tag.
892 </video>""".format(mimetype, video_encoded)
891 </video>""".format(mimetype, video_encoded)
893 return output
892 return output
894
893
895 def reload(self):
894 def reload(self):
896 # TODO
895 # TODO
897 pass
896 pass
898
897
899 def _repr_png_(self):
898 def _repr_png_(self):
900 # TODO
899 # TODO
901 pass
900 pass
902 def _repr_jpeg_(self):
901 def _repr_jpeg_(self):
903 # TODO
902 # TODO
904 pass
903 pass
905
904
906 def clear_output(wait=False):
905 def clear_output(wait=False):
907 """Clear the output of the current cell receiving output.
906 """Clear the output of the current cell receiving output.
908
907
909 Parameters
908 Parameters
910 ----------
909 ----------
911 wait : bool [default: false]
910 wait : bool [default: false]
912 Wait to clear the output until new output is available to replace it."""
911 Wait to clear the output until new output is available to replace it."""
913 from IPython.core.interactiveshell import InteractiveShell
912 from IPython.core.interactiveshell import InteractiveShell
914 if InteractiveShell.initialized():
913 if InteractiveShell.initialized():
915 InteractiveShell.instance().display_pub.clear_output(wait)
914 InteractiveShell.instance().display_pub.clear_output(wait)
916 else:
915 else:
917 from IPython.utils import io
916 from IPython.utils import io
918 print('\033[2K\r', file=io.stdout, end='')
917 print('\033[2K\r', file=io.stdout, end='')
919 io.stdout.flush()
918 io.stdout.flush()
920 print('\033[2K\r', file=io.stderr, end='')
919 print('\033[2K\r', file=io.stderr, end='')
921 io.stderr.flush()
920 io.stderr.flush()
922
921
923
922
924 @skip_doctest
923 @skip_doctest
925 def set_matplotlib_formats(*formats, **kwargs):
924 def set_matplotlib_formats(*formats, **kwargs):
926 """Select figure formats for the inline backend. Optionally pass quality for JPEG.
925 """Select figure formats for the inline backend. Optionally pass quality for JPEG.
927
926
928 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
927 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
929
928
930 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
929 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
931
930
932 To set this in your config files use the following::
931 To set this in your config files use the following::
933
932
934 c.InlineBackend.figure_formats = {'png', 'jpeg'}
933 c.InlineBackend.figure_formats = {'png', 'jpeg'}
935 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
934 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
936
935
937 Parameters
936 Parameters
938 ----------
937 ----------
939 *formats : strs
938 *formats : strs
940 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
939 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
941 **kwargs :
940 **kwargs :
942 Keyword args will be relayed to ``figure.canvas.print_figure``.
941 Keyword args will be relayed to ``figure.canvas.print_figure``.
943 """
942 """
944 from IPython.core.interactiveshell import InteractiveShell
943 from IPython.core.interactiveshell import InteractiveShell
945 from IPython.core.pylabtools import select_figure_formats
944 from IPython.core.pylabtools import select_figure_formats
946 # build kwargs, starting with InlineBackend config
945 # build kwargs, starting with InlineBackend config
947 kw = {}
946 kw = {}
948 from ipykernel.pylab.config import InlineBackend
947 from ipykernel.pylab.config import InlineBackend
949 cfg = InlineBackend.instance()
948 cfg = InlineBackend.instance()
950 kw.update(cfg.print_figure_kwargs)
949 kw.update(cfg.print_figure_kwargs)
951 kw.update(**kwargs)
950 kw.update(**kwargs)
952 shell = InteractiveShell.instance()
951 shell = InteractiveShell.instance()
953 select_figure_formats(shell, formats, **kw)
952 select_figure_formats(shell, formats, **kw)
954
953
955 @skip_doctest
954 @skip_doctest
956 def set_matplotlib_close(close=True):
955 def set_matplotlib_close(close=True):
957 """Set whether the inline backend closes all figures automatically or not.
956 """Set whether the inline backend closes all figures automatically or not.
958
957
959 By default, the inline backend used in the IPython Notebook will close all
958 By default, the inline backend used in the IPython Notebook will close all
960 matplotlib figures automatically after each cell is run. This means that
959 matplotlib figures automatically after each cell is run. This means that
961 plots in different cells won't interfere. Sometimes, you may want to make
960 plots in different cells won't interfere. Sometimes, you may want to make
962 a plot in one cell and then refine it in later cells. This can be accomplished
961 a plot in one cell and then refine it in later cells. This can be accomplished
963 by::
962 by::
964
963
965 In [1]: set_matplotlib_close(False)
964 In [1]: set_matplotlib_close(False)
966
965
967 To set this in your config files use the following::
966 To set this in your config files use the following::
968
967
969 c.InlineBackend.close_figures = False
968 c.InlineBackend.close_figures = False
970
969
971 Parameters
970 Parameters
972 ----------
971 ----------
973 close : bool
972 close : bool
974 Should all matplotlib figures be automatically closed after each cell is
973 Should all matplotlib figures be automatically closed after each cell is
975 run?
974 run?
976 """
975 """
977 from ipykernel.pylab.config import InlineBackend
976 from ipykernel.pylab.config import InlineBackend
978 cfg = InlineBackend.instance()
977 cfg = InlineBackend.instance()
979 cfg.close_figures = close
978 cfg.close_figures = close
980
979
@@ -1,152 +1,155 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 import nose.tools as nt
8 import nose.tools as nt
9
9
10 from IPython.core import display
10 from IPython.core import display
11 from IPython.core.getipython import get_ipython
11 from IPython.core.getipython import get_ipython
12 from IPython import paths as ipath
12 from IPython import paths as ipath
13
13
14 import IPython.testing.decorators as dec
14 import IPython.testing.decorators as dec
15
15
16 def test_image_size():
16 def test_image_size():
17 """Simple test for display.Image(args, width=x,height=y)"""
17 """Simple test for display.Image(args, width=x,height=y)"""
18 thisurl = 'http://www.google.fr/images/srpr/logo3w.png'
18 thisurl = 'http://www.google.fr/images/srpr/logo3w.png'
19 img = display.Image(url=thisurl, width=200, height=200)
19 img = display.Image(url=thisurl, width=200, height=200)
20 nt.assert_equal(u'<img src="%s" width="200" height="200"/>' % (thisurl), img._repr_html_())
20 nt.assert_equal(u'<img src="%s" width="200" height="200"/>' % (thisurl), img._repr_html_())
21 img = display.Image(url=thisurl, width=200)
21 img = display.Image(url=thisurl, width=200)
22 nt.assert_equal(u'<img src="%s" width="200"/>' % (thisurl), img._repr_html_())
22 nt.assert_equal(u'<img src="%s" width="200"/>' % (thisurl), img._repr_html_())
23 img = display.Image(url=thisurl)
23 img = display.Image(url=thisurl)
24 nt.assert_equal(u'<img src="%s"/>' % (thisurl), img._repr_html_())
24 nt.assert_equal(u'<img src="%s"/>' % (thisurl), img._repr_html_())
25 img = display.Image(url=thisurl, unconfined=True)
25 img = display.Image(url=thisurl, unconfined=True)
26 nt.assert_equal(u'<img src="%s" class="unconfined"/>' % (thisurl), img._repr_html_())
26 nt.assert_equal(u'<img src="%s" class="unconfined"/>' % (thisurl), img._repr_html_())
27
27
28 def test_retina_png():
28 def test_retina_png():
29 here = os.path.dirname(__file__)
29 here = os.path.dirname(__file__)
30 img = display.Image(os.path.join(here, "2x2.png"), retina=True)
30 img = display.Image(os.path.join(here, "2x2.png"), retina=True)
31 nt.assert_equal(img.height, 1)
31 nt.assert_equal(img.height, 1)
32 nt.assert_equal(img.width, 1)
32 nt.assert_equal(img.width, 1)
33 data, md = img._repr_png_()
33 data, md = img._repr_png_()
34 nt.assert_equal(md['width'], 1)
34 nt.assert_equal(md['width'], 1)
35 nt.assert_equal(md['height'], 1)
35 nt.assert_equal(md['height'], 1)
36
36
37 def test_retina_jpeg():
37 def test_retina_jpeg():
38 here = os.path.dirname(__file__)
38 here = os.path.dirname(__file__)
39 img = display.Image(os.path.join(here, "2x2.jpg"), retina=True)
39 img = display.Image(os.path.join(here, "2x2.jpg"), retina=True)
40 nt.assert_equal(img.height, 1)
40 nt.assert_equal(img.height, 1)
41 nt.assert_equal(img.width, 1)
41 nt.assert_equal(img.width, 1)
42 data, md = img._repr_jpeg_()
42 data, md = img._repr_jpeg_()
43 nt.assert_equal(md['width'], 1)
43 nt.assert_equal(md['width'], 1)
44 nt.assert_equal(md['height'], 1)
44 nt.assert_equal(md['height'], 1)
45
45
46 def test_base64image():
47 display.Image("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94BCRQnOqNu0b4AAAAKSURBVAjXY2AAAAACAAHiIbwzAAAAAElFTkSuQmCC")
48
46 def test_image_filename_defaults():
49 def test_image_filename_defaults():
47 '''test format constraint, and validity of jpeg and png'''
50 '''test format constraint, and validity of jpeg and png'''
48 tpath = ipath.get_ipython_package_dir()
51 tpath = ipath.get_ipython_package_dir()
49 nt.assert_raises(ValueError, display.Image, filename=os.path.join(tpath, 'testing/tests/badformat.gif'),
52 nt.assert_raises(ValueError, display.Image, filename=os.path.join(tpath, 'testing/tests/badformat.gif'),
50 embed=True)
53 embed=True)
51 nt.assert_raises(ValueError, display.Image)
54 nt.assert_raises(ValueError, display.Image)
52 nt.assert_raises(ValueError, display.Image, data='this is not an image', format='badformat', embed=True)
55 nt.assert_raises(ValueError, display.Image, data='this is not an image', format='badformat', embed=True)
53 # check boths paths to allow packages to test at build and install time
56 # check boths paths to allow packages to test at build and install time
54 imgfile = os.path.join(tpath, 'core/tests/2x2.png')
57 imgfile = os.path.join(tpath, 'core/tests/2x2.png')
55 img = display.Image(filename=imgfile)
58 img = display.Image(filename=imgfile)
56 nt.assert_equal('png', img.format)
59 nt.assert_equal('png', img.format)
57 nt.assert_is_not_none(img._repr_png_())
60 nt.assert_is_not_none(img._repr_png_())
58 img = display.Image(filename=os.path.join(tpath, 'testing/tests/logo.jpg'), embed=False)
61 img = display.Image(filename=os.path.join(tpath, 'testing/tests/logo.jpg'), embed=False)
59 nt.assert_equal('jpeg', img.format)
62 nt.assert_equal('jpeg', img.format)
60 nt.assert_is_none(img._repr_jpeg_())
63 nt.assert_is_none(img._repr_jpeg_())
61
64
62 def _get_inline_config():
65 def _get_inline_config():
63 from ipykernel.pylab.config import InlineBackend
66 from ipykernel.pylab.config import InlineBackend
64 return InlineBackend.instance()
67 return InlineBackend.instance()
65
68
66 @dec.skip_without('matplotlib')
69 @dec.skip_without('matplotlib')
67 def test_set_matplotlib_close():
70 def test_set_matplotlib_close():
68 cfg = _get_inline_config()
71 cfg = _get_inline_config()
69 cfg.close_figures = False
72 cfg.close_figures = False
70 display.set_matplotlib_close()
73 display.set_matplotlib_close()
71 assert cfg.close_figures
74 assert cfg.close_figures
72 display.set_matplotlib_close(False)
75 display.set_matplotlib_close(False)
73 assert not cfg.close_figures
76 assert not cfg.close_figures
74
77
75 _fmt_mime_map = {
78 _fmt_mime_map = {
76 'png': 'image/png',
79 'png': 'image/png',
77 'jpeg': 'image/jpeg',
80 'jpeg': 'image/jpeg',
78 'pdf': 'application/pdf',
81 'pdf': 'application/pdf',
79 'retina': 'image/png',
82 'retina': 'image/png',
80 'svg': 'image/svg+xml',
83 'svg': 'image/svg+xml',
81 }
84 }
82
85
83 @dec.skip_without('matplotlib')
86 @dec.skip_without('matplotlib')
84 def test_set_matplotlib_formats():
87 def test_set_matplotlib_formats():
85 from matplotlib.figure import Figure
88 from matplotlib.figure import Figure
86 formatters = get_ipython().display_formatter.formatters
89 formatters = get_ipython().display_formatter.formatters
87 for formats in [
90 for formats in [
88 ('png',),
91 ('png',),
89 ('pdf', 'svg'),
92 ('pdf', 'svg'),
90 ('jpeg', 'retina', 'png'),
93 ('jpeg', 'retina', 'png'),
91 (),
94 (),
92 ]:
95 ]:
93 active_mimes = {_fmt_mime_map[fmt] for fmt in formats}
96 active_mimes = {_fmt_mime_map[fmt] for fmt in formats}
94 display.set_matplotlib_formats(*formats)
97 display.set_matplotlib_formats(*formats)
95 for mime, f in formatters.items():
98 for mime, f in formatters.items():
96 if mime in active_mimes:
99 if mime in active_mimes:
97 nt.assert_in(Figure, f)
100 nt.assert_in(Figure, f)
98 else:
101 else:
99 nt.assert_not_in(Figure, f)
102 nt.assert_not_in(Figure, f)
100
103
101 @dec.skip_without('matplotlib')
104 @dec.skip_without('matplotlib')
102 def test_set_matplotlib_formats_kwargs():
105 def test_set_matplotlib_formats_kwargs():
103 from matplotlib.figure import Figure
106 from matplotlib.figure import Figure
104 ip = get_ipython()
107 ip = get_ipython()
105 cfg = _get_inline_config()
108 cfg = _get_inline_config()
106 cfg.print_figure_kwargs.update(dict(foo='bar'))
109 cfg.print_figure_kwargs.update(dict(foo='bar'))
107 kwargs = dict(quality=10)
110 kwargs = dict(quality=10)
108 display.set_matplotlib_formats('png', **kwargs)
111 display.set_matplotlib_formats('png', **kwargs)
109 formatter = ip.display_formatter.formatters['image/png']
112 formatter = ip.display_formatter.formatters['image/png']
110 f = formatter.lookup_by_type(Figure)
113 f = formatter.lookup_by_type(Figure)
111 cell = f.__closure__[0].cell_contents
114 cell = f.__closure__[0].cell_contents
112 expected = kwargs
115 expected = kwargs
113 expected.update(cfg.print_figure_kwargs)
116 expected.update(cfg.print_figure_kwargs)
114 nt.assert_equal(cell, expected)
117 nt.assert_equal(cell, expected)
115
118
116 def test_displayobject_repr():
119 def test_displayobject_repr():
117 h = display.HTML('<br />')
120 h = display.HTML('<br />')
118 nt.assert_equal(repr(h), '<IPython.core.display.HTML object>')
121 nt.assert_equal(repr(h), '<IPython.core.display.HTML object>')
119 h._show_mem_addr = True
122 h._show_mem_addr = True
120 nt.assert_equal(repr(h), object.__repr__(h))
123 nt.assert_equal(repr(h), object.__repr__(h))
121 h._show_mem_addr = False
124 h._show_mem_addr = False
122 nt.assert_equal(repr(h), '<IPython.core.display.HTML object>')
125 nt.assert_equal(repr(h), '<IPython.core.display.HTML object>')
123
126
124 j = display.Javascript('')
127 j = display.Javascript('')
125 nt.assert_equal(repr(j), '<IPython.core.display.Javascript object>')
128 nt.assert_equal(repr(j), '<IPython.core.display.Javascript object>')
126 j._show_mem_addr = True
129 j._show_mem_addr = True
127 nt.assert_equal(repr(j), object.__repr__(j))
130 nt.assert_equal(repr(j), object.__repr__(j))
128 j._show_mem_addr = False
131 j._show_mem_addr = False
129 nt.assert_equal(repr(j), '<IPython.core.display.Javascript object>')
132 nt.assert_equal(repr(j), '<IPython.core.display.Javascript object>')
130
133
131 def test_json():
134 def test_json():
132 d = {'a': 5}
135 d = {'a': 5}
133 lis = [d]
136 lis = [d]
134 j = display.JSON(d)
137 j = display.JSON(d)
135 nt.assert_equal(j._repr_json_(), d)
138 nt.assert_equal(j._repr_json_(), d)
136
139
137 with warnings.catch_warnings(record=True) as w:
140 with warnings.catch_warnings(record=True) as w:
138 warnings.simplefilter("always")
141 warnings.simplefilter("always")
139 j = display.JSON(json.dumps(d))
142 j = display.JSON(json.dumps(d))
140 nt.assert_equal(len(w), 1)
143 nt.assert_equal(len(w), 1)
141 nt.assert_equal(j._repr_json_(), d)
144 nt.assert_equal(j._repr_json_(), d)
142
145
143 j = display.JSON(lis)
146 j = display.JSON(lis)
144 nt.assert_equal(j._repr_json_(), lis)
147 nt.assert_equal(j._repr_json_(), lis)
145
148
146 with warnings.catch_warnings(record=True) as w:
149 with warnings.catch_warnings(record=True) as w:
147 warnings.simplefilter("always")
150 warnings.simplefilter("always")
148 j = display.JSON(json.dumps(lis))
151 j = display.JSON(json.dumps(lis))
149 nt.assert_equal(len(w), 1)
152 nt.assert_equal(len(w), 1)
150 nt.assert_equal(j._repr_json_(), lis)
153 nt.assert_equal(j._repr_json_(), lis)
151
154
152
155
General Comments 0
You need to be logged in to leave comments. Login now