##// END OF EJS Templates
validate that text display data is text...
MinRK -
Show More
@@ -1,679 +1,690
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 Authors:
4 Authors:
5
5
6 * Brian Granger
6 * Brian Granger
7 """
7 """
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2013 The IPython Development Team
10 # Copyright (C) 2013 The IPython Development Team
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 from __future__ import print_function
20 from __future__ import print_function
21
21
22 import os
22 import os
23 import struct
23 import struct
24
24
25 from IPython.utils.py3compat import (string_types, cast_bytes_py2, cast_unicode,
25 from IPython.utils.py3compat import (string_types, cast_bytes_py2, cast_unicode,
26 unicode_type)
26 unicode_type)
27
27
28 from .displaypub import publish_display_data
28 from .displaypub import publish_display_data
29
29
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31 # utility functions
31 # utility functions
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33
33
34 def _safe_exists(path):
34 def _safe_exists(path):
35 """Check path, but don't let exceptions raise"""
35 """Check path, but don't let exceptions raise"""
36 try:
36 try:
37 return os.path.exists(path)
37 return os.path.exists(path)
38 except Exception:
38 except Exception:
39 return False
39 return False
40
40
41 def _merge(d1, d2):
41 def _merge(d1, d2):
42 """Like update, but merges sub-dicts instead of clobbering at the top level.
42 """Like update, but merges sub-dicts instead of clobbering at the top level.
43
43
44 Updates d1 in-place
44 Updates d1 in-place
45 """
45 """
46
46
47 if not isinstance(d2, dict) or not isinstance(d1, dict):
47 if not isinstance(d2, dict) or not isinstance(d1, dict):
48 return d2
48 return d2
49 for key, value in d2.items():
49 for key, value in d2.items():
50 d1[key] = _merge(d1.get(key), value)
50 d1[key] = _merge(d1.get(key), value)
51 return d1
51 return d1
52
52
53 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
53 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
54 """internal implementation of all display_foo methods
54 """internal implementation of all display_foo methods
55
55
56 Parameters
56 Parameters
57 ----------
57 ----------
58 mimetype : str
58 mimetype : str
59 The mimetype to be published (e.g. 'image/png')
59 The mimetype to be published (e.g. 'image/png')
60 objs : tuple of objects
60 objs : tuple of objects
61 The Python objects to display, or if raw=True raw text data to
61 The Python objects to display, or if raw=True raw text data to
62 display.
62 display.
63 raw : bool
63 raw : bool
64 Are the data objects raw data or Python objects that need to be
64 Are the data objects raw data or Python objects that need to be
65 formatted before display? [default: False]
65 formatted before display? [default: False]
66 metadata : dict (optional)
66 metadata : dict (optional)
67 Metadata to be associated with the specific mimetype output.
67 Metadata to be associated with the specific mimetype output.
68 """
68 """
69 if metadata:
69 if metadata:
70 metadata = {mimetype: metadata}
70 metadata = {mimetype: metadata}
71 if raw:
71 if raw:
72 # turn list of pngdata into list of { 'image/png': pngdata }
72 # turn list of pngdata into list of { 'image/png': pngdata }
73 objs = [ {mimetype: obj} for obj in objs ]
73 objs = [ {mimetype: obj} for obj in objs ]
74 display(*objs, raw=raw, metadata=metadata, include=[mimetype])
74 display(*objs, raw=raw, metadata=metadata, include=[mimetype])
75
75
76 #-----------------------------------------------------------------------------
76 #-----------------------------------------------------------------------------
77 # Main functions
77 # Main functions
78 #-----------------------------------------------------------------------------
78 #-----------------------------------------------------------------------------
79
79
80 def display(*objs, **kwargs):
80 def display(*objs, **kwargs):
81 """Display a Python object in all frontends.
81 """Display a Python object in all frontends.
82
82
83 By default all representations will be computed and sent to the frontends.
83 By default all representations will be computed and sent to the frontends.
84 Frontends can decide which representation is used and how.
84 Frontends can decide which representation is used and how.
85
85
86 Parameters
86 Parameters
87 ----------
87 ----------
88 objs : tuple of objects
88 objs : tuple of objects
89 The Python objects to display.
89 The Python objects to display.
90 raw : bool, optional
90 raw : bool, optional
91 Are the objects to be displayed already mimetype-keyed dicts of raw display data,
91 Are the objects to be displayed already mimetype-keyed dicts of raw display data,
92 or Python objects that need to be formatted before display? [default: False]
92 or Python objects that need to be formatted before display? [default: False]
93 include : list or tuple, optional
93 include : list or tuple, optional
94 A list of format type strings (MIME types) to include in the
94 A list of format type strings (MIME types) to include in the
95 format data dict. If this is set *only* the format types included
95 format data dict. If this is set *only* the format types included
96 in this list will be computed.
96 in this list will be computed.
97 exclude : list or tuple, optional
97 exclude : list or tuple, optional
98 A list of format type strings (MIME types) to exclude in the format
98 A list of format type strings (MIME types) to exclude in the format
99 data dict. If this is set all format types will be computed,
99 data dict. If this is set all format types will be computed,
100 except for those included in this argument.
100 except for those included in this argument.
101 metadata : dict, optional
101 metadata : dict, optional
102 A dictionary of metadata to associate with the output.
102 A dictionary of metadata to associate with the output.
103 mime-type keys in this dictionary will be associated with the individual
103 mime-type keys in this dictionary will be associated with the individual
104 representation formats, if they exist.
104 representation formats, if they exist.
105 """
105 """
106 raw = kwargs.get('raw', False)
106 raw = kwargs.get('raw', False)
107 include = kwargs.get('include')
107 include = kwargs.get('include')
108 exclude = kwargs.get('exclude')
108 exclude = kwargs.get('exclude')
109 metadata = kwargs.get('metadata')
109 metadata = kwargs.get('metadata')
110
110
111 from IPython.core.interactiveshell import InteractiveShell
111 from IPython.core.interactiveshell import InteractiveShell
112
112
113 if raw:
113 if raw:
114 for obj in objs:
114 for obj in objs:
115 publish_display_data('display', obj, metadata)
115 publish_display_data('display', obj, metadata)
116 else:
116 else:
117 format = InteractiveShell.instance().display_formatter.format
117 format = InteractiveShell.instance().display_formatter.format
118 for obj in objs:
118 for obj in objs:
119 format_dict, md_dict = format(obj, include=include, exclude=exclude)
119 format_dict, md_dict = format(obj, include=include, exclude=exclude)
120 if metadata:
120 if metadata:
121 # kwarg-specified metadata gets precedence
121 # kwarg-specified metadata gets precedence
122 _merge(md_dict, metadata)
122 _merge(md_dict, metadata)
123 publish_display_data('display', format_dict, md_dict)
123 publish_display_data('display', format_dict, md_dict)
124
124
125
125
126 def display_pretty(*objs, **kwargs):
126 def display_pretty(*objs, **kwargs):
127 """Display the pretty (default) representation of an object.
127 """Display the pretty (default) representation of an object.
128
128
129 Parameters
129 Parameters
130 ----------
130 ----------
131 objs : tuple of objects
131 objs : tuple of objects
132 The Python objects to display, or if raw=True raw text data to
132 The Python objects to display, or if raw=True raw text data to
133 display.
133 display.
134 raw : bool
134 raw : bool
135 Are the data objects raw data or Python objects that need to be
135 Are the data objects raw data or Python objects that need to be
136 formatted before display? [default: False]
136 formatted before display? [default: False]
137 metadata : dict (optional)
137 metadata : dict (optional)
138 Metadata to be associated with the specific mimetype output.
138 Metadata to be associated with the specific mimetype output.
139 """
139 """
140 _display_mimetype('text/plain', objs, **kwargs)
140 _display_mimetype('text/plain', objs, **kwargs)
141
141
142
142
143 def display_html(*objs, **kwargs):
143 def display_html(*objs, **kwargs):
144 """Display the HTML representation of an object.
144 """Display the HTML representation of an object.
145
145
146 Parameters
146 Parameters
147 ----------
147 ----------
148 objs : tuple of objects
148 objs : tuple of objects
149 The Python objects to display, or if raw=True raw HTML data to
149 The Python objects to display, or if raw=True raw HTML data to
150 display.
150 display.
151 raw : bool
151 raw : bool
152 Are the data objects raw data or Python objects that need to be
152 Are the data objects raw data or Python objects that need to be
153 formatted before display? [default: False]
153 formatted before display? [default: False]
154 metadata : dict (optional)
154 metadata : dict (optional)
155 Metadata to be associated with the specific mimetype output.
155 Metadata to be associated with the specific mimetype output.
156 """
156 """
157 _display_mimetype('text/html', objs, **kwargs)
157 _display_mimetype('text/html', objs, **kwargs)
158
158
159
159
160 def display_svg(*objs, **kwargs):
160 def display_svg(*objs, **kwargs):
161 """Display the SVG representation of an object.
161 """Display the SVG representation of an object.
162
162
163 Parameters
163 Parameters
164 ----------
164 ----------
165 objs : tuple of objects
165 objs : tuple of objects
166 The Python objects to display, or if raw=True raw svg data to
166 The Python objects to display, or if raw=True raw svg data to
167 display.
167 display.
168 raw : bool
168 raw : bool
169 Are the data objects raw data or Python objects that need to be
169 Are the data objects raw data or Python objects that need to be
170 formatted before display? [default: False]
170 formatted before display? [default: False]
171 metadata : dict (optional)
171 metadata : dict (optional)
172 Metadata to be associated with the specific mimetype output.
172 Metadata to be associated with the specific mimetype output.
173 """
173 """
174 _display_mimetype('image/svg+xml', objs, **kwargs)
174 _display_mimetype('image/svg+xml', objs, **kwargs)
175
175
176
176
177 def display_png(*objs, **kwargs):
177 def display_png(*objs, **kwargs):
178 """Display the PNG representation of an object.
178 """Display the PNG representation of an object.
179
179
180 Parameters
180 Parameters
181 ----------
181 ----------
182 objs : tuple of objects
182 objs : tuple of objects
183 The Python objects to display, or if raw=True raw png data to
183 The Python objects to display, or if raw=True raw png data to
184 display.
184 display.
185 raw : bool
185 raw : bool
186 Are the data objects raw data or Python objects that need to be
186 Are the data objects raw data or Python objects that need to be
187 formatted before display? [default: False]
187 formatted before display? [default: False]
188 metadata : dict (optional)
188 metadata : dict (optional)
189 Metadata to be associated with the specific mimetype output.
189 Metadata to be associated with the specific mimetype output.
190 """
190 """
191 _display_mimetype('image/png', objs, **kwargs)
191 _display_mimetype('image/png', objs, **kwargs)
192
192
193
193
194 def display_jpeg(*objs, **kwargs):
194 def display_jpeg(*objs, **kwargs):
195 """Display the JPEG representation of an object.
195 """Display the JPEG representation of an object.
196
196
197 Parameters
197 Parameters
198 ----------
198 ----------
199 objs : tuple of objects
199 objs : tuple of objects
200 The Python objects to display, or if raw=True raw JPEG data to
200 The Python objects to display, or if raw=True raw JPEG data to
201 display.
201 display.
202 raw : bool
202 raw : bool
203 Are the data objects raw data or Python objects that need to be
203 Are the data objects raw data or Python objects that need to be
204 formatted before display? [default: False]
204 formatted before display? [default: False]
205 metadata : dict (optional)
205 metadata : dict (optional)
206 Metadata to be associated with the specific mimetype output.
206 Metadata to be associated with the specific mimetype output.
207 """
207 """
208 _display_mimetype('image/jpeg', objs, **kwargs)
208 _display_mimetype('image/jpeg', objs, **kwargs)
209
209
210
210
211 def display_latex(*objs, **kwargs):
211 def display_latex(*objs, **kwargs):
212 """Display the LaTeX representation of an object.
212 """Display the LaTeX representation of an object.
213
213
214 Parameters
214 Parameters
215 ----------
215 ----------
216 objs : tuple of objects
216 objs : tuple of objects
217 The Python objects to display, or if raw=True raw latex data to
217 The Python objects to display, or if raw=True raw latex data to
218 display.
218 display.
219 raw : bool
219 raw : bool
220 Are the data objects raw data or Python objects that need to be
220 Are the data objects raw data or Python objects that need to be
221 formatted before display? [default: False]
221 formatted before display? [default: False]
222 metadata : dict (optional)
222 metadata : dict (optional)
223 Metadata to be associated with the specific mimetype output.
223 Metadata to be associated with the specific mimetype output.
224 """
224 """
225 _display_mimetype('text/latex', objs, **kwargs)
225 _display_mimetype('text/latex', objs, **kwargs)
226
226
227
227
228 def display_json(*objs, **kwargs):
228 def display_json(*objs, **kwargs):
229 """Display the JSON representation of an object.
229 """Display the JSON representation of an object.
230
230
231 Note that not many frontends support displaying JSON.
231 Note that not many frontends support displaying JSON.
232
232
233 Parameters
233 Parameters
234 ----------
234 ----------
235 objs : tuple of objects
235 objs : tuple of objects
236 The Python objects to display, or if raw=True raw json data to
236 The Python objects to display, or if raw=True raw json data to
237 display.
237 display.
238 raw : bool
238 raw : bool
239 Are the data objects raw data or Python objects that need to be
239 Are the data objects raw data or Python objects that need to be
240 formatted before display? [default: False]
240 formatted before display? [default: False]
241 metadata : dict (optional)
241 metadata : dict (optional)
242 Metadata to be associated with the specific mimetype output.
242 Metadata to be associated with the specific mimetype output.
243 """
243 """
244 _display_mimetype('application/json', objs, **kwargs)
244 _display_mimetype('application/json', objs, **kwargs)
245
245
246
246
247 def display_javascript(*objs, **kwargs):
247 def display_javascript(*objs, **kwargs):
248 """Display the Javascript representation of an object.
248 """Display the Javascript representation of an object.
249
249
250 Parameters
250 Parameters
251 ----------
251 ----------
252 objs : tuple of objects
252 objs : tuple of objects
253 The Python objects to display, or if raw=True raw javascript data to
253 The Python objects to display, or if raw=True raw javascript data to
254 display.
254 display.
255 raw : bool
255 raw : bool
256 Are the data objects raw data or Python objects that need to be
256 Are the data objects raw data or Python objects that need to be
257 formatted before display? [default: False]
257 formatted before display? [default: False]
258 metadata : dict (optional)
258 metadata : dict (optional)
259 Metadata to be associated with the specific mimetype output.
259 Metadata to be associated with the specific mimetype output.
260 """
260 """
261 _display_mimetype('application/javascript', objs, **kwargs)
261 _display_mimetype('application/javascript', objs, **kwargs)
262
262
263 #-----------------------------------------------------------------------------
263 #-----------------------------------------------------------------------------
264 # Smart classes
264 # Smart classes
265 #-----------------------------------------------------------------------------
265 #-----------------------------------------------------------------------------
266
266
267
267
268 class DisplayObject(object):
268 class DisplayObject(object):
269 """An object that wraps data to be displayed."""
269 """An object that wraps data to be displayed."""
270
270
271 _read_flags = 'r'
271 _read_flags = 'r'
272
272
273 def __init__(self, data=None, url=None, filename=None):
273 def __init__(self, data=None, url=None, filename=None):
274 """Create a display object given raw data.
274 """Create a display object given raw data.
275
275
276 When this object is returned by an expression or passed to the
276 When this object is returned by an expression or passed to the
277 display function, it will result in the data being displayed
277 display function, it will result in the data being displayed
278 in the frontend. The MIME type of the data should match the
278 in the frontend. The MIME type of the data should match the
279 subclasses used, so the Png subclass should be used for 'image/png'
279 subclasses used, so the Png subclass should be used for 'image/png'
280 data. If the data is a URL, the data will first be downloaded
280 data. If the data is a URL, the data will first be downloaded
281 and then displayed. If
281 and then displayed. If
282
282
283 Parameters
283 Parameters
284 ----------
284 ----------
285 data : unicode, str or bytes
285 data : unicode, str or bytes
286 The raw data or a URL or file to load the data from
286 The raw data or a URL or file to load the data from
287 url : unicode
287 url : unicode
288 A URL to download the data from.
288 A URL to download the data from.
289 filename : unicode
289 filename : unicode
290 Path to a local file to load the data from.
290 Path to a local file to load the data from.
291 """
291 """
292 if data is not None and isinstance(data, string_types):
292 if data is not None and isinstance(data, string_types):
293 if data.startswith('http') and url is None:
293 if data.startswith('http') and url is None:
294 url = data
294 url = data
295 filename = None
295 filename = None
296 data = None
296 data = None
297 elif _safe_exists(data) and filename is None:
297 elif _safe_exists(data) and filename is None:
298 url = None
298 url = None
299 filename = data
299 filename = data
300 data = None
300 data = None
301
301
302 self.data = data
302 self.data = data
303 self.url = url
303 self.url = url
304 self.filename = None if filename is None else unicode_type(filename)
304 self.filename = None if filename is None else unicode_type(filename)
305
305
306 self.reload()
306 self.reload()
307 self._check_data()
308
309 def _check_data(self):
310 """Override in subclasses if there's something to check."""
311 pass
307
312
308 def reload(self):
313 def reload(self):
309 """Reload the raw data from file or URL."""
314 """Reload the raw data from file or URL."""
310 if self.filename is not None:
315 if self.filename is not None:
311 with open(self.filename, self._read_flags) as f:
316 with open(self.filename, self._read_flags) as f:
312 self.data = f.read()
317 self.data = f.read()
313 elif self.url is not None:
318 elif self.url is not None:
314 try:
319 try:
315 try:
320 try:
316 from urllib.request import urlopen # Py3
321 from urllib.request import urlopen # Py3
317 except ImportError:
322 except ImportError:
318 from urllib2 import urlopen
323 from urllib2 import urlopen
319 response = urlopen(self.url)
324 response = urlopen(self.url)
320 self.data = response.read()
325 self.data = response.read()
321 # extract encoding from header, if there is one:
326 # extract encoding from header, if there is one:
322 encoding = None
327 encoding = None
323 for sub in response.headers['content-type'].split(';'):
328 for sub in response.headers['content-type'].split(';'):
324 sub = sub.strip()
329 sub = sub.strip()
325 if sub.startswith('charset'):
330 if sub.startswith('charset'):
326 encoding = sub.split('=')[-1].strip()
331 encoding = sub.split('=')[-1].strip()
327 break
332 break
328 # decode data, if an encoding was specified
333 # decode data, if an encoding was specified
329 if encoding:
334 if encoding:
330 self.data = self.data.decode(encoding, 'replace')
335 self.data = self.data.decode(encoding, 'replace')
331 except:
336 except:
332 self.data = None
337 self.data = None
333
338
334 class Pretty(DisplayObject):
339 class TextDisplayObject(DisplayObject):
340 """Validate that display data is text"""
341 def _check_data(self):
342 if self.data is not None and not isinstance(self.data, string_types):
343 raise TypeError("%s xpects text, not %r" % (self.__class__.__name__, self.data))
344
345 class Pretty(TextDisplayObject):
335
346
336 def _repr_pretty_(self):
347 def _repr_pretty_(self):
337 return self.data
348 return self.data
338
349
339
350
340 class HTML(DisplayObject):
351 class HTML(TextDisplayObject):
341
352
342 def _repr_html_(self):
353 def _repr_html_(self):
343 return self.data
354 return self.data
344
355
345 def __html__(self):
356 def __html__(self):
346 """
357 """
347 This method exists to inform other HTML-using modules (e.g. Markupsafe,
358 This method exists to inform other HTML-using modules (e.g. Markupsafe,
348 htmltag, etc) that this object is HTML and does not need things like
359 htmltag, etc) that this object is HTML and does not need things like
349 special characters (<>&) escaped.
360 special characters (<>&) escaped.
350 """
361 """
351 return self._repr_html_()
362 return self._repr_html_()
352
363
353
364
354 class Math(DisplayObject):
365 class Math(TextDisplayObject):
355
366
356 def _repr_latex_(self):
367 def _repr_latex_(self):
357 s = self.data.strip('$')
368 s = self.data.strip('$')
358 return "$$%s$$" % s
369 return "$$%s$$" % s
359
370
360
371
361 class Latex(DisplayObject):
372 class Latex(TextDisplayObject):
362
373
363 def _repr_latex_(self):
374 def _repr_latex_(self):
364 return self.data
375 return self.data
365
376
366
377
367 class SVG(DisplayObject):
378 class SVG(DisplayObject):
368
379
369 # wrap data in a property, which extracts the <svg> tag, discarding
380 # wrap data in a property, which extracts the <svg> tag, discarding
370 # document headers
381 # document headers
371 _data = None
382 _data = None
372
383
373 @property
384 @property
374 def data(self):
385 def data(self):
375 return self._data
386 return self._data
376
387
377 @data.setter
388 @data.setter
378 def data(self, svg):
389 def data(self, svg):
379 if svg is None:
390 if svg is None:
380 self._data = None
391 self._data = None
381 return
392 return
382 # parse into dom object
393 # parse into dom object
383 from xml.dom import minidom
394 from xml.dom import minidom
384 svg = cast_bytes_py2(svg)
395 svg = cast_bytes_py2(svg)
385 x = minidom.parseString(svg)
396 x = minidom.parseString(svg)
386 # get svg tag (should be 1)
397 # get svg tag (should be 1)
387 found_svg = x.getElementsByTagName('svg')
398 found_svg = x.getElementsByTagName('svg')
388 if found_svg:
399 if found_svg:
389 svg = found_svg[0].toxml()
400 svg = found_svg[0].toxml()
390 else:
401 else:
391 # fallback on the input, trust the user
402 # fallback on the input, trust the user
392 # but this is probably an error.
403 # but this is probably an error.
393 pass
404 pass
394 svg = cast_unicode(svg)
405 svg = cast_unicode(svg)
395 self._data = svg
406 self._data = svg
396
407
397 def _repr_svg_(self):
408 def _repr_svg_(self):
398 return self.data
409 return self.data
399
410
400
411
401 class JSON(DisplayObject):
412 class JSON(TextDisplayObject):
402
413
403 def _repr_json_(self):
414 def _repr_json_(self):
404 return self.data
415 return self.data
405
416
406 css_t = """$("head").append($("<link/>").attr({
417 css_t = """$("head").append($("<link/>").attr({
407 rel: "stylesheet",
418 rel: "stylesheet",
408 type: "text/css",
419 type: "text/css",
409 href: "%s"
420 href: "%s"
410 }));
421 }));
411 """
422 """
412
423
413 lib_t1 = """$.getScript("%s", function () {
424 lib_t1 = """$.getScript("%s", function () {
414 """
425 """
415 lib_t2 = """});
426 lib_t2 = """});
416 """
427 """
417
428
418 class Javascript(DisplayObject):
429 class Javascript(TextDisplayObject):
419
430
420 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
431 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
421 """Create a Javascript display object given raw data.
432 """Create a Javascript display object given raw data.
422
433
423 When this object is returned by an expression or passed to the
434 When this object is returned by an expression or passed to the
424 display function, it will result in the data being displayed
435 display function, it will result in the data being displayed
425 in the frontend. If the data is a URL, the data will first be
436 in the frontend. If the data is a URL, the data will first be
426 downloaded and then displayed.
437 downloaded and then displayed.
427
438
428 In the Notebook, the containing element will be available as `element`,
439 In the Notebook, the containing element will be available as `element`,
429 and jQuery will be available. The output area starts hidden, so if
440 and jQuery will be available. The output area starts hidden, so if
430 the js appends content to `element` that should be visible, then
441 the js appends content to `element` that should be visible, then
431 it must call `container.show()` to unhide the area.
442 it must call `container.show()` to unhide the area.
432
443
433 Parameters
444 Parameters
434 ----------
445 ----------
435 data : unicode, str or bytes
446 data : unicode, str or bytes
436 The Javascript source code or a URL to download it from.
447 The Javascript source code or a URL to download it from.
437 url : unicode
448 url : unicode
438 A URL to download the data from.
449 A URL to download the data from.
439 filename : unicode
450 filename : unicode
440 Path to a local file to load the data from.
451 Path to a local file to load the data from.
441 lib : list or str
452 lib : list or str
442 A sequence of Javascript library URLs to load asynchronously before
453 A sequence of Javascript library URLs to load asynchronously before
443 running the source code. The full URLs of the libraries should
454 running the source code. The full URLs of the libraries should
444 be given. A single Javascript library URL can also be given as a
455 be given. A single Javascript library URL can also be given as a
445 string.
456 string.
446 css: : list or str
457 css: : list or str
447 A sequence of css files to load before running the source code.
458 A sequence of css files to load before running the source code.
448 The full URLs of the css files should be given. A single css URL
459 The full URLs of the css files should be given. A single css URL
449 can also be given as a string.
460 can also be given as a string.
450 """
461 """
451 if isinstance(lib, string_types):
462 if isinstance(lib, string_types):
452 lib = [lib]
463 lib = [lib]
453 elif lib is None:
464 elif lib is None:
454 lib = []
465 lib = []
455 if isinstance(css, string_types):
466 if isinstance(css, string_types):
456 css = [css]
467 css = [css]
457 elif css is None:
468 elif css is None:
458 css = []
469 css = []
459 if not isinstance(lib, (list,tuple)):
470 if not isinstance(lib, (list,tuple)):
460 raise TypeError('expected sequence, got: %r' % lib)
471 raise TypeError('expected sequence, got: %r' % lib)
461 if not isinstance(css, (list,tuple)):
472 if not isinstance(css, (list,tuple)):
462 raise TypeError('expected sequence, got: %r' % css)
473 raise TypeError('expected sequence, got: %r' % css)
463 self.lib = lib
474 self.lib = lib
464 self.css = css
475 self.css = css
465 super(Javascript, self).__init__(data=data, url=url, filename=filename)
476 super(Javascript, self).__init__(data=data, url=url, filename=filename)
466
477
467 def _repr_javascript_(self):
478 def _repr_javascript_(self):
468 r = ''
479 r = ''
469 for c in self.css:
480 for c in self.css:
470 r += css_t % c
481 r += css_t % c
471 for l in self.lib:
482 for l in self.lib:
472 r += lib_t1 % l
483 r += lib_t1 % l
473 r += self.data
484 r += self.data
474 r += lib_t2*len(self.lib)
485 r += lib_t2*len(self.lib)
475 return r
486 return r
476
487
477 # constants for identifying png/jpeg data
488 # constants for identifying png/jpeg data
478 _PNG = b'\x89PNG\r\n\x1a\n'
489 _PNG = b'\x89PNG\r\n\x1a\n'
479 _JPEG = b'\xff\xd8'
490 _JPEG = b'\xff\xd8'
480
491
481 def _pngxy(data):
492 def _pngxy(data):
482 """read the (width, height) from a PNG header"""
493 """read the (width, height) from a PNG header"""
483 ihdr = data.index(b'IHDR')
494 ihdr = data.index(b'IHDR')
484 # next 8 bytes are width/height
495 # next 8 bytes are width/height
485 w4h4 = data[ihdr+4:ihdr+12]
496 w4h4 = data[ihdr+4:ihdr+12]
486 return struct.unpack('>ii', w4h4)
497 return struct.unpack('>ii', w4h4)
487
498
488 def _jpegxy(data):
499 def _jpegxy(data):
489 """read the (width, height) from a JPEG header"""
500 """read the (width, height) from a JPEG header"""
490 # adapted from http://www.64lines.com/jpeg-width-height
501 # adapted from http://www.64lines.com/jpeg-width-height
491
502
492 idx = 4
503 idx = 4
493 while True:
504 while True:
494 block_size = struct.unpack('>H', data[idx:idx+2])[0]
505 block_size = struct.unpack('>H', data[idx:idx+2])[0]
495 idx = idx + block_size
506 idx = idx + block_size
496 if data[idx:idx+2] == b'\xFF\xC0':
507 if data[idx:idx+2] == b'\xFF\xC0':
497 # found Start of Frame
508 # found Start of Frame
498 iSOF = idx
509 iSOF = idx
499 break
510 break
500 else:
511 else:
501 # read another block
512 # read another block
502 idx += 2
513 idx += 2
503
514
504 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
515 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
505 return w, h
516 return w, h
506
517
507 class Image(DisplayObject):
518 class Image(DisplayObject):
508
519
509 _read_flags = 'rb'
520 _read_flags = 'rb'
510 _FMT_JPEG = u'jpeg'
521 _FMT_JPEG = u'jpeg'
511 _FMT_PNG = u'png'
522 _FMT_PNG = u'png'
512 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
523 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
513
524
514 def __init__(self, data=None, url=None, filename=None, format=u'png', embed=None, width=None, height=None, retina=False):
525 def __init__(self, data=None, url=None, filename=None, format=u'png', embed=None, width=None, height=None, retina=False):
515 """Create a PNG/JPEG image object given raw data.
526 """Create a PNG/JPEG image object given raw data.
516
527
517 When this object is returned by an input cell or passed to the
528 When this object is returned by an input cell or passed to the
518 display function, it will result in the image being displayed
529 display function, it will result in the image being displayed
519 in the frontend.
530 in the frontend.
520
531
521 Parameters
532 Parameters
522 ----------
533 ----------
523 data : unicode, str or bytes
534 data : unicode, str or bytes
524 The raw image data or a URL or filename to load the data from.
535 The raw image data or a URL or filename to load the data from.
525 This always results in embedded image data.
536 This always results in embedded image data.
526 url : unicode
537 url : unicode
527 A URL to download the data from. If you specify `url=`,
538 A URL to download the data from. If you specify `url=`,
528 the image data will not be embedded unless you also specify `embed=True`.
539 the image data will not be embedded unless you also specify `embed=True`.
529 filename : unicode
540 filename : unicode
530 Path to a local file to load the data from.
541 Path to a local file to load the data from.
531 Images from a file are always embedded.
542 Images from a file are always embedded.
532 format : unicode
543 format : unicode
533 The format of the image data (png/jpeg/jpg). If a filename or URL is given
544 The format of the image data (png/jpeg/jpg). If a filename or URL is given
534 for format will be inferred from the filename extension.
545 for format will be inferred from the filename extension.
535 embed : bool
546 embed : bool
536 Should the image data be embedded using a data URI (True) or be
547 Should the image data be embedded using a data URI (True) or be
537 loaded using an <img> tag. Set this to True if you want the image
548 loaded using an <img> tag. Set this to True if you want the image
538 to be viewable later with no internet connection in the notebook.
549 to be viewable later with no internet connection in the notebook.
539
550
540 Default is `True`, unless the keyword argument `url` is set, then
551 Default is `True`, unless the keyword argument `url` is set, then
541 default value is `False`.
552 default value is `False`.
542
553
543 Note that QtConsole is not able to display images if `embed` is set to `False`
554 Note that QtConsole is not able to display images if `embed` is set to `False`
544 width : int
555 width : int
545 Width to which to constrain the image in html
556 Width to which to constrain the image in html
546 height : int
557 height : int
547 Height to which to constrain the image in html
558 Height to which to constrain the image in html
548 retina : bool
559 retina : bool
549 Automatically set the width and height to half of the measured
560 Automatically set the width and height to half of the measured
550 width and height.
561 width and height.
551 This only works for embedded images because it reads the width/height
562 This only works for embedded images because it reads the width/height
552 from image data.
563 from image data.
553 For non-embedded images, you can just set the desired display width
564 For non-embedded images, you can just set the desired display width
554 and height directly.
565 and height directly.
555
566
556 Examples
567 Examples
557 --------
568 --------
558 # embedded image data, works in qtconsole and notebook
569 # embedded image data, works in qtconsole and notebook
559 # when passed positionally, the first arg can be any of raw image data,
570 # when passed positionally, the first arg can be any of raw image data,
560 # a URL, or a filename from which to load image data.
571 # a URL, or a filename from which to load image data.
561 # The result is always embedding image data for inline images.
572 # The result is always embedding image data for inline images.
562 Image('http://www.google.fr/images/srpr/logo3w.png')
573 Image('http://www.google.fr/images/srpr/logo3w.png')
563 Image('/path/to/image.jpg')
574 Image('/path/to/image.jpg')
564 Image(b'RAW_PNG_DATA...')
575 Image(b'RAW_PNG_DATA...')
565
576
566 # Specifying Image(url=...) does not embed the image data,
577 # Specifying Image(url=...) does not embed the image data,
567 # it only generates `<img>` tag with a link to the source.
578 # it only generates `<img>` tag with a link to the source.
568 # This will not work in the qtconsole or offline.
579 # This will not work in the qtconsole or offline.
569 Image(url='http://www.google.fr/images/srpr/logo3w.png')
580 Image(url='http://www.google.fr/images/srpr/logo3w.png')
570
581
571 """
582 """
572 if filename is not None:
583 if filename is not None:
573 ext = self._find_ext(filename)
584 ext = self._find_ext(filename)
574 elif url is not None:
585 elif url is not None:
575 ext = self._find_ext(url)
586 ext = self._find_ext(url)
576 elif data is None:
587 elif data is None:
577 raise ValueError("No image data found. Expecting filename, url, or data.")
588 raise ValueError("No image data found. Expecting filename, url, or data.")
578 elif isinstance(data, string_types) and (
589 elif isinstance(data, string_types) and (
579 data.startswith('http') or _safe_exists(data)
590 data.startswith('http') or _safe_exists(data)
580 ):
591 ):
581 ext = self._find_ext(data)
592 ext = self._find_ext(data)
582 else:
593 else:
583 ext = None
594 ext = None
584
595
585 if ext is not None:
596 if ext is not None:
586 format = ext.lower()
597 format = ext.lower()
587 if ext == u'jpg' or ext == u'jpeg':
598 if ext == u'jpg' or ext == u'jpeg':
588 format = self._FMT_JPEG
599 format = self._FMT_JPEG
589 if ext == u'png':
600 if ext == u'png':
590 format = self._FMT_PNG
601 format = self._FMT_PNG
591 elif isinstance(data, bytes) and format == 'png':
602 elif isinstance(data, bytes) and format == 'png':
592 # infer image type from image data header,
603 # infer image type from image data header,
593 # only if format might not have been specified.
604 # only if format might not have been specified.
594 if data[:2] == _JPEG:
605 if data[:2] == _JPEG:
595 format = 'jpeg'
606 format = 'jpeg'
596
607
597 self.format = unicode_type(format).lower()
608 self.format = unicode_type(format).lower()
598 self.embed = embed if embed is not None else (url is None)
609 self.embed = embed if embed is not None else (url is None)
599
610
600 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
611 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
601 raise ValueError("Cannot embed the '%s' image format" % (self.format))
612 raise ValueError("Cannot embed the '%s' image format" % (self.format))
602 self.width = width
613 self.width = width
603 self.height = height
614 self.height = height
604 self.retina = retina
615 self.retina = retina
605 super(Image, self).__init__(data=data, url=url, filename=filename)
616 super(Image, self).__init__(data=data, url=url, filename=filename)
606
617
607 if retina:
618 if retina:
608 self._retina_shape()
619 self._retina_shape()
609
620
610 def _retina_shape(self):
621 def _retina_shape(self):
611 """load pixel-doubled width and height from image data"""
622 """load pixel-doubled width and height from image data"""
612 if not self.embed:
623 if not self.embed:
613 return
624 return
614 if self.format == 'png':
625 if self.format == 'png':
615 w, h = _pngxy(self.data)
626 w, h = _pngxy(self.data)
616 elif self.format == 'jpeg':
627 elif self.format == 'jpeg':
617 w, h = _jpegxy(self.data)
628 w, h = _jpegxy(self.data)
618 else:
629 else:
619 # retina only supports png
630 # retina only supports png
620 return
631 return
621 self.width = w // 2
632 self.width = w // 2
622 self.height = h // 2
633 self.height = h // 2
623
634
624 def reload(self):
635 def reload(self):
625 """Reload the raw data from file or URL."""
636 """Reload the raw data from file or URL."""
626 if self.embed:
637 if self.embed:
627 super(Image,self).reload()
638 super(Image,self).reload()
628 if self.retina:
639 if self.retina:
629 self._retina_shape()
640 self._retina_shape()
630
641
631 def _repr_html_(self):
642 def _repr_html_(self):
632 if not self.embed:
643 if not self.embed:
633 width = height = ''
644 width = height = ''
634 if self.width:
645 if self.width:
635 width = ' width="%d"' % self.width
646 width = ' width="%d"' % self.width
636 if self.height:
647 if self.height:
637 height = ' height="%d"' % self.height
648 height = ' height="%d"' % self.height
638 return u'<img src="%s"%s%s/>' % (self.url, width, height)
649 return u'<img src="%s"%s%s/>' % (self.url, width, height)
639
650
640 def _data_and_metadata(self):
651 def _data_and_metadata(self):
641 """shortcut for returning metadata with shape information, if defined"""
652 """shortcut for returning metadata with shape information, if defined"""
642 md = {}
653 md = {}
643 if self.width:
654 if self.width:
644 md['width'] = self.width
655 md['width'] = self.width
645 if self.height:
656 if self.height:
646 md['height'] = self.height
657 md['height'] = self.height
647 if md:
658 if md:
648 return self.data, md
659 return self.data, md
649 else:
660 else:
650 return self.data
661 return self.data
651
662
652 def _repr_png_(self):
663 def _repr_png_(self):
653 if self.embed and self.format == u'png':
664 if self.embed and self.format == u'png':
654 return self._data_and_metadata()
665 return self._data_and_metadata()
655
666
656 def _repr_jpeg_(self):
667 def _repr_jpeg_(self):
657 if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
668 if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
658 return self._data_and_metadata()
669 return self._data_and_metadata()
659
670
660 def _find_ext(self, s):
671 def _find_ext(self, s):
661 return unicode_type(s.split('.')[-1].lower())
672 return unicode_type(s.split('.')[-1].lower())
662
673
663
674
664 def clear_output(wait=False):
675 def clear_output(wait=False):
665 """Clear the output of the current cell receiving output.
676 """Clear the output of the current cell receiving output.
666
677
667 Parameters
678 Parameters
668 ----------
679 ----------
669 wait : bool [default: false]
680 wait : bool [default: false]
670 Wait to clear the output until new output is available to replace it."""
681 Wait to clear the output until new output is available to replace it."""
671 from IPython.core.interactiveshell import InteractiveShell
682 from IPython.core.interactiveshell import InteractiveShell
672 if InteractiveShell.initialized():
683 if InteractiveShell.initialized():
673 InteractiveShell.instance().display_pub.clear_output(wait)
684 InteractiveShell.instance().display_pub.clear_output(wait)
674 else:
685 else:
675 from IPython.utils import io
686 from IPython.utils import io
676 print('\033[2K\r', file=io.stdout, end='')
687 print('\033[2K\r', file=io.stdout, end='')
677 io.stdout.flush()
688 io.stdout.flush()
678 print('\033[2K\r', file=io.stderr, end='')
689 print('\033[2K\r', file=io.stderr, end='')
679 io.stderr.flush()
690 io.stderr.flush()
General Comments 0
You need to be logged in to leave comments. Login now