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