##// END OF EJS Templates
xpects typo
MinRK -
Show More
@@ -1,690 +1,690 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 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()
307 self._check_data()
308
308
309 def _check_data(self):
309 def _check_data(self):
310 """Override in subclasses if there's something to check."""
310 """Override in subclasses if there's something to check."""
311 pass
311 pass
312
312
313 def reload(self):
313 def reload(self):
314 """Reload the raw data from file or URL."""
314 """Reload the raw data from file or URL."""
315 if self.filename is not None:
315 if self.filename is not None:
316 with open(self.filename, self._read_flags) as f:
316 with open(self.filename, self._read_flags) as f:
317 self.data = f.read()
317 self.data = f.read()
318 elif self.url is not None:
318 elif self.url is not None:
319 try:
319 try:
320 try:
320 try:
321 from urllib.request import urlopen # Py3
321 from urllib.request import urlopen # Py3
322 except ImportError:
322 except ImportError:
323 from urllib2 import urlopen
323 from urllib2 import urlopen
324 response = urlopen(self.url)
324 response = urlopen(self.url)
325 self.data = response.read()
325 self.data = response.read()
326 # extract encoding from header, if there is one:
326 # extract encoding from header, if there is one:
327 encoding = None
327 encoding = None
328 for sub in response.headers['content-type'].split(';'):
328 for sub in response.headers['content-type'].split(';'):
329 sub = sub.strip()
329 sub = sub.strip()
330 if sub.startswith('charset'):
330 if sub.startswith('charset'):
331 encoding = sub.split('=')[-1].strip()
331 encoding = sub.split('=')[-1].strip()
332 break
332 break
333 # decode data, if an encoding was specified
333 # decode data, if an encoding was specified
334 if encoding:
334 if encoding:
335 self.data = self.data.decode(encoding, 'replace')
335 self.data = self.data.decode(encoding, 'replace')
336 except:
336 except:
337 self.data = None
337 self.data = None
338
338
339 class TextDisplayObject(DisplayObject):
339 class TextDisplayObject(DisplayObject):
340 """Validate that display data is text"""
340 """Validate that display data is text"""
341 def _check_data(self):
341 def _check_data(self):
342 if self.data is not None and not isinstance(self.data, string_types):
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))
343 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
344
344
345 class Pretty(TextDisplayObject):
345 class Pretty(TextDisplayObject):
346
346
347 def _repr_pretty_(self):
347 def _repr_pretty_(self):
348 return self.data
348 return self.data
349
349
350
350
351 class HTML(TextDisplayObject):
351 class HTML(TextDisplayObject):
352
352
353 def _repr_html_(self):
353 def _repr_html_(self):
354 return self.data
354 return self.data
355
355
356 def __html__(self):
356 def __html__(self):
357 """
357 """
358 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,
359 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
360 special characters (<>&) escaped.
360 special characters (<>&) escaped.
361 """
361 """
362 return self._repr_html_()
362 return self._repr_html_()
363
363
364
364
365 class Math(TextDisplayObject):
365 class Math(TextDisplayObject):
366
366
367 def _repr_latex_(self):
367 def _repr_latex_(self):
368 s = self.data.strip('$')
368 s = self.data.strip('$')
369 return "$$%s$$" % s
369 return "$$%s$$" % s
370
370
371
371
372 class Latex(TextDisplayObject):
372 class Latex(TextDisplayObject):
373
373
374 def _repr_latex_(self):
374 def _repr_latex_(self):
375 return self.data
375 return self.data
376
376
377
377
378 class SVG(DisplayObject):
378 class SVG(DisplayObject):
379
379
380 # wrap data in a property, which extracts the <svg> tag, discarding
380 # wrap data in a property, which extracts the <svg> tag, discarding
381 # document headers
381 # document headers
382 _data = None
382 _data = None
383
383
384 @property
384 @property
385 def data(self):
385 def data(self):
386 return self._data
386 return self._data
387
387
388 @data.setter
388 @data.setter
389 def data(self, svg):
389 def data(self, svg):
390 if svg is None:
390 if svg is None:
391 self._data = None
391 self._data = None
392 return
392 return
393 # parse into dom object
393 # parse into dom object
394 from xml.dom import minidom
394 from xml.dom import minidom
395 svg = cast_bytes_py2(svg)
395 svg = cast_bytes_py2(svg)
396 x = minidom.parseString(svg)
396 x = minidom.parseString(svg)
397 # get svg tag (should be 1)
397 # get svg tag (should be 1)
398 found_svg = x.getElementsByTagName('svg')
398 found_svg = x.getElementsByTagName('svg')
399 if found_svg:
399 if found_svg:
400 svg = found_svg[0].toxml()
400 svg = found_svg[0].toxml()
401 else:
401 else:
402 # fallback on the input, trust the user
402 # fallback on the input, trust the user
403 # but this is probably an error.
403 # but this is probably an error.
404 pass
404 pass
405 svg = cast_unicode(svg)
405 svg = cast_unicode(svg)
406 self._data = svg
406 self._data = svg
407
407
408 def _repr_svg_(self):
408 def _repr_svg_(self):
409 return self.data
409 return self.data
410
410
411
411
412 class JSON(TextDisplayObject):
412 class JSON(TextDisplayObject):
413
413
414 def _repr_json_(self):
414 def _repr_json_(self):
415 return self.data
415 return self.data
416
416
417 css_t = """$("head").append($("<link/>").attr({
417 css_t = """$("head").append($("<link/>").attr({
418 rel: "stylesheet",
418 rel: "stylesheet",
419 type: "text/css",
419 type: "text/css",
420 href: "%s"
420 href: "%s"
421 }));
421 }));
422 """
422 """
423
423
424 lib_t1 = """$.getScript("%s", function () {
424 lib_t1 = """$.getScript("%s", function () {
425 """
425 """
426 lib_t2 = """});
426 lib_t2 = """});
427 """
427 """
428
428
429 class Javascript(TextDisplayObject):
429 class Javascript(TextDisplayObject):
430
430
431 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):
432 """Create a Javascript display object given raw data.
432 """Create a Javascript display object given raw data.
433
433
434 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
435 display function, it will result in the data being displayed
435 display function, it will result in the data being displayed
436 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
437 downloaded and then displayed.
437 downloaded and then displayed.
438
438
439 In the Notebook, the containing element will be available as `element`,
439 In the Notebook, the containing element will be available as `element`,
440 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
441 the js appends content to `element` that should be visible, then
441 the js appends content to `element` that should be visible, then
442 it must call `container.show()` to unhide the area.
442 it must call `container.show()` to unhide the area.
443
443
444 Parameters
444 Parameters
445 ----------
445 ----------
446 data : unicode, str or bytes
446 data : unicode, str or bytes
447 The Javascript source code or a URL to download it from.
447 The Javascript source code or a URL to download it from.
448 url : unicode
448 url : unicode
449 A URL to download the data from.
449 A URL to download the data from.
450 filename : unicode
450 filename : unicode
451 Path to a local file to load the data from.
451 Path to a local file to load the data from.
452 lib : list or str
452 lib : list or str
453 A sequence of Javascript library URLs to load asynchronously before
453 A sequence of Javascript library URLs to load asynchronously before
454 running the source code. The full URLs of the libraries should
454 running the source code. The full URLs of the libraries should
455 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
456 string.
456 string.
457 css: : list or str
457 css: : list or str
458 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.
459 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
460 can also be given as a string.
460 can also be given as a string.
461 """
461 """
462 if isinstance(lib, string_types):
462 if isinstance(lib, string_types):
463 lib = [lib]
463 lib = [lib]
464 elif lib is None:
464 elif lib is None:
465 lib = []
465 lib = []
466 if isinstance(css, string_types):
466 if isinstance(css, string_types):
467 css = [css]
467 css = [css]
468 elif css is None:
468 elif css is None:
469 css = []
469 css = []
470 if not isinstance(lib, (list,tuple)):
470 if not isinstance(lib, (list,tuple)):
471 raise TypeError('expected sequence, got: %r' % lib)
471 raise TypeError('expected sequence, got: %r' % lib)
472 if not isinstance(css, (list,tuple)):
472 if not isinstance(css, (list,tuple)):
473 raise TypeError('expected sequence, got: %r' % css)
473 raise TypeError('expected sequence, got: %r' % css)
474 self.lib = lib
474 self.lib = lib
475 self.css = css
475 self.css = css
476 super(Javascript, self).__init__(data=data, url=url, filename=filename)
476 super(Javascript, self).__init__(data=data, url=url, filename=filename)
477
477
478 def _repr_javascript_(self):
478 def _repr_javascript_(self):
479 r = ''
479 r = ''
480 for c in self.css:
480 for c in self.css:
481 r += css_t % c
481 r += css_t % c
482 for l in self.lib:
482 for l in self.lib:
483 r += lib_t1 % l
483 r += lib_t1 % l
484 r += self.data
484 r += self.data
485 r += lib_t2*len(self.lib)
485 r += lib_t2*len(self.lib)
486 return r
486 return r
487
487
488 # constants for identifying png/jpeg data
488 # constants for identifying png/jpeg data
489 _PNG = b'\x89PNG\r\n\x1a\n'
489 _PNG = b'\x89PNG\r\n\x1a\n'
490 _JPEG = b'\xff\xd8'
490 _JPEG = b'\xff\xd8'
491
491
492 def _pngxy(data):
492 def _pngxy(data):
493 """read the (width, height) from a PNG header"""
493 """read the (width, height) from a PNG header"""
494 ihdr = data.index(b'IHDR')
494 ihdr = data.index(b'IHDR')
495 # next 8 bytes are width/height
495 # next 8 bytes are width/height
496 w4h4 = data[ihdr+4:ihdr+12]
496 w4h4 = data[ihdr+4:ihdr+12]
497 return struct.unpack('>ii', w4h4)
497 return struct.unpack('>ii', w4h4)
498
498
499 def _jpegxy(data):
499 def _jpegxy(data):
500 """read the (width, height) from a JPEG header"""
500 """read the (width, height) from a JPEG header"""
501 # adapted from http://www.64lines.com/jpeg-width-height
501 # adapted from http://www.64lines.com/jpeg-width-height
502
502
503 idx = 4
503 idx = 4
504 while True:
504 while True:
505 block_size = struct.unpack('>H', data[idx:idx+2])[0]
505 block_size = struct.unpack('>H', data[idx:idx+2])[0]
506 idx = idx + block_size
506 idx = idx + block_size
507 if data[idx:idx+2] == b'\xFF\xC0':
507 if data[idx:idx+2] == b'\xFF\xC0':
508 # found Start of Frame
508 # found Start of Frame
509 iSOF = idx
509 iSOF = idx
510 break
510 break
511 else:
511 else:
512 # read another block
512 # read another block
513 idx += 2
513 idx += 2
514
514
515 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
515 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
516 return w, h
516 return w, h
517
517
518 class Image(DisplayObject):
518 class Image(DisplayObject):
519
519
520 _read_flags = 'rb'
520 _read_flags = 'rb'
521 _FMT_JPEG = u'jpeg'
521 _FMT_JPEG = u'jpeg'
522 _FMT_PNG = u'png'
522 _FMT_PNG = u'png'
523 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
523 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
524
524
525 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):
526 """Create a PNG/JPEG image object given raw data.
526 """Create a PNG/JPEG image object given raw data.
527
527
528 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
529 display function, it will result in the image being displayed
529 display function, it will result in the image being displayed
530 in the frontend.
530 in the frontend.
531
531
532 Parameters
532 Parameters
533 ----------
533 ----------
534 data : unicode, str or bytes
534 data : unicode, str or bytes
535 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.
536 This always results in embedded image data.
536 This always results in embedded image data.
537 url : unicode
537 url : unicode
538 A URL to download the data from. If you specify `url=`,
538 A URL to download the data from. If you specify `url=`,
539 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`.
540 filename : unicode
540 filename : unicode
541 Path to a local file to load the data from.
541 Path to a local file to load the data from.
542 Images from a file are always embedded.
542 Images from a file are always embedded.
543 format : unicode
543 format : unicode
544 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
545 for format will be inferred from the filename extension.
545 for format will be inferred from the filename extension.
546 embed : bool
546 embed : bool
547 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
548 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
549 to be viewable later with no internet connection in the notebook.
549 to be viewable later with no internet connection in the notebook.
550
550
551 Default is `True`, unless the keyword argument `url` is set, then
551 Default is `True`, unless the keyword argument `url` is set, then
552 default value is `False`.
552 default value is `False`.
553
553
554 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`
555 width : int
555 width : int
556 Width to which to constrain the image in html
556 Width to which to constrain the image in html
557 height : int
557 height : int
558 Height to which to constrain the image in html
558 Height to which to constrain the image in html
559 retina : bool
559 retina : bool
560 Automatically set the width and height to half of the measured
560 Automatically set the width and height to half of the measured
561 width and height.
561 width and height.
562 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
563 from image data.
563 from image data.
564 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
565 and height directly.
565 and height directly.
566
566
567 Examples
567 Examples
568 --------
568 --------
569 # embedded image data, works in qtconsole and notebook
569 # embedded image data, works in qtconsole and notebook
570 # 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,
571 # a URL, or a filename from which to load image data.
571 # a URL, or a filename from which to load image data.
572 # The result is always embedding image data for inline images.
572 # The result is always embedding image data for inline images.
573 Image('http://www.google.fr/images/srpr/logo3w.png')
573 Image('http://www.google.fr/images/srpr/logo3w.png')
574 Image('/path/to/image.jpg')
574 Image('/path/to/image.jpg')
575 Image(b'RAW_PNG_DATA...')
575 Image(b'RAW_PNG_DATA...')
576
576
577 # Specifying Image(url=...) does not embed the image data,
577 # Specifying Image(url=...) does not embed the image data,
578 # it only generates `<img>` tag with a link to the source.
578 # it only generates `<img>` tag with a link to the source.
579 # This will not work in the qtconsole or offline.
579 # This will not work in the qtconsole or offline.
580 Image(url='http://www.google.fr/images/srpr/logo3w.png')
580 Image(url='http://www.google.fr/images/srpr/logo3w.png')
581
581
582 """
582 """
583 if filename is not None:
583 if filename is not None:
584 ext = self._find_ext(filename)
584 ext = self._find_ext(filename)
585 elif url is not None:
585 elif url is not None:
586 ext = self._find_ext(url)
586 ext = self._find_ext(url)
587 elif data is None:
587 elif data is None:
588 raise ValueError("No image data found. Expecting filename, url, or data.")
588 raise ValueError("No image data found. Expecting filename, url, or data.")
589 elif isinstance(data, string_types) and (
589 elif isinstance(data, string_types) and (
590 data.startswith('http') or _safe_exists(data)
590 data.startswith('http') or _safe_exists(data)
591 ):
591 ):
592 ext = self._find_ext(data)
592 ext = self._find_ext(data)
593 else:
593 else:
594 ext = None
594 ext = None
595
595
596 if ext is not None:
596 if ext is not None:
597 format = ext.lower()
597 format = ext.lower()
598 if ext == u'jpg' or ext == u'jpeg':
598 if ext == u'jpg' or ext == u'jpeg':
599 format = self._FMT_JPEG
599 format = self._FMT_JPEG
600 if ext == u'png':
600 if ext == u'png':
601 format = self._FMT_PNG
601 format = self._FMT_PNG
602 elif isinstance(data, bytes) and format == 'png':
602 elif isinstance(data, bytes) and format == 'png':
603 # infer image type from image data header,
603 # infer image type from image data header,
604 # only if format might not have been specified.
604 # only if format might not have been specified.
605 if data[:2] == _JPEG:
605 if data[:2] == _JPEG:
606 format = 'jpeg'
606 format = 'jpeg'
607
607
608 self.format = unicode_type(format).lower()
608 self.format = unicode_type(format).lower()
609 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)
610
610
611 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
611 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
612 raise ValueError("Cannot embed the '%s' image format" % (self.format))
612 raise ValueError("Cannot embed the '%s' image format" % (self.format))
613 self.width = width
613 self.width = width
614 self.height = height
614 self.height = height
615 self.retina = retina
615 self.retina = retina
616 super(Image, self).__init__(data=data, url=url, filename=filename)
616 super(Image, self).__init__(data=data, url=url, filename=filename)
617
617
618 if retina:
618 if retina:
619 self._retina_shape()
619 self._retina_shape()
620
620
621 def _retina_shape(self):
621 def _retina_shape(self):
622 """load pixel-doubled width and height from image data"""
622 """load pixel-doubled width and height from image data"""
623 if not self.embed:
623 if not self.embed:
624 return
624 return
625 if self.format == 'png':
625 if self.format == 'png':
626 w, h = _pngxy(self.data)
626 w, h = _pngxy(self.data)
627 elif self.format == 'jpeg':
627 elif self.format == 'jpeg':
628 w, h = _jpegxy(self.data)
628 w, h = _jpegxy(self.data)
629 else:
629 else:
630 # retina only supports png
630 # retina only supports png
631 return
631 return
632 self.width = w // 2
632 self.width = w // 2
633 self.height = h // 2
633 self.height = h // 2
634
634
635 def reload(self):
635 def reload(self):
636 """Reload the raw data from file or URL."""
636 """Reload the raw data from file or URL."""
637 if self.embed:
637 if self.embed:
638 super(Image,self).reload()
638 super(Image,self).reload()
639 if self.retina:
639 if self.retina:
640 self._retina_shape()
640 self._retina_shape()
641
641
642 def _repr_html_(self):
642 def _repr_html_(self):
643 if not self.embed:
643 if not self.embed:
644 width = height = ''
644 width = height = ''
645 if self.width:
645 if self.width:
646 width = ' width="%d"' % self.width
646 width = ' width="%d"' % self.width
647 if self.height:
647 if self.height:
648 height = ' height="%d"' % self.height
648 height = ' height="%d"' % self.height
649 return u'<img src="%s"%s%s/>' % (self.url, width, height)
649 return u'<img src="%s"%s%s/>' % (self.url, width, height)
650
650
651 def _data_and_metadata(self):
651 def _data_and_metadata(self):
652 """shortcut for returning metadata with shape information, if defined"""
652 """shortcut for returning metadata with shape information, if defined"""
653 md = {}
653 md = {}
654 if self.width:
654 if self.width:
655 md['width'] = self.width
655 md['width'] = self.width
656 if self.height:
656 if self.height:
657 md['height'] = self.height
657 md['height'] = self.height
658 if md:
658 if md:
659 return self.data, md
659 return self.data, md
660 else:
660 else:
661 return self.data
661 return self.data
662
662
663 def _repr_png_(self):
663 def _repr_png_(self):
664 if self.embed and self.format == u'png':
664 if self.embed and self.format == u'png':
665 return self._data_and_metadata()
665 return self._data_and_metadata()
666
666
667 def _repr_jpeg_(self):
667 def _repr_jpeg_(self):
668 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'):
669 return self._data_and_metadata()
669 return self._data_and_metadata()
670
670
671 def _find_ext(self, s):
671 def _find_ext(self, s):
672 return unicode_type(s.split('.')[-1].lower())
672 return unicode_type(s.split('.')[-1].lower())
673
673
674
674
675 def clear_output(wait=False):
675 def clear_output(wait=False):
676 """Clear the output of the current cell receiving output.
676 """Clear the output of the current cell receiving output.
677
677
678 Parameters
678 Parameters
679 ----------
679 ----------
680 wait : bool [default: false]
680 wait : bool [default: false]
681 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."""
682 from IPython.core.interactiveshell import InteractiveShell
682 from IPython.core.interactiveshell import InteractiveShell
683 if InteractiveShell.initialized():
683 if InteractiveShell.initialized():
684 InteractiveShell.instance().display_pub.clear_output(wait)
684 InteractiveShell.instance().display_pub.clear_output(wait)
685 else:
685 else:
686 from IPython.utils import io
686 from IPython.utils import io
687 print('\033[2K\r', file=io.stdout, end='')
687 print('\033[2K\r', file=io.stdout, end='')
688 io.stdout.flush()
688 io.stdout.flush()
689 print('\033[2K\r', file=io.stderr, end='')
689 print('\033[2K\r', file=io.stderr, end='')
690 io.stderr.flush()
690 io.stderr.flush()
General Comments 0
You need to be logged in to leave comments. Login now