##// END OF EJS Templates
implement GIF support without registering a new formatter...
Min RK -
Show More
@@ -1,1372 +1,1357 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Top-level display functions for displaying object in different formats."""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7
8 8 try:
9 9 from base64 import encodebytes as base64_encode
10 10 except ImportError:
11 11 from base64 import encodestring as base64_encode
12 12
13 13 from binascii import b2a_hex
14 14 import json
15 15 import mimetypes
16 16 import os
17 17 import struct
18 18 import sys
19 19 import warnings
20 20 from copy import deepcopy
21 21
22 22 from IPython.utils.py3compat import cast_unicode
23 23 from IPython.testing.skipdoctest import skip_doctest
24 24
25 25 __all__ = ['display', 'display_pretty', 'display_html', 'display_markdown',
26 'display_svg', 'display_png', 'display_jpeg', 'display_gif', 'display_latex', 'display_json',
26 'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
27 27 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
28 28 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'JSON', 'GeoJSON', 'Javascript',
29 29 'Image', 'clear_output', 'set_matplotlib_formats', 'set_matplotlib_close',
30 30 'publish_display_data', 'update_display', 'DisplayHandle', 'Video']
31 31
32 32 #-----------------------------------------------------------------------------
33 33 # utility functions
34 34 #-----------------------------------------------------------------------------
35 35
36 36 def _safe_exists(path):
37 37 """Check path, but don't let exceptions raise"""
38 38 try:
39 39 return os.path.exists(path)
40 40 except Exception:
41 41 return False
42 42
43 43 def _merge(d1, d2):
44 44 """Like update, but merges sub-dicts instead of clobbering at the top level.
45 45
46 46 Updates d1 in-place
47 47 """
48 48
49 49 if not isinstance(d2, dict) or not isinstance(d1, dict):
50 50 return d2
51 51 for key, value in d2.items():
52 52 d1[key] = _merge(d1.get(key), value)
53 53 return d1
54 54
55 55 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
56 56 """internal implementation of all display_foo methods
57 57
58 58 Parameters
59 59 ----------
60 60 mimetype : str
61 61 The mimetype to be published (e.g. 'image/png')
62 62 objs : tuple of objects
63 63 The Python objects to display, or if raw=True raw text data to
64 64 display.
65 65 raw : bool
66 66 Are the data objects raw data or Python objects that need to be
67 67 formatted before display? [default: False]
68 68 metadata : dict (optional)
69 69 Metadata to be associated with the specific mimetype output.
70 70 """
71 71 if metadata:
72 72 metadata = {mimetype: metadata}
73 73 if raw:
74 74 # turn list of pngdata into list of { 'image/png': pngdata }
75 75 objs = [ {mimetype: obj} for obj in objs ]
76 76 display(*objs, raw=raw, metadata=metadata, include=[mimetype])
77 77
78 78 #-----------------------------------------------------------------------------
79 79 # Main functions
80 80 #-----------------------------------------------------------------------------
81 81
82 82 # use * to indicate transient is keyword-only
83 83 def publish_display_data(data, metadata=None, source=None, *, transient=None, **kwargs):
84 84 """Publish data and metadata to all frontends.
85 85
86 86 See the ``display_data`` message in the messaging documentation for
87 87 more details about this message type.
88 88
89 The following MIME types are currently implemented:
90
91 * text/plain
92 * text/html
93 * text/markdown
94 * text/latex
95 * application/json
96 * application/javascript
97 * image/png
98 * image/jpeg
99 * image/gif
100 * image/svg+xml
89 Keys of data and metadata can be any mime-type.
101 90
102 91 Parameters
103 92 ----------
104 93 data : dict
105 94 A dictionary having keys that are valid MIME types (like
106 95 'text/plain' or 'image/svg+xml') and values that are the data for
107 96 that MIME type. The data itself must be a JSON'able data
108 97 structure. Minimally all data should have the 'text/plain' data,
109 98 which can be displayed by all frontends. If more than the plain
110 99 text is given, it is up to the frontend to decide which
111 100 representation to use.
112 101 metadata : dict
113 102 A dictionary for metadata related to the data. This can contain
114 103 arbitrary key, value pairs that frontends can use to interpret
115 104 the data. mime-type keys matching those in data can be used
116 105 to specify metadata about particular representations.
117 106 source : str, deprecated
118 107 Unused.
119 108 transient : dict, keyword-only
120 109 A dictionary of transient data, such as display_id.
121 110 """
122 111 from IPython.core.interactiveshell import InteractiveShell
123 112
124 113 display_pub = InteractiveShell.instance().display_pub
125 114
126 115 # only pass transient if supplied,
127 116 # to avoid errors with older ipykernel.
128 117 # TODO: We could check for ipykernel version and provide a detailed upgrade message.
129 118 if transient:
130 119 kwargs['transient'] = transient
131 120
132 121 display_pub.publish(
133 122 data=data,
134 123 metadata=metadata,
135 124 **kwargs
136 125 )
137 126
138 127
139 128 def _new_id():
140 129 """Generate a new random text id with urandom"""
141 130 return b2a_hex(os.urandom(16)).decode('ascii')
142 131
143 132
144 133 def display(*objs, include=None, exclude=None, metadata=None, transient=None, display_id=None, **kwargs):
145 134 """Display a Python object in all frontends.
146 135
147 136 By default all representations will be computed and sent to the frontends.
148 137 Frontends can decide which representation is used and how.
149 138
150 139 In terminal IPython this will be similar to using :func:`print`, for use in richer
151 140 frontends see Jupyter notebook examples with rich display logic.
152 141
153 142 Parameters
154 143 ----------
155 144 objs : tuple of objects
156 145 The Python objects to display.
157 146 raw : bool, optional
158 147 Are the objects to be displayed already mimetype-keyed dicts of raw display data,
159 148 or Python objects that need to be formatted before display? [default: False]
160 149 include : list, tuple or set, optional
161 150 A list of format type strings (MIME types) to include in the
162 151 format data dict. If this is set *only* the format types included
163 152 in this list will be computed.
164 153 exclude : list, tuple or set, optional
165 154 A list of format type strings (MIME types) to exclude in the format
166 155 data dict. If this is set all format types will be computed,
167 156 except for those included in this argument.
168 157 metadata : dict, optional
169 158 A dictionary of metadata to associate with the output.
170 159 mime-type keys in this dictionary will be associated with the individual
171 160 representation formats, if they exist.
172 161 transient : dict, optional
173 162 A dictionary of transient data to associate with the output.
174 163 Data in this dict should not be persisted to files (e.g. notebooks).
175 164 display_id : str, bool optional
176 165 Set an id for the display.
177 166 This id can be used for updating this display area later via update_display.
178 167 If given as `True`, generate a new `display_id`
179 168 kwargs: additional keyword-args, optional
180 169 Additional keyword-arguments are passed through to the display publisher.
181 170
182 171 Returns
183 172 -------
184 173
185 174 handle: DisplayHandle
186 175 Returns a handle on updatable displays for use with :func:`update_display`,
187 176 if `display_id` is given. Returns :any:`None` if no `display_id` is given
188 177 (default).
189 178
190 179 Examples
191 180 --------
192 181
193 182 >>> class Json(object):
194 183 ... def __init__(self, json):
195 184 ... self.json = json
196 185 ... def _repr_pretty_(self, pp, cycle):
197 186 ... import json
198 187 ... pp.text(json.dumps(self.json, indent=2))
199 188 ... def __repr__(self):
200 189 ... return str(self.json)
201 190 ...
202 191
203 192 >>> d = Json({1:2, 3: {4:5}})
204 193
205 194 >>> print(d)
206 195 {1: 2, 3: {4: 5}}
207 196
208 197 >>> display(d)
209 198 {
210 199 "1": 2,
211 200 "3": {
212 201 "4": 5
213 202 }
214 203 }
215 204
216 205 >>> def int_formatter(integer, pp, cycle):
217 206 ... pp.text('I'*integer)
218 207
219 208 >>> plain = get_ipython().display_formatter.formatters['text/plain']
220 209 >>> plain.for_type(int, int_formatter)
221 210 <function _repr_pprint at 0x...>
222 211 >>> display(7-5)
223 212 II
224 213
225 214 >>> del plain.type_printers[int]
226 215 >>> display(7-5)
227 216 2
228 217
229 218 See Also
230 219 --------
231 220
232 221 :func:`update_display`
233 222
234 223 Notes
235 224 -----
236 225
237 226 In Python, objects can declare their textual representation using the
238 227 `__repr__` method. IPython expands on this idea and allows objects to declare
239 228 other, rich representations including:
240 229
241 230 - HTML
242 231 - JSON
243 232 - PNG
244 233 - JPEG
245 234 - SVG
246 235 - LaTeX
247 236
248 237 A single object can declare some or all of these representations; all are
249 238 handled by IPython's display system.
250 239
251 240 The main idea of the first approach is that you have to implement special
252 241 display methods when you define your class, one for each representation you
253 242 want to use. Here is a list of the names of the special methods and the
254 243 values they must return:
255 244
256 245 - `_repr_html_`: return raw HTML as a string
257 246 - `_repr_json_`: return a JSONable dict
258 247 - `_repr_jpeg_`: return raw JPEG data
259 248 - `_repr_png_`: return raw PNG data
260 - `_repr_gif_`: return raw GIF data
261 249 - `_repr_svg_`: return raw SVG data as a string
262 250 - `_repr_latex_`: return LaTeX commands in a string surrounded by "$".
263 251 - `_repr_mimebundle_`: return a full mimebundle containing the mapping
264 from all mimetypes to data
252 from all mimetypes to data.
253 Use this for any mime-type not listed above.
265 254
266 255 When you are directly writing your own classes, you can adapt them for
267 256 display in IPython by following the above approach. But in practice, you
268 257 often need to work with existing classes that you can't easily modify.
269 258
270 259 You can refer to the documentation on IPython display formatters in order to
271 260 register custom formatters for already existing types.
272 261
273 262 .. versionadded:: 5.4 display available without import
274 263 .. versionadded:: 6.1 display available without import
275 264
276 265 Since IPython 5.4 and 6.1 :func:`display` is automatically made available to
277 266 the user without import. If you are using display in a document that might
278 267 be used in a pure python context or with older version of IPython, use the
279 268 following import at the top of your file::
280 269
281 270 from IPython.display import display
282 271
283 272 """
284 273 from IPython.core.interactiveshell import InteractiveShell
285 274
286 275 if not InteractiveShell.initialized():
287 276 # Directly print objects.
288 277 print(*objs)
289 278 return
290 279
291 280 raw = kwargs.pop('raw', False)
292 281 if transient is None:
293 282 transient = {}
294 283 if metadata is None:
295 284 metadata={}
296 285 if display_id:
297 286 if display_id is True:
298 287 display_id = _new_id()
299 288 transient['display_id'] = display_id
300 289 if kwargs.get('update') and 'display_id' not in transient:
301 290 raise TypeError('display_id required for update_display')
302 291 if transient:
303 292 kwargs['transient'] = transient
304 293
305 294 if not raw:
306 295 format = InteractiveShell.instance().display_formatter.format
307 296
308 297 for obj in objs:
309 298 if raw:
310 299 publish_display_data(data=obj, metadata=metadata, **kwargs)
311 300 else:
312 301 format_dict, md_dict = format(obj, include=include, exclude=exclude)
313 302 if not format_dict:
314 303 # nothing to display (e.g. _ipython_display_ took over)
315 304 continue
316 305 if metadata:
317 306 # kwarg-specified metadata gets precedence
318 307 _merge(md_dict, metadata)
319 308 publish_display_data(data=format_dict, metadata=md_dict, **kwargs)
320 309 if display_id:
321 310 return DisplayHandle(display_id)
322 311
323 312
324 313 # use * for keyword-only display_id arg
325 314 def update_display(obj, *, display_id, **kwargs):
326 315 """Update an existing display by id
327 316
328 317 Parameters
329 318 ----------
330 319
331 320 obj:
332 321 The object with which to update the display
333 322 display_id: keyword-only
334 323 The id of the display to update
335 324
336 325 See Also
337 326 --------
338 327
339 328 :func:`display`
340 329 """
341 330 kwargs['update'] = True
342 331 display(obj, display_id=display_id, **kwargs)
343 332
344 333
345 334 class DisplayHandle(object):
346 335 """A handle on an updatable display
347 336
348 337 Call `.update(obj)` to display a new object.
349 338
350 339 Call `.display(obj`) to add a new instance of this display,
351 340 and update existing instances.
352 341
353 342 See Also
354 343 --------
355 344
356 345 :func:`display`, :func:`update_display`
357 346
358 347 """
359 348
360 349 def __init__(self, display_id=None):
361 350 if display_id is None:
362 351 display_id = _new_id()
363 352 self.display_id = display_id
364 353
365 354 def __repr__(self):
366 355 return "<%s display_id=%s>" % (self.__class__.__name__, self.display_id)
367 356
368 357 def display(self, obj, **kwargs):
369 358 """Make a new display with my id, updating existing instances.
370 359
371 360 Parameters
372 361 ----------
373 362
374 363 obj:
375 364 object to display
376 365 **kwargs:
377 366 additional keyword arguments passed to display
378 367 """
379 368 display(obj, display_id=self.display_id, **kwargs)
380 369
381 370 def update(self, obj, **kwargs):
382 371 """Update existing displays with my id
383 372
384 373 Parameters
385 374 ----------
386 375
387 376 obj:
388 377 object to display
389 378 **kwargs:
390 379 additional keyword arguments passed to update_display
391 380 """
392 381 update_display(obj, display_id=self.display_id, **kwargs)
393 382
394 383
395 384 def display_pretty(*objs, **kwargs):
396 385 """Display the pretty (default) representation of an object.
397 386
398 387 Parameters
399 388 ----------
400 389 objs : tuple of objects
401 390 The Python objects to display, or if raw=True raw text data to
402 391 display.
403 392 raw : bool
404 393 Are the data objects raw data or Python objects that need to be
405 394 formatted before display? [default: False]
406 395 metadata : dict (optional)
407 396 Metadata to be associated with the specific mimetype output.
408 397 """
409 398 _display_mimetype('text/plain', objs, **kwargs)
410 399
411 400
412 401 def display_html(*objs, **kwargs):
413 402 """Display the HTML representation of an object.
414 403
415 404 Note: If raw=False and the object does not have a HTML
416 405 representation, no HTML will be shown.
417 406
418 407 Parameters
419 408 ----------
420 409 objs : tuple of objects
421 410 The Python objects to display, or if raw=True raw HTML data to
422 411 display.
423 412 raw : bool
424 413 Are the data objects raw data or Python objects that need to be
425 414 formatted before display? [default: False]
426 415 metadata : dict (optional)
427 416 Metadata to be associated with the specific mimetype output.
428 417 """
429 418 _display_mimetype('text/html', objs, **kwargs)
430 419
431 420
432 421 def display_markdown(*objs, **kwargs):
433 422 """Displays the Markdown representation of an object.
434 423
435 424 Parameters
436 425 ----------
437 426 objs : tuple of objects
438 427 The Python objects to display, or if raw=True raw markdown data to
439 428 display.
440 429 raw : bool
441 430 Are the data objects raw data or Python objects that need to be
442 431 formatted before display? [default: False]
443 432 metadata : dict (optional)
444 433 Metadata to be associated with the specific mimetype output.
445 434 """
446 435
447 436 _display_mimetype('text/markdown', objs, **kwargs)
448 437
449 438
450 439 def display_svg(*objs, **kwargs):
451 440 """Display the SVG representation of an object.
452 441
453 442 Parameters
454 443 ----------
455 444 objs : tuple of objects
456 445 The Python objects to display, or if raw=True raw svg data to
457 446 display.
458 447 raw : bool
459 448 Are the data objects raw data or Python objects that need to be
460 449 formatted before display? [default: False]
461 450 metadata : dict (optional)
462 451 Metadata to be associated with the specific mimetype output.
463 452 """
464 453 _display_mimetype('image/svg+xml', objs, **kwargs)
465 454
466 455
467 456 def display_png(*objs, **kwargs):
468 457 """Display the PNG representation of an object.
469 458
470 459 Parameters
471 460 ----------
472 461 objs : tuple of objects
473 462 The Python objects to display, or if raw=True raw png data to
474 463 display.
475 464 raw : bool
476 465 Are the data objects raw data or Python objects that need to be
477 466 formatted before display? [default: False]
478 467 metadata : dict (optional)
479 468 Metadata to be associated with the specific mimetype output.
480 469 """
481 470 _display_mimetype('image/png', objs, **kwargs)
482 471
483 472
484 473 def display_jpeg(*objs, **kwargs):
485 474 """Display the JPEG representation of an object.
486 475
487 476 Parameters
488 477 ----------
489 478 objs : tuple of objects
490 479 The Python objects to display, or if raw=True raw JPEG data to
491 480 display.
492 481 raw : bool
493 482 Are the data objects raw data or Python objects that need to be
494 483 formatted before display? [default: False]
495 484 metadata : dict (optional)
496 485 Metadata to be associated with the specific mimetype output.
497 486 """
498 487 _display_mimetype('image/jpeg', objs, **kwargs)
499
500 def display_gif(*objs, **kwargs):
501 """Display the GIF representation of an object.
502
503 Parameters
504 ----------
505 objs : tuple of objects
506 The Python objects to display, or if raw=True raw gif data to
507 display.
508 raw : bool
509 Are the data objects raw data or Python objects that need to be
510 formatted before display? [default: False]
511 metadata : dict (optional)
512 Metadata to be associated with the specific mimetype output.
513 """
514 _display_mimetype('image/gif', objs, **kwargs)
515 488
516 489
517 490 def display_latex(*objs, **kwargs):
518 491 """Display the LaTeX representation of an object.
519 492
520 493 Parameters
521 494 ----------
522 495 objs : tuple of objects
523 496 The Python objects to display, or if raw=True raw latex data to
524 497 display.
525 498 raw : bool
526 499 Are the data objects raw data or Python objects that need to be
527 500 formatted before display? [default: False]
528 501 metadata : dict (optional)
529 502 Metadata to be associated with the specific mimetype output.
530 503 """
531 504 _display_mimetype('text/latex', objs, **kwargs)
532 505
533 506
534 507 def display_json(*objs, **kwargs):
535 508 """Display the JSON representation of an object.
536 509
537 510 Note that not many frontends support displaying JSON.
538 511
539 512 Parameters
540 513 ----------
541 514 objs : tuple of objects
542 515 The Python objects to display, or if raw=True raw json data to
543 516 display.
544 517 raw : bool
545 518 Are the data objects raw data or Python objects that need to be
546 519 formatted before display? [default: False]
547 520 metadata : dict (optional)
548 521 Metadata to be associated with the specific mimetype output.
549 522 """
550 523 _display_mimetype('application/json', objs, **kwargs)
551 524
552 525
553 526 def display_javascript(*objs, **kwargs):
554 527 """Display the Javascript representation of an object.
555 528
556 529 Parameters
557 530 ----------
558 531 objs : tuple of objects
559 532 The Python objects to display, or if raw=True raw javascript data to
560 533 display.
561 534 raw : bool
562 535 Are the data objects raw data or Python objects that need to be
563 536 formatted before display? [default: False]
564 537 metadata : dict (optional)
565 538 Metadata to be associated with the specific mimetype output.
566 539 """
567 540 _display_mimetype('application/javascript', objs, **kwargs)
568 541
569 542
570 543 def display_pdf(*objs, **kwargs):
571 544 """Display the PDF representation of an object.
572 545
573 546 Parameters
574 547 ----------
575 548 objs : tuple of objects
576 549 The Python objects to display, or if raw=True raw javascript data to
577 550 display.
578 551 raw : bool
579 552 Are the data objects raw data or Python objects that need to be
580 553 formatted before display? [default: False]
581 554 metadata : dict (optional)
582 555 Metadata to be associated with the specific mimetype output.
583 556 """
584 557 _display_mimetype('application/pdf', objs, **kwargs)
585 558
586 559
587 560 #-----------------------------------------------------------------------------
588 561 # Smart classes
589 562 #-----------------------------------------------------------------------------
590 563
591 564
592 565 class DisplayObject(object):
593 566 """An object that wraps data to be displayed."""
594 567
595 568 _read_flags = 'r'
596 569 _show_mem_addr = False
597 570 metadata = None
598 571
599 572 def __init__(self, data=None, url=None, filename=None, metadata=None):
600 573 """Create a display object given raw data.
601 574
602 575 When this object is returned by an expression or passed to the
603 576 display function, it will result in the data being displayed
604 577 in the frontend. The MIME type of the data should match the
605 578 subclasses used, so the Png subclass should be used for 'image/png'
606 579 data. If the data is a URL, the data will first be downloaded
607 580 and then displayed. If
608 581
609 582 Parameters
610 583 ----------
611 584 data : unicode, str or bytes
612 585 The raw data or a URL or file to load the data from
613 586 url : unicode
614 587 A URL to download the data from.
615 588 filename : unicode
616 589 Path to a local file to load the data from.
617 590 metadata : dict
618 591 Dict of metadata associated to be the object when displayed
619 592 """
620 593 if data is not None and isinstance(data, str):
621 594 if data.startswith('http') and url is None:
622 595 url = data
623 596 filename = None
624 597 data = None
625 598 elif _safe_exists(data) and filename is None:
626 599 url = None
627 600 filename = data
628 601 data = None
629 602
630 603 self.data = data
631 604 self.url = url
632 605 self.filename = filename
633 606
634 607 if metadata is not None:
635 608 self.metadata = metadata
636 609 elif self.metadata is None:
637 610 self.metadata = {}
638 611
639 612 self.reload()
640 613 self._check_data()
641 614
642 615 def __repr__(self):
643 616 if not self._show_mem_addr:
644 617 cls = self.__class__
645 618 r = "<%s.%s object>" % (cls.__module__, cls.__name__)
646 619 else:
647 620 r = super(DisplayObject, self).__repr__()
648 621 return r
649 622
650 623 def _check_data(self):
651 624 """Override in subclasses if there's something to check."""
652 625 pass
653 626
654 627 def _data_and_metadata(self):
655 628 """shortcut for returning metadata with shape information, if defined"""
656 629 if self.metadata:
657 630 return self.data, deepcopy(self.metadata)
658 631 else:
659 632 return self.data
660 633
661 634 def reload(self):
662 635 """Reload the raw data from file or URL."""
663 636 if self.filename is not None:
664 637 with open(self.filename, self._read_flags) as f:
665 638 self.data = f.read()
666 639 elif self.url is not None:
667 640 try:
668 641 # Deferred import
669 642 from urllib.request import urlopen
670 643 response = urlopen(self.url)
671 644 self.data = response.read()
672 645 # extract encoding from header, if there is one:
673 646 encoding = None
674 647 for sub in response.headers['content-type'].split(';'):
675 648 sub = sub.strip()
676 649 if sub.startswith('charset'):
677 650 encoding = sub.split('=')[-1].strip()
678 651 break
679 652 # decode data, if an encoding was specified
680 653 if encoding:
681 654 self.data = self.data.decode(encoding, 'replace')
682 655 except:
683 656 self.data = None
684 657
685 658 class TextDisplayObject(DisplayObject):
686 659 """Validate that display data is text"""
687 660 def _check_data(self):
688 661 if self.data is not None and not isinstance(self.data, str):
689 662 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
690 663
691 664 class Pretty(TextDisplayObject):
692 665
693 666 def _repr_pretty_(self, pp, cycle):
694 667 return pp.text(self.data)
695 668
696 669
697 670 class HTML(TextDisplayObject):
698 671
699 672 def _repr_html_(self):
700 673 return self.data
701 674
702 675 def __html__(self):
703 676 """
704 677 This method exists to inform other HTML-using modules (e.g. Markupsafe,
705 678 htmltag, etc) that this object is HTML and does not need things like
706 679 special characters (<>&) escaped.
707 680 """
708 681 return self._repr_html_()
709 682
710 683
711 684 class Markdown(TextDisplayObject):
712 685
713 686 def _repr_markdown_(self):
714 687 return self.data
715 688
716 689
717 690 class Math(TextDisplayObject):
718 691
719 692 def _repr_latex_(self):
720 693 s = self.data.strip('$')
721 694 return "$$%s$$" % s
722 695
723 696
724 697 class Latex(TextDisplayObject):
725 698
726 699 def _repr_latex_(self):
727 700 return self.data
728 701
729 702
730 703 class SVG(DisplayObject):
731 704
732 705 _read_flags = 'rb'
733 706 # wrap data in a property, which extracts the <svg> tag, discarding
734 707 # document headers
735 708 _data = None
736 709
737 710 @property
738 711 def data(self):
739 712 return self._data
740 713
741 714 @data.setter
742 715 def data(self, svg):
743 716 if svg is None:
744 717 self._data = None
745 718 return
746 719 # parse into dom object
747 720 from xml.dom import minidom
748 721 x = minidom.parseString(svg)
749 722 # get svg tag (should be 1)
750 723 found_svg = x.getElementsByTagName('svg')
751 724 if found_svg:
752 725 svg = found_svg[0].toxml()
753 726 else:
754 727 # fallback on the input, trust the user
755 728 # but this is probably an error.
756 729 pass
757 730 svg = cast_unicode(svg)
758 731 self._data = svg
759 732
760 733 def _repr_svg_(self):
761 734 return self._data_and_metadata()
762 735
763 736
764 737 class JSON(DisplayObject):
765 738 """JSON expects a JSON-able dict or list
766 739
767 740 not an already-serialized JSON string.
768 741
769 742 Scalar types (None, number, string) are not allowed, only dict or list containers.
770 743 """
771 744 # wrap data in a property, which warns about passing already-serialized JSON
772 745 _data = None
773 746 def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None, **kwargs):
774 747 """Create a JSON display object given raw data.
775 748
776 749 Parameters
777 750 ----------
778 751 data : dict or list
779 752 JSON data to display. Not an already-serialized JSON string.
780 753 Scalar types (None, number, string) are not allowed, only dict
781 754 or list containers.
782 755 url : unicode
783 756 A URL to download the data from.
784 757 filename : unicode
785 758 Path to a local file to load the data from.
786 759 expanded : boolean
787 760 Metadata to control whether a JSON display component is expanded.
788 761 metadata: dict
789 762 Specify extra metadata to attach to the json display object.
790 763 """
791 764 self.metadata = {'expanded': expanded}
792 765 if metadata:
793 766 self.metadata.update(metadata)
794 767 if kwargs:
795 768 self.metadata.update(kwargs)
796 769 super(JSON, self).__init__(data=data, url=url, filename=filename)
797 770
798 771 def _check_data(self):
799 772 if self.data is not None and not isinstance(self.data, (dict, list)):
800 773 raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
801 774
802 775 @property
803 776 def data(self):
804 777 return self._data
805 778
806 779 @data.setter
807 780 def data(self, data):
808 781 if isinstance(data, str):
809 782 if getattr(self, 'filename', None) is None:
810 783 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
811 784 data = json.loads(data)
812 785 self._data = data
813 786
814 787 def _data_and_metadata(self):
815 788 return self.data, self.metadata
816 789
817 790 def _repr_json_(self):
818 791 return self._data_and_metadata()
819 792
820 793 _css_t = """$("head").append($("<link/>").attr({
821 794 rel: "stylesheet",
822 795 type: "text/css",
823 796 href: "%s"
824 797 }));
825 798 """
826 799
827 800 _lib_t1 = """$.getScript("%s", function () {
828 801 """
829 802 _lib_t2 = """});
830 803 """
831 804
832 805 class GeoJSON(JSON):
833 806 """GeoJSON expects JSON-able dict
834 807
835 808 not an already-serialized JSON string.
836 809
837 810 Scalar types (None, number, string) are not allowed, only dict containers.
838 811 """
839 812
840 813 def __init__(self, *args, **kwargs):
841 814 """Create a GeoJSON display object given raw data.
842 815
843 816 Parameters
844 817 ----------
845 818 data : dict or list
846 819 VegaLite data. Not an already-serialized JSON string.
847 820 Scalar types (None, number, string) are not allowed, only dict
848 821 or list containers.
849 822 url_template : string
850 823 Leaflet TileLayer URL template: http://leafletjs.com/reference.html#url-template
851 824 layer_options : dict
852 825 Leaflet TileLayer options: http://leafletjs.com/reference.html#tilelayer-options
853 826 url : unicode
854 827 A URL to download the data from.
855 828 filename : unicode
856 829 Path to a local file to load the data from.
857 830 metadata: dict
858 831 Specify extra metadata to attach to the json display object.
859 832
860 833 Examples
861 834 --------
862 835
863 836 The following will display an interactive map of Mars with a point of
864 837 interest on frontend that do support GeoJSON display.
865 838
866 839 >>> from IPython.display import GeoJSON
867 840
868 841 >>> GeoJSON(data={
869 842 ... "type": "Feature",
870 843 ... "geometry": {
871 844 ... "type": "Point",
872 845 ... "coordinates": [-81.327, 296.038]
873 846 ... }
874 847 ... },
875 848 ... url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
876 849 ... layer_options={
877 850 ... "basemap_id": "celestia_mars-shaded-16k_global",
878 851 ... "attribution" : "Celestia/praesepe",
879 852 ... "minZoom" : 0,
880 853 ... "maxZoom" : 18,
881 854 ... })
882 855 <IPython.core.display.GeoJSON object>
883 856
884 857 In the terminal IPython, you will only see the text representation of
885 858 the GeoJSON object.
886 859
887 860 """
888 861
889 862 super(GeoJSON, self).__init__(*args, **kwargs)
890 863
891 864
892 865 def _ipython_display_(self):
893 866 bundle = {
894 867 'application/geo+json': self.data,
895 868 'text/plain': '<IPython.display.GeoJSON object>'
896 869 }
897 870 metadata = {
898 871 'application/geo+json': self.metadata
899 872 }
900 873 display(bundle, metadata=metadata, raw=True)
901 874
902 875 class Javascript(TextDisplayObject):
903 876
904 877 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
905 878 """Create a Javascript display object given raw data.
906 879
907 880 When this object is returned by an expression or passed to the
908 881 display function, it will result in the data being displayed
909 882 in the frontend. If the data is a URL, the data will first be
910 883 downloaded and then displayed.
911 884
912 885 In the Notebook, the containing element will be available as `element`,
913 886 and jQuery will be available. Content appended to `element` will be
914 887 visible in the output area.
915 888
916 889 Parameters
917 890 ----------
918 891 data : unicode, str or bytes
919 892 The Javascript source code or a URL to download it from.
920 893 url : unicode
921 894 A URL to download the data from.
922 895 filename : unicode
923 896 Path to a local file to load the data from.
924 897 lib : list or str
925 898 A sequence of Javascript library URLs to load asynchronously before
926 899 running the source code. The full URLs of the libraries should
927 900 be given. A single Javascript library URL can also be given as a
928 901 string.
929 902 css: : list or str
930 903 A sequence of css files to load before running the source code.
931 904 The full URLs of the css files should be given. A single css URL
932 905 can also be given as a string.
933 906 """
934 907 if isinstance(lib, str):
935 908 lib = [lib]
936 909 elif lib is None:
937 910 lib = []
938 911 if isinstance(css, str):
939 912 css = [css]
940 913 elif css is None:
941 914 css = []
942 915 if not isinstance(lib, (list,tuple)):
943 916 raise TypeError('expected sequence, got: %r' % lib)
944 917 if not isinstance(css, (list,tuple)):
945 918 raise TypeError('expected sequence, got: %r' % css)
946 919 self.lib = lib
947 920 self.css = css
948 921 super(Javascript, self).__init__(data=data, url=url, filename=filename)
949 922
950 923 def _repr_javascript_(self):
951 924 r = ''
952 925 for c in self.css:
953 926 r += _css_t % c
954 927 for l in self.lib:
955 928 r += _lib_t1 % l
956 929 r += self.data
957 930 r += _lib_t2*len(self.lib)
958 931 return r
959 932
960 933 # constants for identifying png/jpeg data
961 934 _PNG = b'\x89PNG\r\n\x1a\n'
962 935 _JPEG = b'\xff\xd8'
963 936
964 937 def _pngxy(data):
965 938 """read the (width, height) from a PNG header"""
966 939 ihdr = data.index(b'IHDR')
967 940 # next 8 bytes are width/height
968 941 return struct.unpack('>ii', data[ihdr+4:ihdr+12])
969 942
970 943 def _jpegxy(data):
971 944 """read the (width, height) from a JPEG header"""
972 945 # adapted from http://www.64lines.com/jpeg-width-height
973 946
974 947 idx = 4
975 948 while True:
976 949 block_size = struct.unpack('>H', data[idx:idx+2])[0]
977 950 idx = idx + block_size
978 951 if data[idx:idx+2] == b'\xFF\xC0':
979 952 # found Start of Frame
980 953 iSOF = idx
981 954 break
982 955 else:
983 956 # read another block
984 957 idx += 2
985 958
986 959 return struct.unpack('>HH', data[iSOF+5:iSOF+9])
987
960
988 961 def _gifxy(data):
989 962 """read the (width, height) from a GIF header"""
990 963 return struct.unpack('<HH', data[6:10])
991 964
965
992 966 class Image(DisplayObject):
993 967
994 968 _read_flags = 'rb'
995 969 _FMT_JPEG = u'jpeg'
996 970 _FMT_PNG = u'png'
997 971 _FMT_GIF = u'gif'
998 972 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF]
973 _MIMETYPES = {
974 _FMT_PNG: 'image/png',
975 _FMT_JPEG: 'image/jpeg',
976 _FMT_GIF: 'image/gif',
977 }
999 978
1000 979 def __init__(self, data=None, url=None, filename=None, format=None,
1001 980 embed=None, width=None, height=None, retina=False,
1002 981 unconfined=False, metadata=None):
1003 982 """Create a PNG/JPEG/GIF image object given raw data.
1004 983
1005 984 When this object is returned by an input cell or passed to the
1006 985 display function, it will result in the image being displayed
1007 986 in the frontend.
1008 987
1009 988 Parameters
1010 989 ----------
1011 990 data : unicode, str or bytes
1012 991 The raw image data or a URL or filename to load the data from.
1013 992 This always results in embedded image data.
1014 993 url : unicode
1015 994 A URL to download the data from. If you specify `url=`,
1016 995 the image data will not be embedded unless you also specify `embed=True`.
1017 996 filename : unicode
1018 997 Path to a local file to load the data from.
1019 998 Images from a file are always embedded.
1020 999 format : unicode
1021 1000 The format of the image data (png/jpeg/jpg/gif). If a filename or URL is given
1022 1001 for format will be inferred from the filename extension.
1023 1002 embed : bool
1024 1003 Should the image data be embedded using a data URI (True) or be
1025 1004 loaded using an <img> tag. Set this to True if you want the image
1026 1005 to be viewable later with no internet connection in the notebook.
1027 1006
1028 1007 Default is `True`, unless the keyword argument `url` is set, then
1029 1008 default value is `False`.
1030 1009
1031 1010 Note that QtConsole is not able to display images if `embed` is set to `False`
1032 1011 width : int
1033 1012 Width in pixels to which to constrain the image in html
1034 1013 height : int
1035 1014 Height in pixels to which to constrain the image in html
1036 1015 retina : bool
1037 1016 Automatically set the width and height to half of the measured
1038 1017 width and height.
1039 1018 This only works for embedded images because it reads the width/height
1040 1019 from image data.
1041 1020 For non-embedded images, you can just set the desired display width
1042 1021 and height directly.
1043 1022 unconfined: bool
1044 1023 Set unconfined=True to disable max-width confinement of the image.
1045 1024 metadata: dict
1046 1025 Specify extra metadata to attach to the image.
1047 1026
1048 1027 Examples
1049 1028 --------
1050 1029 # embedded image data, works in qtconsole and notebook
1051 1030 # when passed positionally, the first arg can be any of raw image data,
1052 1031 # a URL, or a filename from which to load image data.
1053 1032 # The result is always embedding image data for inline images.
1054 1033 Image('http://www.google.fr/images/srpr/logo3w.png')
1055 1034 Image('/path/to/image.jpg')
1056 1035 Image(b'RAW_PNG_DATA...')
1057 1036
1058 1037 # Specifying Image(url=...) does not embed the image data,
1059 1038 # it only generates `<img>` tag with a link to the source.
1060 1039 # This will not work in the qtconsole or offline.
1061 1040 Image(url='http://www.google.fr/images/srpr/logo3w.png')
1062 1041
1063 1042 """
1064 1043 if filename is not None:
1065 1044 ext = self._find_ext(filename)
1066 1045 elif url is not None:
1067 1046 ext = self._find_ext(url)
1068 1047 elif data is None:
1069 1048 raise ValueError("No image data found. Expecting filename, url, or data.")
1070 1049 elif isinstance(data, str) and (
1071 1050 data.startswith('http') or _safe_exists(data)
1072 1051 ):
1073 1052 ext = self._find_ext(data)
1074 1053 else:
1075 1054 ext = None
1076 1055
1077 1056 if format is None:
1078 1057 if ext is not None:
1079 1058 if ext == u'jpg' or ext == u'jpeg':
1080 1059 format = self._FMT_JPEG
1081 1060 if ext == u'png':
1082 1061 format = self._FMT_PNG
1083 1062 if ext == u'gif':
1084 1063 format = self._FMT_GIF
1085 1064 else:
1086 1065 format = ext.lower()
1087 1066 elif isinstance(data, bytes):
1088 1067 # infer image type from image data header,
1089 1068 # only if format has not been specified.
1090 1069 if data[:2] == _JPEG:
1091 1070 format = self._FMT_JPEG
1092 1071
1093 1072 # failed to detect format, default png
1094 1073 if format is None:
1095 1074 format = self._FMT_PNG
1096 1075
1097 1076 if format.lower() == 'jpg':
1098 1077 # jpg->jpeg
1099 1078 format = self._FMT_JPEG
1100
1079
1101 1080 self.format = format.lower()
1102 1081 self.embed = embed if embed is not None else (url is None)
1103 1082
1104 1083 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
1105 1084 raise ValueError("Cannot embed the '%s' image format" % (self.format))
1085 if self.embed:
1086 self._mimetype = self._MIMETYPES.get(self.format)
1087
1106 1088 self.width = width
1107 1089 self.height = height
1108 1090 self.retina = retina
1109 1091 self.unconfined = unconfined
1110 1092 super(Image, self).__init__(data=data, url=url, filename=filename,
1111 1093 metadata=metadata)
1112 1094
1113 1095 if self.width is None and self.metadata.get('width', {}):
1114 1096 self.width = metadata['width']
1115 1097
1116 1098 if self.height is None and self.metadata.get('height', {}):
1117 1099 self.height = metadata['height']
1118 1100
1119 1101 if retina:
1120 1102 self._retina_shape()
1121 1103
1104
1122 1105 def _retina_shape(self):
1123 1106 """load pixel-doubled width and height from image data"""
1124 1107 if not self.embed:
1125 1108 return
1126 1109 if self.format == self._FMT_PNG:
1127 1110 w, h = _pngxy(self.data)
1128 1111 elif self.format == self._FMT_JPEG:
1129 1112 w, h = _jpegxy(self.data)
1130 1113 elif self.format == self._FMT_GIF:
1131 1114 w, h = _gifxy(self.data)
1132 1115 else:
1133 1116 # retina only supports png
1134 1117 return
1135 1118 self.width = w // 2
1136 1119 self.height = h // 2
1137 1120
1138 1121 def reload(self):
1139 1122 """Reload the raw data from file or URL."""
1140 1123 if self.embed:
1141 1124 super(Image,self).reload()
1142 1125 if self.retina:
1143 1126 self._retina_shape()
1144 1127
1145 1128 def _repr_html_(self):
1146 1129 if not self.embed:
1147 1130 width = height = klass = ''
1148 1131 if self.width:
1149 1132 width = ' width="%d"' % self.width
1150 1133 if self.height:
1151 1134 height = ' height="%d"' % self.height
1152 1135 if self.unconfined:
1153 1136 klass = ' class="unconfined"'
1154 1137 return u'<img src="{url}"{width}{height}{klass}/>'.format(
1155 1138 url=self.url,
1156 1139 width=width,
1157 1140 height=height,
1158 1141 klass=klass,
1159 1142 )
1160 1143
1161 def _data_and_metadata(self):
1144 def _repr_mimebundle_(self, include=None, exclude=None):
1145 """Return the image as a mimebundle
1146
1147 Any new mimetype support should be implemented here.
1148 """
1149 if self.embed:
1150 mimetype = self._mimetype
1151 data, metadata = self._data_and_metadata(always_both=True)
1152 if metadata:
1153 metadata = {mimetype: metadata}
1154 return {mimetype: data}, metadata
1155 else:
1156 return {'text/html': self._repr_html_()}
1157
1158 def _data_and_metadata(self, always_both=False):
1162 1159 """shortcut for returning metadata with shape information, if defined"""
1163 1160 md = {}
1164 1161 if self.metadata:
1165 1162 md.update(self.metadata)
1166 1163 if self.width:
1167 1164 md['width'] = self.width
1168 1165 if self.height:
1169 1166 md['height'] = self.height
1170 1167 if self.unconfined:
1171 1168 md['unconfined'] = self.unconfined
1172 if md:
1169 if md or always_both:
1173 1170 return self.data, md
1174 1171 else:
1175 1172 return self.data
1176 1173
1177 1174 def _repr_png_(self):
1178 1175 if self.embed and self.format == self._FMT_PNG:
1179 1176 return self._data_and_metadata()
1180 1177
1181 1178 def _repr_jpeg_(self):
1182 if self.embed and (self.format == self._FMT_JPEG or self.format == u'jpg'):
1183 return self._data_and_metadata()
1184
1185 def _repr_gif_(self):
1186 if self.embed and self.format == self._FMT_GIF:
1179 if self.embed and self.format == self._FMT_JPEG:
1187 1180 return self._data_and_metadata()
1188 1181
1189 1182 def _find_ext(self, s):
1190 1183 return s.split('.')[-1].lower()
1191 1184
1185
1192 1186 class Video(DisplayObject):
1193 1187
1194 1188 def __init__(self, data=None, url=None, filename=None, embed=False, mimetype=None):
1195 1189 """Create a video object given raw data or an URL.
1196 1190
1197 1191 When this object is returned by an input cell or passed to the
1198 1192 display function, it will result in the video being displayed
1199 1193 in the frontend.
1200 1194
1201 1195 Parameters
1202 1196 ----------
1203 1197 data : unicode, str or bytes
1204 1198 The raw video data or a URL or filename to load the data from.
1205 1199 Raw data will require passing `embed=True`.
1206 1200 url : unicode
1207 1201 A URL for the video. If you specify `url=`,
1208 1202 the image data will not be embedded.
1209 1203 filename : unicode
1210 1204 Path to a local file containing the video.
1211 1205 Will be interpreted as a local URL unless `embed=True`.
1212 1206 embed : bool
1213 1207 Should the video be embedded using a data URI (True) or be
1214 1208 loaded using a <video> tag (False).
1215 1209
1216 1210 Since videos are large, embedding them should be avoided, if possible.
1217 1211 You must confirm embedding as your intention by passing `embed=True`.
1218 1212
1219 1213 Local files can be displayed with URLs without embedding the content, via::
1220 1214
1221 1215 Video('./video.mp4')
1222 1216
1223 1217 mimetype: unicode
1224 1218 Specify the mimetype for embedded videos.
1225 1219 Default will be guessed from file extension, if available.
1226 1220
1227 1221 Examples
1228 1222 --------
1229 1223
1230 1224 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
1231 1225 Video('path/to/video.mp4')
1232 1226 Video('path/to/video.mp4', embed=True)
1233 1227 Video(b'raw-videodata', embed=True)
1234 1228 """
1235 1229 if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
1236 1230 url = data
1237 1231 data = None
1238 1232 elif os.path.exists(data):
1239 1233 filename = data
1240 1234 data = None
1241 1235
1242 1236 if data and not embed:
1243 1237 msg = ''.join([
1244 1238 "To embed videos, you must pass embed=True ",
1245 1239 "(this may make your notebook files huge)\n",
1246 1240 "Consider passing Video(url='...')",
1247 1241 ])
1248 1242 raise ValueError(msg)
1249 1243
1250 1244 self.mimetype = mimetype
1251 1245 self.embed = embed
1252 1246 super(Video, self).__init__(data=data, url=url, filename=filename)
1253 1247
1254 1248 def _repr_html_(self):
1255 1249 # External URLs and potentially local files are not embedded into the
1256 1250 # notebook output.
1257 1251 if not self.embed:
1258 1252 url = self.url if self.url is not None else self.filename
1259 1253 output = """<video src="{0}" controls>
1260 1254 Your browser does not support the <code>video</code> element.
1261 1255 </video>""".format(url)
1262 1256 return output
1263 1257
1264 1258 # Embedded videos are base64-encoded.
1265 1259 mimetype = self.mimetype
1266 1260 if self.filename is not None:
1267 1261 if not mimetype:
1268 1262 mimetype, _ = mimetypes.guess_type(self.filename)
1269 1263
1270 1264 with open(self.filename, 'rb') as f:
1271 1265 video = f.read()
1272 1266 else:
1273 1267 video = self.data
1274 1268 if isinstance(video, str):
1275 1269 # unicode input is already b64-encoded
1276 1270 b64_video = video
1277 1271 else:
1278 1272 b64_video = base64_encode(video).decode('ascii').rstrip()
1279 1273
1280 1274 output = """<video controls>
1281 1275 <source src="data:{0};base64,{1}" type="{0}">
1282 1276 Your browser does not support the video tag.
1283 1277 </video>""".format(mimetype, b64_video)
1284 1278 return output
1285 1279
1286 1280 def reload(self):
1287 1281 # TODO
1288 1282 pass
1289 1283
1290 def _repr_png_(self):
1291 # TODO
1292 pass
1293 def _repr_jpeg_(self):
1294 # TODO
1295 pass
1296 def _repr_gif_(self):
1297 # TODO
1298 pass
1299 1284
1300 1285 def clear_output(wait=False):
1301 1286 """Clear the output of the current cell receiving output.
1302 1287
1303 1288 Parameters
1304 1289 ----------
1305 1290 wait : bool [default: false]
1306 1291 Wait to clear the output until new output is available to replace it."""
1307 1292 from IPython.core.interactiveshell import InteractiveShell
1308 1293 if InteractiveShell.initialized():
1309 1294 InteractiveShell.instance().display_pub.clear_output(wait)
1310 1295 else:
1311 1296 print('\033[2K\r', end='')
1312 1297 sys.stdout.flush()
1313 1298 print('\033[2K\r', end='')
1314 1299 sys.stderr.flush()
1315 1300
1316 1301
1317 1302 @skip_doctest
1318 1303 def set_matplotlib_formats(*formats, **kwargs):
1319 1304 """Select figure formats for the inline backend. Optionally pass quality for JPEG.
1320 1305
1321 1306 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
1322 1307
1323 1308 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
1324 1309
1325 1310 To set this in your config files use the following::
1326 1311
1327 1312 c.InlineBackend.figure_formats = {'png', 'jpeg'}
1328 1313 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
1329 1314
1330 1315 Parameters
1331 1316 ----------
1332 1317 *formats : strs
1333 1318 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
1334 1319 **kwargs :
1335 1320 Keyword args will be relayed to ``figure.canvas.print_figure``.
1336 1321 """
1337 1322 from IPython.core.interactiveshell import InteractiveShell
1338 1323 from IPython.core.pylabtools import select_figure_formats
1339 1324 # build kwargs, starting with InlineBackend config
1340 1325 kw = {}
1341 1326 from ipykernel.pylab.config import InlineBackend
1342 1327 cfg = InlineBackend.instance()
1343 1328 kw.update(cfg.print_figure_kwargs)
1344 1329 kw.update(**kwargs)
1345 1330 shell = InteractiveShell.instance()
1346 1331 select_figure_formats(shell, formats, **kw)
1347 1332
1348 1333 @skip_doctest
1349 1334 def set_matplotlib_close(close=True):
1350 1335 """Set whether the inline backend closes all figures automatically or not.
1351 1336
1352 1337 By default, the inline backend used in the IPython Notebook will close all
1353 1338 matplotlib figures automatically after each cell is run. This means that
1354 1339 plots in different cells won't interfere. Sometimes, you may want to make
1355 1340 a plot in one cell and then refine it in later cells. This can be accomplished
1356 1341 by::
1357 1342
1358 1343 In [1]: set_matplotlib_close(False)
1359 1344
1360 1345 To set this in your config files use the following::
1361 1346
1362 1347 c.InlineBackend.close_figures = False
1363 1348
1364 1349 Parameters
1365 1350 ----------
1366 1351 close : bool
1367 1352 Should all matplotlib figures be automatically closed after each cell is
1368 1353 run?
1369 1354 """
1370 1355 from ipykernel.pylab.config import InlineBackend
1371 1356 cfg = InlineBackend.instance()
1372 1357 cfg.close_figures = close
@@ -1,1051 +1,1015 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Display formatters.
3 3
4 4 Inheritance diagram:
5 5
6 6 .. inheritance-diagram:: IPython.core.formatters
7 7 :parts: 3
8 8 """
9 9
10 10 # Copyright (c) IPython Development Team.
11 11 # Distributed under the terms of the Modified BSD License.
12 12
13 13 import abc
14 14 import json
15 15 import sys
16 16 import traceback
17 17 import warnings
18 18 from io import StringIO
19 19
20 20 from decorator import decorator
21 21
22 22 from traitlets.config.configurable import Configurable
23 23 from IPython.core.getipython import get_ipython
24 24 from IPython.utils.sentinel import Sentinel
25 25 from IPython.utils.dir2 import get_real_method
26 26 from IPython.lib import pretty
27 27 from traitlets import (
28 28 Bool, Dict, Integer, Unicode, CUnicode, ObjectName, List,
29 29 ForwardDeclaredInstance,
30 30 default, observe,
31 31 )
32 32
33 33
34 34 class DisplayFormatter(Configurable):
35 35
36 36 active_types = List(Unicode(),
37 37 help="""List of currently active mime-types to display.
38 38 You can use this to set a white-list for formats to display.
39 39
40 40 Most users will not need to change this value.
41 41 """).tag(config=True)
42 42
43 43 @default('active_types')
44 44 def _active_types_default(self):
45 45 return self.format_types
46 46
47 47 @observe('active_types')
48 48 def _active_types_changed(self, change):
49 49 for key, formatter in self.formatters.items():
50 50 if key in change['new']:
51 51 formatter.enabled = True
52 52 else:
53 53 formatter.enabled = False
54 54
55 55 ipython_display_formatter = ForwardDeclaredInstance('FormatterABC')
56 56 @default('ipython_display_formatter')
57 57 def _default_formatter(self):
58 58 return IPythonDisplayFormatter(parent=self)
59 59
60 60 mimebundle_formatter = ForwardDeclaredInstance('FormatterABC')
61 61 @default('mimebundle_formatter')
62 62 def _default_mime_formatter(self):
63 63 return MimeBundleFormatter(parent=self)
64 64
65 65 # A dict of formatter whose keys are format types (MIME types) and whose
66 66 # values are subclasses of BaseFormatter.
67 67 formatters = Dict()
68 68 @default('formatters')
69 69 def _formatters_default(self):
70 70 """Activate the default formatters."""
71 71 formatter_classes = [
72 72 PlainTextFormatter,
73 73 HTMLFormatter,
74 74 MarkdownFormatter,
75 75 SVGFormatter,
76 76 PNGFormatter,
77 GIFFormatter,
78 77 PDFFormatter,
79 78 JPEGFormatter,
80 79 LatexFormatter,
81 80 JSONFormatter,
82 81 JavascriptFormatter
83 82 ]
84 83 d = {}
85 84 for cls in formatter_classes:
86 85 f = cls(parent=self)
87 86 d[f.format_type] = f
88 87 return d
89 88
90 89 def format(self, obj, include=None, exclude=None):
91 90 """Return a format data dict for an object.
92 91
93 92 By default all format types will be computed.
94 93
95 94 The following MIME types are usually implemented:
96 95
97 96 * text/plain
98 97 * text/html
99 98 * text/markdown
100 99 * text/latex
101 100 * application/json
102 101 * application/javascript
103 102 * application/pdf
104 103 * image/png
105 104 * image/jpeg
106 105 * image/svg+xml
107 106
108 107 Parameters
109 108 ----------
110 109 obj : object
111 110 The Python object whose format data will be computed.
112 111 include : list, tuple or set; optional
113 112 A list of format type strings (MIME types) to include in the
114 113 format data dict. If this is set *only* the format types included
115 114 in this list will be computed.
116 115 exclude : list, tuple or set; optional
117 116 A list of format type string (MIME types) to exclude in the format
118 117 data dict. If this is set all format types will be computed,
119 118 except for those included in this argument.
120 119 Mimetypes present in exclude will take precedence over the ones in include
121 120
122 121 Returns
123 122 -------
124 123 (format_dict, metadata_dict) : tuple of two dicts
125 124
126 125 format_dict is a dictionary of key/value pairs, one of each format that was
127 126 generated for the object. The keys are the format types, which
128 127 will usually be MIME type strings and the values and JSON'able
129 128 data structure containing the raw data for the representation in
130 129 that format.
131 130
132 131 metadata_dict is a dictionary of metadata about each mime-type output.
133 132 Its keys will be a strict subset of the keys in format_dict.
134 133
135 134 Notes
136 135 -----
137 136
138 137 If an object implement `_repr_mimebundle_` as well as various
139 138 `_repr_*_`, the data returned by `_repr_mimebundle_` will take
140 139 precedence and the corresponding `_repr_*_` for this mimetype will
141 140 not be called.
142 141
143 142 """
144 143 format_dict = {}
145 144 md_dict = {}
146 145
147 146 if self.ipython_display_formatter(obj):
148 147 # object handled itself, don't proceed
149 148 return {}, {}
150 149
151 150 format_dict, md_dict = self.mimebundle_formatter(obj, include=include, exclude=exclude)
152 151
153 152 if format_dict or md_dict:
154 153 if include:
155 154 format_dict = {k:v for k,v in format_dict.items() if k in include}
156 155 md_dict = {k:v for k,v in md_dict.items() if k in include}
157 156 if exclude:
158 157 format_dict = {k:v for k,v in format_dict.items() if k not in exclude}
159 158 md_dict = {k:v for k,v in md_dict.items() if k not in exclude}
160 159
161 160 for format_type, formatter in self.formatters.items():
162 161 if format_type in format_dict:
163 162 # already got it from mimebundle, don't render again
164 163 continue
165 164 if include and format_type not in include:
166 165 continue
167 166 if exclude and format_type in exclude:
168 167 continue
169 168
170 169 md = None
171 170 try:
172 171 data = formatter(obj)
173 172 except:
174 173 # FIXME: log the exception
175 174 raise
176 175
177 176 # formatters can return raw data or (data, metadata)
178 177 if isinstance(data, tuple) and len(data) == 2:
179 178 data, md = data
180 179
181 180 if data is not None:
182 181 format_dict[format_type] = data
183 182 if md is not None:
184 183 md_dict[format_type] = md
185 184 return format_dict, md_dict
186 185
187 186 @property
188 187 def format_types(self):
189 188 """Return the format types (MIME types) of the active formatters."""
190 189 return list(self.formatters.keys())
191 190
192 191
193 192 #-----------------------------------------------------------------------------
194 193 # Formatters for specific format types (text, html, svg, etc.)
195 194 #-----------------------------------------------------------------------------
196 195
197 196
198 197 def _safe_repr(obj):
199 198 """Try to return a repr of an object
200 199
201 200 always returns a string, at least.
202 201 """
203 202 try:
204 203 return repr(obj)
205 204 except Exception as e:
206 205 return "un-repr-able object (%r)" % e
207 206
208 207
209 208 class FormatterWarning(UserWarning):
210 209 """Warning class for errors in formatters"""
211 210
212 211 @decorator
213 212 def catch_format_error(method, self, *args, **kwargs):
214 213 """show traceback on failed format call"""
215 214 try:
216 215 r = method(self, *args, **kwargs)
217 216 except NotImplementedError:
218 217 # don't warn on NotImplementedErrors
219 218 return None
220 219 except Exception:
221 220 exc_info = sys.exc_info()
222 221 ip = get_ipython()
223 222 if ip is not None:
224 223 ip.showtraceback(exc_info)
225 224 else:
226 225 traceback.print_exception(*exc_info)
227 226 return None
228 227 return self._check_return(r, args[0])
229 228
230 229
231 230 class FormatterABC(metaclass=abc.ABCMeta):
232 231 """ Abstract base class for Formatters.
233 232
234 233 A formatter is a callable class that is responsible for computing the
235 234 raw format data for a particular format type (MIME type). For example,
236 235 an HTML formatter would have a format type of `text/html` and would return
237 236 the HTML representation of the object when called.
238 237 """
239 238
240 239 # The format type of the data returned, usually a MIME type.
241 240 format_type = 'text/plain'
242 241
243 242 # Is the formatter enabled...
244 243 enabled = True
245 244
246 245 @abc.abstractmethod
247 246 def __call__(self, obj):
248 247 """Return a JSON'able representation of the object.
249 248
250 249 If the object cannot be formatted by this formatter,
251 250 warn and return None.
252 251 """
253 252 return repr(obj)
254 253
255 254
256 255 def _mod_name_key(typ):
257 256 """Return a (__module__, __name__) tuple for a type.
258 257
259 258 Used as key in Formatter.deferred_printers.
260 259 """
261 260 module = getattr(typ, '__module__', None)
262 261 name = getattr(typ, '__name__', None)
263 262 return (module, name)
264 263
265 264
266 265 def _get_type(obj):
267 266 """Return the type of an instance (old and new-style)"""
268 267 return getattr(obj, '__class__', None) or type(obj)
269 268
270 269
271 270 _raise_key_error = Sentinel('_raise_key_error', __name__,
272 271 """
273 272 Special value to raise a KeyError
274 273
275 274 Raise KeyError in `BaseFormatter.pop` if passed as the default value to `pop`
276 275 """)
277 276
278 277
279 278 class BaseFormatter(Configurable):
280 279 """A base formatter class that is configurable.
281 280
282 281 This formatter should usually be used as the base class of all formatters.
283 282 It is a traited :class:`Configurable` class and includes an extensible
284 283 API for users to determine how their objects are formatted. The following
285 284 logic is used to find a function to format an given object.
286 285
287 286 1. The object is introspected to see if it has a method with the name
288 287 :attr:`print_method`. If is does, that object is passed to that method
289 288 for formatting.
290 289 2. If no print method is found, three internal dictionaries are consulted
291 290 to find print method: :attr:`singleton_printers`, :attr:`type_printers`
292 291 and :attr:`deferred_printers`.
293 292
294 293 Users should use these dictionaries to register functions that will be
295 294 used to compute the format data for their objects (if those objects don't
296 295 have the special print methods). The easiest way of using these
297 296 dictionaries is through the :meth:`for_type` and :meth:`for_type_by_name`
298 297 methods.
299 298
300 299 If no function/callable is found to compute the format data, ``None`` is
301 300 returned and this format type is not used.
302 301 """
303 302
304 303 format_type = Unicode('text/plain')
305 304 _return_type = str
306 305
307 306 enabled = Bool(True).tag(config=True)
308 307
309 308 print_method = ObjectName('__repr__')
310 309
311 310 # The singleton printers.
312 311 # Maps the IDs of the builtin singleton objects to the format functions.
313 312 singleton_printers = Dict().tag(config=True)
314 313
315 314 # The type-specific printers.
316 315 # Map type objects to the format functions.
317 316 type_printers = Dict().tag(config=True)
318 317
319 318 # The deferred-import type-specific printers.
320 319 # Map (modulename, classname) pairs to the format functions.
321 320 deferred_printers = Dict().tag(config=True)
322 321
323 322 @catch_format_error
324 323 def __call__(self, obj):
325 324 """Compute the format for an object."""
326 325 if self.enabled:
327 326 # lookup registered printer
328 327 try:
329 328 printer = self.lookup(obj)
330 329 except KeyError:
331 330 pass
332 331 else:
333 332 return printer(obj)
334 333 # Finally look for special method names
335 334 method = get_real_method(obj, self.print_method)
336 335 if method is not None:
337 336 return method()
338 337 return None
339 338 else:
340 339 return None
341 340
342 341 def __contains__(self, typ):
343 342 """map in to lookup_by_type"""
344 343 try:
345 344 self.lookup_by_type(typ)
346 345 except KeyError:
347 346 return False
348 347 else:
349 348 return True
350 349
351 350 def _check_return(self, r, obj):
352 351 """Check that a return value is appropriate
353 352
354 353 Return the value if so, None otherwise, warning if invalid.
355 354 """
356 355 if r is None or isinstance(r, self._return_type) or \
357 356 (isinstance(r, tuple) and r and isinstance(r[0], self._return_type)):
358 357 return r
359 358 else:
360 359 warnings.warn(
361 360 "%s formatter returned invalid type %s (expected %s) for object: %s" % \
362 361 (self.format_type, type(r), self._return_type, _safe_repr(obj)),
363 362 FormatterWarning
364 363 )
365 364
366 365 def lookup(self, obj):
367 366 """Look up the formatter for a given instance.
368 367
369 368 Parameters
370 369 ----------
371 370 obj : object instance
372 371
373 372 Returns
374 373 -------
375 374 f : callable
376 375 The registered formatting callable for the type.
377 376
378 377 Raises
379 378 ------
380 379 KeyError if the type has not been registered.
381 380 """
382 381 # look for singleton first
383 382 obj_id = id(obj)
384 383 if obj_id in self.singleton_printers:
385 384 return self.singleton_printers[obj_id]
386 385 # then lookup by type
387 386 return self.lookup_by_type(_get_type(obj))
388 387
389 388 def lookup_by_type(self, typ):
390 389 """Look up the registered formatter for a type.
391 390
392 391 Parameters
393 392 ----------
394 393 typ : type or '__module__.__name__' string for a type
395 394
396 395 Returns
397 396 -------
398 397 f : callable
399 398 The registered formatting callable for the type.
400 399
401 400 Raises
402 401 ------
403 402 KeyError if the type has not been registered.
404 403 """
405 404 if isinstance(typ, str):
406 405 typ_key = tuple(typ.rsplit('.',1))
407 406 if typ_key not in self.deferred_printers:
408 407 # We may have it cached in the type map. We will have to
409 408 # iterate over all of the types to check.
410 409 for cls in self.type_printers:
411 410 if _mod_name_key(cls) == typ_key:
412 411 return self.type_printers[cls]
413 412 else:
414 413 return self.deferred_printers[typ_key]
415 414 else:
416 415 for cls in pretty._get_mro(typ):
417 416 if cls in self.type_printers or self._in_deferred_types(cls):
418 417 return self.type_printers[cls]
419 418
420 419 # If we have reached here, the lookup failed.
421 420 raise KeyError("No registered printer for {0!r}".format(typ))
422 421
423 422 def for_type(self, typ, func=None):
424 423 """Add a format function for a given type.
425 424
426 425 Parameters
427 426 -----------
428 427 typ : type or '__module__.__name__' string for a type
429 428 The class of the object that will be formatted using `func`.
430 429 func : callable
431 430 A callable for computing the format data.
432 431 `func` will be called with the object to be formatted,
433 432 and will return the raw data in this formatter's format.
434 433 Subclasses may use a different call signature for the
435 434 `func` argument.
436 435
437 436 If `func` is None or not specified, there will be no change,
438 437 only returning the current value.
439 438
440 439 Returns
441 440 -------
442 441 oldfunc : callable
443 442 The currently registered callable.
444 443 If you are registering a new formatter,
445 444 this will be the previous value (to enable restoring later).
446 445 """
447 446 # if string given, interpret as 'pkg.module.class_name'
448 447 if isinstance(typ, str):
449 448 type_module, type_name = typ.rsplit('.', 1)
450 449 return self.for_type_by_name(type_module, type_name, func)
451 450
452 451 try:
453 452 oldfunc = self.lookup_by_type(typ)
454 453 except KeyError:
455 454 oldfunc = None
456 455
457 456 if func is not None:
458 457 self.type_printers[typ] = func
459 458
460 459 return oldfunc
461 460
462 461 def for_type_by_name(self, type_module, type_name, func=None):
463 462 """Add a format function for a type specified by the full dotted
464 463 module and name of the type, rather than the type of the object.
465 464
466 465 Parameters
467 466 ----------
468 467 type_module : str
469 468 The full dotted name of the module the type is defined in, like
470 469 ``numpy``.
471 470 type_name : str
472 471 The name of the type (the class name), like ``dtype``
473 472 func : callable
474 473 A callable for computing the format data.
475 474 `func` will be called with the object to be formatted,
476 475 and will return the raw data in this formatter's format.
477 476 Subclasses may use a different call signature for the
478 477 `func` argument.
479 478
480 479 If `func` is None or unspecified, there will be no change,
481 480 only returning the current value.
482 481
483 482 Returns
484 483 -------
485 484 oldfunc : callable
486 485 The currently registered callable.
487 486 If you are registering a new formatter,
488 487 this will be the previous value (to enable restoring later).
489 488 """
490 489 key = (type_module, type_name)
491 490
492 491 try:
493 492 oldfunc = self.lookup_by_type("%s.%s" % key)
494 493 except KeyError:
495 494 oldfunc = None
496 495
497 496 if func is not None:
498 497 self.deferred_printers[key] = func
499 498 return oldfunc
500 499
501 500 def pop(self, typ, default=_raise_key_error):
502 501 """Pop a formatter for the given type.
503 502
504 503 Parameters
505 504 ----------
506 505 typ : type or '__module__.__name__' string for a type
507 506 default : object
508 507 value to be returned if no formatter is registered for typ.
509 508
510 509 Returns
511 510 -------
512 511 obj : object
513 512 The last registered object for the type.
514 513
515 514 Raises
516 515 ------
517 516 KeyError if the type is not registered and default is not specified.
518 517 """
519 518
520 519 if isinstance(typ, str):
521 520 typ_key = tuple(typ.rsplit('.',1))
522 521 if typ_key not in self.deferred_printers:
523 522 # We may have it cached in the type map. We will have to
524 523 # iterate over all of the types to check.
525 524 for cls in self.type_printers:
526 525 if _mod_name_key(cls) == typ_key:
527 526 old = self.type_printers.pop(cls)
528 527 break
529 528 else:
530 529 old = default
531 530 else:
532 531 old = self.deferred_printers.pop(typ_key)
533 532 else:
534 533 if typ in self.type_printers:
535 534 old = self.type_printers.pop(typ)
536 535 else:
537 536 old = self.deferred_printers.pop(_mod_name_key(typ), default)
538 537 if old is _raise_key_error:
539 538 raise KeyError("No registered value for {0!r}".format(typ))
540 539 return old
541 540
542 541 def _in_deferred_types(self, cls):
543 542 """
544 543 Check if the given class is specified in the deferred type registry.
545 544
546 545 Successful matches will be moved to the regular type registry for future use.
547 546 """
548 547 mod = getattr(cls, '__module__', None)
549 548 name = getattr(cls, '__name__', None)
550 549 key = (mod, name)
551 550 if key in self.deferred_printers:
552 551 # Move the printer over to the regular registry.
553 552 printer = self.deferred_printers.pop(key)
554 553 self.type_printers[cls] = printer
555 554 return True
556 555 return False
557 556
558 557
559 558 class PlainTextFormatter(BaseFormatter):
560 559 """The default pretty-printer.
561 560
562 561 This uses :mod:`IPython.lib.pretty` to compute the format data of
563 562 the object. If the object cannot be pretty printed, :func:`repr` is used.
564 563 See the documentation of :mod:`IPython.lib.pretty` for details on
565 564 how to write pretty printers. Here is a simple example::
566 565
567 566 def dtype_pprinter(obj, p, cycle):
568 567 if cycle:
569 568 return p.text('dtype(...)')
570 569 if hasattr(obj, 'fields'):
571 570 if obj.fields is None:
572 571 p.text(repr(obj))
573 572 else:
574 573 p.begin_group(7, 'dtype([')
575 574 for i, field in enumerate(obj.descr):
576 575 if i > 0:
577 576 p.text(',')
578 577 p.breakable()
579 578 p.pretty(field)
580 579 p.end_group(7, '])')
581 580 """
582 581
583 582 # The format type of data returned.
584 583 format_type = Unicode('text/plain')
585 584
586 585 # This subclass ignores this attribute as it always need to return
587 586 # something.
588 587 enabled = Bool(True).tag(config=False)
589 588
590 589 max_seq_length = Integer(pretty.MAX_SEQ_LENGTH,
591 590 help="""Truncate large collections (lists, dicts, tuples, sets) to this size.
592 591
593 592 Set to 0 to disable truncation.
594 593 """
595 594 ).tag(config=True)
596 595
597 596 # Look for a _repr_pretty_ methods to use for pretty printing.
598 597 print_method = ObjectName('_repr_pretty_')
599 598
600 599 # Whether to pretty-print or not.
601 600 pprint = Bool(True).tag(config=True)
602 601
603 602 # Whether to be verbose or not.
604 603 verbose = Bool(False).tag(config=True)
605 604
606 605 # The maximum width.
607 606 max_width = Integer(79).tag(config=True)
608 607
609 608 # The newline character.
610 609 newline = Unicode('\n').tag(config=True)
611 610
612 611 # format-string for pprinting floats
613 612 float_format = Unicode('%r')
614 613 # setter for float precision, either int or direct format-string
615 614 float_precision = CUnicode('').tag(config=True)
616 615
617 616 @observe('float_precision')
618 617 def _float_precision_changed(self, change):
619 618 """float_precision changed, set float_format accordingly.
620 619
621 620 float_precision can be set by int or str.
622 621 This will set float_format, after interpreting input.
623 622 If numpy has been imported, numpy print precision will also be set.
624 623
625 624 integer `n` sets format to '%.nf', otherwise, format set directly.
626 625
627 626 An empty string returns to defaults (repr for float, 8 for numpy).
628 627
629 628 This parameter can be set via the '%precision' magic.
630 629 """
631 630
632 631 new = change['new']
633 632 if '%' in new:
634 633 # got explicit format string
635 634 fmt = new
636 635 try:
637 636 fmt%3.14159
638 637 except Exception:
639 638 raise ValueError("Precision must be int or format string, not %r"%new)
640 639 elif new:
641 640 # otherwise, should be an int
642 641 try:
643 642 i = int(new)
644 643 assert i >= 0
645 644 except ValueError:
646 645 raise ValueError("Precision must be int or format string, not %r"%new)
647 646 except AssertionError:
648 647 raise ValueError("int precision must be non-negative, not %r"%i)
649 648
650 649 fmt = '%%.%if'%i
651 650 if 'numpy' in sys.modules:
652 651 # set numpy precision if it has been imported
653 652 import numpy
654 653 numpy.set_printoptions(precision=i)
655 654 else:
656 655 # default back to repr
657 656 fmt = '%r'
658 657 if 'numpy' in sys.modules:
659 658 import numpy
660 659 # numpy default is 8
661 660 numpy.set_printoptions(precision=8)
662 661 self.float_format = fmt
663 662
664 663 # Use the default pretty printers from IPython.lib.pretty.
665 664 @default('singleton_printers')
666 665 def _singleton_printers_default(self):
667 666 return pretty._singleton_pprinters.copy()
668 667
669 668 @default('type_printers')
670 669 def _type_printers_default(self):
671 670 d = pretty._type_pprinters.copy()
672 671 d[float] = lambda obj,p,cycle: p.text(self.float_format%obj)
673 672 return d
674 673
675 674 @default('deferred_printers')
676 675 def _deferred_printers_default(self):
677 676 return pretty._deferred_type_pprinters.copy()
678 677
679 678 #### FormatterABC interface ####
680 679
681 680 @catch_format_error
682 681 def __call__(self, obj):
683 682 """Compute the pretty representation of the object."""
684 683 if not self.pprint:
685 684 return repr(obj)
686 685 else:
687 686 stream = StringIO()
688 687 printer = pretty.RepresentationPrinter(stream, self.verbose,
689 688 self.max_width, self.newline,
690 689 max_seq_length=self.max_seq_length,
691 690 singleton_pprinters=self.singleton_printers,
692 691 type_pprinters=self.type_printers,
693 692 deferred_pprinters=self.deferred_printers)
694 693 printer.pretty(obj)
695 694 printer.flush()
696 695 return stream.getvalue()
697 696
698 697
699 698 class HTMLFormatter(BaseFormatter):
700 699 """An HTML formatter.
701 700
702 701 To define the callables that compute the HTML representation of your
703 702 objects, define a :meth:`_repr_html_` method or use the :meth:`for_type`
704 703 or :meth:`for_type_by_name` methods to register functions that handle
705 704 this.
706 705
707 706 The return value of this formatter should be a valid HTML snippet that
708 707 could be injected into an existing DOM. It should *not* include the
709 708 ```<html>`` or ```<body>`` tags.
710 709 """
711 710 format_type = Unicode('text/html')
712 711
713 712 print_method = ObjectName('_repr_html_')
714 713
715 714
716 715 class MarkdownFormatter(BaseFormatter):
717 716 """A Markdown formatter.
718 717
719 718 To define the callables that compute the Markdown representation of your
720 719 objects, define a :meth:`_repr_markdown_` method or use the :meth:`for_type`
721 720 or :meth:`for_type_by_name` methods to register functions that handle
722 721 this.
723 722
724 723 The return value of this formatter should be a valid Markdown.
725 724 """
726 725 format_type = Unicode('text/markdown')
727 726
728 727 print_method = ObjectName('_repr_markdown_')
729 728
730 729 class SVGFormatter(BaseFormatter):
731 730 """An SVG formatter.
732 731
733 732 To define the callables that compute the SVG representation of your
734 733 objects, define a :meth:`_repr_svg_` method or use the :meth:`for_type`
735 734 or :meth:`for_type_by_name` methods to register functions that handle
736 735 this.
737 736
738 737 The return value of this formatter should be valid SVG enclosed in
739 738 ```<svg>``` tags, that could be injected into an existing DOM. It should
740 739 *not* include the ```<html>`` or ```<body>`` tags.
741 740 """
742 741 format_type = Unicode('image/svg+xml')
743 742
744 743 print_method = ObjectName('_repr_svg_')
745 744
746 745
747 746 class PNGFormatter(BaseFormatter):
748 747 """A PNG formatter.
749 748
750 749 To define the callables that compute the PNG representation of your
751 750 objects, define a :meth:`_repr_png_` method or use the :meth:`for_type`
752 751 or :meth:`for_type_by_name` methods to register functions that handle
753 752 this.
754 753
755 754 The return value of this formatter should be raw PNG data, *not*
756 755 base64 encoded.
757 756 """
758 757 format_type = Unicode('image/png')
759 758
760 759 print_method = ObjectName('_repr_png_')
761 760
762 761 _return_type = (bytes, str)
763 762
764 763
765 764 class JPEGFormatter(BaseFormatter):
766 765 """A JPEG formatter.
767 766
768 767 To define the callables that compute the JPEG representation of your
769 768 objects, define a :meth:`_repr_jpeg_` method or use the :meth:`for_type`
770 769 or :meth:`for_type_by_name` methods to register functions that handle
771 770 this.
772 771
773 772 The return value of this formatter should be raw JPEG data, *not*
774 773 base64 encoded.
775 774 """
776 775 format_type = Unicode('image/jpeg')
777 776
778 777 print_method = ObjectName('_repr_jpeg_')
779 778
780 779 _return_type = (bytes, str)
781 780
782 781
783 class GIFFormatter(BaseFormatter):
784 """A PNG formatter.
785
786 To define the callables that compute the GIF representation of your
787 objects, define a :meth:`_repr_gif_` method or use the :meth:`for_type`
788 or :meth:`for_type_by_name` methods to register functions that handle
789 this.
790
791 The return value of this formatter should be raw GIF data, *not*
792 base64 encoded.
793 """
794 format_type = Unicode('image/gif')
795
796 print_method = ObjectName('_repr_gif_')
797
798 _return_type = (bytes, str)
799
800
801 782 class LatexFormatter(BaseFormatter):
802 783 """A LaTeX formatter.
803 784
804 785 To define the callables that compute the LaTeX representation of your
805 786 objects, define a :meth:`_repr_latex_` method or use the :meth:`for_type`
806 787 or :meth:`for_type_by_name` methods to register functions that handle
807 788 this.
808 789
809 790 The return value of this formatter should be a valid LaTeX equation,
810 791 enclosed in either ```$```, ```$$``` or another LaTeX equation
811 792 environment.
812 793 """
813 794 format_type = Unicode('text/latex')
814 795
815 796 print_method = ObjectName('_repr_latex_')
816 797
817 798
818 799 class JSONFormatter(BaseFormatter):
819 800 """A JSON string formatter.
820 801
821 802 To define the callables that compute the JSONable representation of
822 803 your objects, define a :meth:`_repr_json_` method or use the :meth:`for_type`
823 804 or :meth:`for_type_by_name` methods to register functions that handle
824 805 this.
825 806
826 807 The return value of this formatter should be a JSONable list or dict.
827 808 JSON scalars (None, number, string) are not allowed, only dict or list containers.
828 809 """
829 810 format_type = Unicode('application/json')
830 811 _return_type = (list, dict)
831 812
832 813 print_method = ObjectName('_repr_json_')
833 814
834 815 def _check_return(self, r, obj):
835 816 """Check that a return value is appropriate
836 817
837 818 Return the value if so, None otherwise, warning if invalid.
838 819 """
839 820 if r is None:
840 821 return
841 822 md = None
842 823 if isinstance(r, tuple):
843 824 # unpack data, metadata tuple for type checking on first element
844 825 r, md = r
845 826
846 827 # handle deprecated JSON-as-string form from IPython < 3
847 828 if isinstance(r, str):
848 829 warnings.warn("JSON expects JSONable list/dict containers, not JSON strings",
849 830 FormatterWarning)
850 831 r = json.loads(r)
851 832
852 833 if md is not None:
853 834 # put the tuple back together
854 835 r = (r, md)
855 836 return super(JSONFormatter, self)._check_return(r, obj)
856 837
857 838
858 839 class JavascriptFormatter(BaseFormatter):
859 840 """A Javascript formatter.
860 841
861 842 To define the callables that compute the Javascript representation of
862 843 your objects, define a :meth:`_repr_javascript_` method or use the
863 844 :meth:`for_type` or :meth:`for_type_by_name` methods to register functions
864 845 that handle this.
865 846
866 847 The return value of this formatter should be valid Javascript code and
867 848 should *not* be enclosed in ```<script>``` tags.
868 849 """
869 850 format_type = Unicode('application/javascript')
870 851
871 852 print_method = ObjectName('_repr_javascript_')
872 853
873 854
874 855 class PDFFormatter(BaseFormatter):
875 856 """A PDF formatter.
876 857
877 858 To define the callables that compute the PDF representation of your
878 859 objects, define a :meth:`_repr_pdf_` method or use the :meth:`for_type`
879 860 or :meth:`for_type_by_name` methods to register functions that handle
880 861 this.
881 862
882 863 The return value of this formatter should be raw PDF data, *not*
883 864 base64 encoded.
884 865 """
885 866 format_type = Unicode('application/pdf')
886 867
887 868 print_method = ObjectName('_repr_pdf_')
888 869
889 870 _return_type = (bytes, str)
890 871
891 872 class IPythonDisplayFormatter(BaseFormatter):
892 873 """An escape-hatch Formatter for objects that know how to display themselves.
893 874
894 875 To define the callables that compute the representation of your
895 876 objects, define a :meth:`_ipython_display_` method or use the :meth:`for_type`
896 877 or :meth:`for_type_by_name` methods to register functions that handle
897 878 this. Unlike mime-type displays, this method should not return anything,
898 879 instead calling any appropriate display methods itself.
899 880
900 881 This display formatter has highest priority.
901 882 If it fires, no other display formatter will be called.
902 883
903 884 Prior to IPython 6.1, `_ipython_display_` was the only way to display custom mime-types
904 885 without registering a new Formatter.
905 886
906 887 IPython 6.1 introduces `_repr_mimebundle_` for displaying custom mime-types,
907 888 so `_ipython_display_` should only be used for objects that require unusual
908 889 display patterns, such as multiple display calls.
909 890 """
910 891 print_method = ObjectName('_ipython_display_')
911 892 _return_type = (type(None), bool)
912 893
913 894 @catch_format_error
914 895 def __call__(self, obj):
915 896 """Compute the format for an object."""
916 897 if self.enabled:
917 898 # lookup registered printer
918 899 try:
919 900 printer = self.lookup(obj)
920 901 except KeyError:
921 902 pass
922 903 else:
923 904 printer(obj)
924 905 return True
925 906 # Finally look for special method names
926 907 method = get_real_method(obj, self.print_method)
927 908 if method is not None:
928 909 method()
929 910 return True
930 911
931 912
932 913 class MimeBundleFormatter(BaseFormatter):
933 914 """A Formatter for arbitrary mime-types.
934 915
935 916 Unlike other `_repr_<mimetype>_` methods,
936 917 `_repr_mimebundle_` should return mime-bundle data,
937 918 either the mime-keyed `data` dictionary or the tuple `(data, metadata)`.
938 919 Any mime-type is valid.
939 920
940 921 To define the callables that compute the mime-bundle representation of your
941 922 objects, define a :meth:`_repr_mimebundle_` method or use the :meth:`for_type`
942 923 or :meth:`for_type_by_name` methods to register functions that handle
943 924 this.
944 925
945 926 .. versionadded:: 6.1
946 927 """
947 928 print_method = ObjectName('_repr_mimebundle_')
948 929 _return_type = dict
949 930
950 931 def _check_return(self, r, obj):
951 932 r = super(MimeBundleFormatter, self)._check_return(r, obj)
952 933 # always return (data, metadata):
953 934 if r is None:
954 935 return {}, {}
955 936 if not isinstance(r, tuple):
956 937 return r, {}
957 938 return r
958 939
959 940 @catch_format_error
960 941 def __call__(self, obj, include=None, exclude=None):
961 942 """Compute the format for an object.
962 943
963 944 Identical to parent's method but we pass extra parameters to the method.
964 945
965 946 Unlike other _repr_*_ `_repr_mimebundle_` should allow extra kwargs, in
966 947 particular `include` and `exclude`.
967 948 """
968 949 if self.enabled:
969 950 # lookup registered printer
970 951 try:
971 952 printer = self.lookup(obj)
972 953 except KeyError:
973 954 pass
974 955 else:
975 956 return printer(obj)
976 957 # Finally look for special method names
977 958 method = get_real_method(obj, self.print_method)
978 959
979 960 if method is not None:
980 d = {}
981 d['include'] = include
982 d['exclude'] = exclude
983 return method(**d)
961 return method(include=include, exclude=exclude)
984 962 return None
985 963 else:
986 964 return None
987 965
988 966
989 967 FormatterABC.register(BaseFormatter)
990 968 FormatterABC.register(PlainTextFormatter)
991 969 FormatterABC.register(HTMLFormatter)
992 970 FormatterABC.register(MarkdownFormatter)
993 971 FormatterABC.register(SVGFormatter)
994 972 FormatterABC.register(PNGFormatter)
995 FormatterABC.register(GIFFormatter)
996 973 FormatterABC.register(PDFFormatter)
997 974 FormatterABC.register(JPEGFormatter)
998 975 FormatterABC.register(LatexFormatter)
999 976 FormatterABC.register(JSONFormatter)
1000 977 FormatterABC.register(JavascriptFormatter)
1001 978 FormatterABC.register(IPythonDisplayFormatter)
1002 979 FormatterABC.register(MimeBundleFormatter)
1003 980
1004 981
1005 982 def format_display_data(obj, include=None, exclude=None):
1006 983 """Return a format data dict for an object.
1007 984
1008 985 By default all format types will be computed.
1009 986
1010 The following MIME types are currently implemented:
1011
1012 * text/plain
1013 * text/html
1014 * text/markdown
1015 * text/latex
1016 * application/json
1017 * application/javascript
1018 * application/pdf
1019 * image/png
1020 * image/jpeg
1021 * image/svg+xml
1022
1023 987 Parameters
1024 988 ----------
1025 989 obj : object
1026 990 The Python object whose format data will be computed.
1027 991
1028 992 Returns
1029 993 -------
1030 994 format_dict : dict
1031 995 A dictionary of key/value pairs, one or each format that was
1032 996 generated for the object. The keys are the format types, which
1033 997 will usually be MIME type strings and the values and JSON'able
1034 998 data structure containing the raw data for the representation in
1035 999 that format.
1036 1000 include : list or tuple, optional
1037 1001 A list of format type strings (MIME types) to include in the
1038 1002 format data dict. If this is set *only* the format types included
1039 1003 in this list will be computed.
1040 1004 exclude : list or tuple, optional
1041 1005 A list of format type string (MIME types) to exclue in the format
1042 1006 data dict. If this is set all format types will be computed,
1043 1007 except for those included in this argument.
1044 1008 """
1045 1009 from IPython.core.interactiveshell import InteractiveShell
1046 1010
1047 1011 return InteractiveShell.instance().display_formatter.format(
1048 1012 obj,
1049 1013 include,
1050 1014 exclude
1051 1015 )
@@ -1,363 +1,373 b''
1 1 # Copyright (c) IPython Development Team.
2 2 # Distributed under the terms of the Modified BSD License.
3 3
4 4 import json
5 5 import os
6 6 import warnings
7 7
8 8 from unittest import mock
9 9
10 10 import nose.tools as nt
11 11
12 12 from IPython.core import display
13 13 from IPython.core.getipython import get_ipython
14 14 from IPython.utils.tempdir import NamedFileInTemporaryDirectory
15 15 from IPython import paths as ipath
16 16 from IPython.testing.tools import AssertPrints, AssertNotPrints
17 17
18 18 import IPython.testing.decorators as dec
19 19
20 20 def test_image_size():
21 21 """Simple test for display.Image(args, width=x,height=y)"""
22 22 thisurl = 'http://www.google.fr/images/srpr/logo3w.png'
23 23 img = display.Image(url=thisurl, width=200, height=200)
24 24 nt.assert_equal(u'<img src="%s" width="200" height="200"/>' % (thisurl), img._repr_html_())
25 25 img = display.Image(url=thisurl, metadata={'width':200, 'height':200})
26 26 nt.assert_equal(u'<img src="%s" width="200" height="200"/>' % (thisurl), img._repr_html_())
27 27 img = display.Image(url=thisurl, width=200)
28 28 nt.assert_equal(u'<img src="%s" width="200"/>' % (thisurl), img._repr_html_())
29 29 img = display.Image(url=thisurl)
30 30 nt.assert_equal(u'<img src="%s"/>' % (thisurl), img._repr_html_())
31 31 img = display.Image(url=thisurl, unconfined=True)
32 32 nt.assert_equal(u'<img src="%s" class="unconfined"/>' % (thisurl), img._repr_html_())
33 33
34 34
35 def test_image_mimes():
36 fmt = get_ipython().display_formatter.format
37 for format in display.Image._ACCEPTABLE_EMBEDDINGS:
38 mime = display.Image._MIMETYPES[format]
39 img = display.Image(b'garbage', format=format)
40 data, metadata = fmt(img)
41 nt.assert_equal(sorted(data), sorted([mime, 'text/plain']))
42
43
35 44 def test_geojson():
36 45
37 46 gj = display.GeoJSON(data={
38 47 "type": "Feature",
39 48 "geometry": {
40 49 "type": "Point",
41 50 "coordinates": [-81.327, 296.038]
42 51 },
43 52 "properties": {
44 53 "name": "Inca City"
45 54 }
46 55 },
47 56 url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
48 57 layer_options={
49 58 "basemap_id": "celestia_mars-shaded-16k_global",
50 59 "attribution": "Celestia/praesepe",
51 60 "minZoom": 0,
52 61 "maxZoom": 18,
53 62 })
54 63 nt.assert_equal(u'<IPython.core.display.GeoJSON object>', str(gj))
55 64
56 65 def test_retina_png():
57 66 here = os.path.dirname(__file__)
58 67 img = display.Image(os.path.join(here, "2x2.png"), retina=True)
59 68 nt.assert_equal(img.height, 1)
60 69 nt.assert_equal(img.width, 1)
61 70 data, md = img._repr_png_()
62 71 nt.assert_equal(md['width'], 1)
63 72 nt.assert_equal(md['height'], 1)
64 73
65 74 def test_retina_jpeg():
66 75 here = os.path.dirname(__file__)
67 76 img = display.Image(os.path.join(here, "2x2.jpg"), retina=True)
68 77 nt.assert_equal(img.height, 1)
69 78 nt.assert_equal(img.width, 1)
70 79 data, md = img._repr_jpeg_()
71 80 nt.assert_equal(md['width'], 1)
72 81 nt.assert_equal(md['height'], 1)
73 82
74 83 def test_base64image():
75 84 display.Image("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94BCRQnOqNu0b4AAAAKSURBVAjXY2AAAAACAAHiIbwzAAAAAElFTkSuQmCC")
76 85
77 86 def test_image_filename_defaults():
78 87 '''test format constraint, and validity of jpeg and png'''
79 88 tpath = ipath.get_ipython_package_dir()
80 89 nt.assert_raises(ValueError, display.Image, filename=os.path.join(tpath, 'testing/tests/badformat.zip'),
81 90 embed=True)
82 91 nt.assert_raises(ValueError, display.Image)
83 92 nt.assert_raises(ValueError, display.Image, data='this is not an image', format='badformat', embed=True)
84 93 # check boths paths to allow packages to test at build and install time
85 94 imgfile = os.path.join(tpath, 'core/tests/2x2.png')
86 95 img = display.Image(filename=imgfile)
87 96 nt.assert_equal('png', img.format)
88 97 nt.assert_is_not_none(img._repr_png_())
89 98 img = display.Image(filename=os.path.join(tpath, 'testing/tests/logo.jpg'), embed=False)
90 99 nt.assert_equal('jpeg', img.format)
91 100 nt.assert_is_none(img._repr_jpeg_())
92 101
93 102 def _get_inline_config():
94 103 from ipykernel.pylab.config import InlineBackend
95 104 return InlineBackend.instance()
96 105
97 106 @dec.skip_without('matplotlib')
98 107 def test_set_matplotlib_close():
99 108 cfg = _get_inline_config()
100 109 cfg.close_figures = False
101 110 display.set_matplotlib_close()
102 111 assert cfg.close_figures
103 112 display.set_matplotlib_close(False)
104 113 assert not cfg.close_figures
105 114
106 115 _fmt_mime_map = {
107 116 'png': 'image/png',
108 117 'jpeg': 'image/jpeg',
109 118 'pdf': 'application/pdf',
110 119 'retina': 'image/png',
111 120 'svg': 'image/svg+xml',
112 121 }
113 122
114 123 @dec.skip_without('matplotlib')
115 124 def test_set_matplotlib_formats():
116 125 from matplotlib.figure import Figure
117 126 formatters = get_ipython().display_formatter.formatters
118 127 for formats in [
119 128 ('png',),
120 129 ('pdf', 'svg'),
121 130 ('jpeg', 'retina', 'png'),
122 131 (),
123 132 ]:
124 133 active_mimes = {_fmt_mime_map[fmt] for fmt in formats}
125 134 display.set_matplotlib_formats(*formats)
126 135 for mime, f in formatters.items():
127 136 if mime in active_mimes:
128 137 nt.assert_in(Figure, f)
129 138 else:
130 139 nt.assert_not_in(Figure, f)
131 140
132 141 @dec.skip_without('matplotlib')
133 142 def test_set_matplotlib_formats_kwargs():
134 143 from matplotlib.figure import Figure
135 144 ip = get_ipython()
136 145 cfg = _get_inline_config()
137 146 cfg.print_figure_kwargs.update(dict(foo='bar'))
138 147 kwargs = dict(quality=10)
139 148 display.set_matplotlib_formats('png', **kwargs)
140 149 formatter = ip.display_formatter.formatters['image/png']
141 150 f = formatter.lookup_by_type(Figure)
142 151 cell = f.__closure__[0].cell_contents
143 152 expected = kwargs
144 153 expected.update(cfg.print_figure_kwargs)
145 154 nt.assert_equal(cell, expected)
146 155
147 156 def test_display_available():
148 157 """
149 158 Test that display is available without import
150 159
151 160 We don't really care if it's in builtin or anything else, but it should
152 161 always be available.
153 162 """
154 163 ip = get_ipython()
155 164 with AssertNotPrints('NameError'):
156 165 ip.run_cell('display')
157 166 try:
158 167 ip.run_cell('del display')
159 168 except NameError:
160 169 pass # it's ok, it might be in builtins
161 170 # even if deleted it should be back
162 171 with AssertNotPrints('NameError'):
163 172 ip.run_cell('display')
164 173
165 174 def test_textdisplayobj_pretty_repr():
166 175 p = display.Pretty("This is a simple test")
167 176 nt.assert_equal(repr(p), '<IPython.core.display.Pretty object>')
168 177 nt.assert_equal(p.data, 'This is a simple test')
169 178
170 179 p._show_mem_addr = True
171 180 nt.assert_equal(repr(p), object.__repr__(p))
172 181
173 182 def test_displayobject_repr():
174 183 h = display.HTML('<br />')
175 184 nt.assert_equal(repr(h), '<IPython.core.display.HTML object>')
176 185 h._show_mem_addr = True
177 186 nt.assert_equal(repr(h), object.__repr__(h))
178 187 h._show_mem_addr = False
179 188 nt.assert_equal(repr(h), '<IPython.core.display.HTML object>')
180 189
181 190 j = display.Javascript('')
182 191 nt.assert_equal(repr(j), '<IPython.core.display.Javascript object>')
183 192 j._show_mem_addr = True
184 193 nt.assert_equal(repr(j), object.__repr__(j))
185 194 j._show_mem_addr = False
186 195 nt.assert_equal(repr(j), '<IPython.core.display.Javascript object>')
187 196
188 197 def test_json():
189 198 d = {'a': 5}
190 199 lis = [d]
191 200 md = {'expanded': False}
192 201 md2 = {'expanded': True}
193 202 j = display.JSON(d)
194 203 j2 = display.JSON(d, expanded=True)
195 204 nt.assert_equal(j._repr_json_(), (d, md))
196 205 nt.assert_equal(j2._repr_json_(), (d, md2))
197 206
198 207 with warnings.catch_warnings(record=True) as w:
199 208 warnings.simplefilter("always")
200 209 j = display.JSON(json.dumps(d))
201 210 nt.assert_equal(len(w), 1)
202 211 nt.assert_equal(j._repr_json_(), (d, md))
203 212 nt.assert_equal(j2._repr_json_(), (d, md2))
204 213
205 214 j = display.JSON(lis)
206 215 j2 = display.JSON(lis, expanded=True)
207 216 nt.assert_equal(j._repr_json_(), (lis, md))
208 217 nt.assert_equal(j2._repr_json_(), (lis, md2))
209 218
210 219 with warnings.catch_warnings(record=True) as w:
211 220 warnings.simplefilter("always")
212 221 j = display.JSON(json.dumps(lis))
213 222 nt.assert_equal(len(w), 1)
214 223 nt.assert_equal(j._repr_json_(), (lis, md))
215 224 nt.assert_equal(j2._repr_json_(), (lis, md2))
216 225
217 226 def test_video_embedding():
218 227 """use a tempfile, with dummy-data, to ensure that video embedding doesn't crash"""
219 228 v = display.Video("http://ignored")
220 229 assert not v.embed
221 230 html = v._repr_html_()
222 231 nt.assert_not_in('src="data:', html)
223 232 nt.assert_in('src="http://ignored"', html)
224 233
225 234 with nt.assert_raises(ValueError):
226 235 v = display.Video(b'abc')
227 236
228 237 with NamedFileInTemporaryDirectory('test.mp4') as f:
229 238 f.write(b'abc')
230 239 f.close()
231 240
232 241 v = display.Video(f.name)
233 242 assert not v.embed
234 243 html = v._repr_html_()
235 244 nt.assert_not_in('src="data:', html)
236 245
237 246 v = display.Video(f.name, embed=True)
238 247 html = v._repr_html_()
239 248 nt.assert_in('src="data:video/mp4;base64,YWJj"',html)
240 249
241 250 v = display.Video(f.name, embed=True, mimetype='video/other')
242 251 html = v._repr_html_()
243 252 nt.assert_in('src="data:video/other;base64,YWJj"',html)
244 253
245 254 v = display.Video(b'abc', embed=True, mimetype='video/mp4')
246 255 html = v._repr_html_()
247 256 nt.assert_in('src="data:video/mp4;base64,YWJj"',html)
248 257
249 258 v = display.Video(u'YWJj', embed=True, mimetype='video/xyz')
250 259 html = v._repr_html_()
251 260 nt.assert_in('src="data:video/xyz;base64,YWJj"',html)
252 261
253 262
254 263 def test_display_id():
255 264 ip = get_ipython()
256 265 with mock.patch.object(ip.display_pub, 'publish') as pub:
257 266 handle = display.display('x')
258 267 nt.assert_is(handle, None)
259 268 handle = display.display('y', display_id='secret')
260 269 nt.assert_is_instance(handle, display.DisplayHandle)
261 270 handle2 = display.display('z', display_id=True)
262 271 nt.assert_is_instance(handle2, display.DisplayHandle)
263 272 nt.assert_not_equal(handle.display_id, handle2.display_id)
264 273
265 274 nt.assert_equal(pub.call_count, 3)
266 275 args, kwargs = pub.call_args_list[0]
267 276 nt.assert_equal(args, ())
268 277 nt.assert_equal(kwargs, {
269 278 'data': {
270 279 'text/plain': repr('x')
271 280 },
272 281 'metadata': {},
273 282 })
274 283 args, kwargs = pub.call_args_list[1]
275 284 nt.assert_equal(args, ())
276 285 nt.assert_equal(kwargs, {
277 286 'data': {
278 287 'text/plain': repr('y')
279 288 },
280 289 'metadata': {},
281 290 'transient': {
282 291 'display_id': handle.display_id,
283 292 },
284 293 })
285 294 args, kwargs = pub.call_args_list[2]
286 295 nt.assert_equal(args, ())
287 296 nt.assert_equal(kwargs, {
288 297 'data': {
289 298 'text/plain': repr('z')
290 299 },
291 300 'metadata': {},
292 301 'transient': {
293 302 'display_id': handle2.display_id,
294 303 },
295 304 })
296 305
297 306
298 307 def test_update_display():
299 308 ip = get_ipython()
300 309 with mock.patch.object(ip.display_pub, 'publish') as pub:
301 310 with nt.assert_raises(TypeError):
302 311 display.update_display('x')
303 312 display.update_display('x', display_id='1')
304 313 display.update_display('y', display_id='2')
305 314 args, kwargs = pub.call_args_list[0]
306 315 nt.assert_equal(args, ())
307 316 nt.assert_equal(kwargs, {
308 317 'data': {
309 318 'text/plain': repr('x')
310 319 },
311 320 'metadata': {},
312 321 'transient': {
313 322 'display_id': '1',
314 323 },
315 324 'update': True,
316 325 })
317 326 args, kwargs = pub.call_args_list[1]
318 327 nt.assert_equal(args, ())
319 328 nt.assert_equal(kwargs, {
320 329 'data': {
321 330 'text/plain': repr('y')
322 331 },
323 332 'metadata': {},
324 333 'transient': {
325 334 'display_id': '2',
326 335 },
327 336 'update': True,
328 337 })
329 338
330 339
331 340 def test_display_handle():
332 341 ip = get_ipython()
333 342 handle = display.DisplayHandle()
334 343 nt.assert_is_instance(handle.display_id, str)
335 344 handle = display.DisplayHandle('my-id')
336 345 nt.assert_equal(handle.display_id, 'my-id')
337 346 with mock.patch.object(ip.display_pub, 'publish') as pub:
338 347 handle.display('x')
339 348 handle.update('y')
340 349
341 350 args, kwargs = pub.call_args_list[0]
342 351 nt.assert_equal(args, ())
343 352 nt.assert_equal(kwargs, {
344 353 'data': {
345 354 'text/plain': repr('x')
346 355 },
347 356 'metadata': {},
348 357 'transient': {
349 358 'display_id': handle.display_id,
350 359 }
351 360 })
352 361 args, kwargs = pub.call_args_list[1]
353 362 nt.assert_equal(args, ())
354 363 nt.assert_equal(kwargs, {
355 364 'data': {
356 365 'text/plain': repr('y')
357 366 },
358 367 'metadata': {},
359 368 'transient': {
360 369 'display_id': handle.display_id,
361 370 },
362 371 'update': True,
363 372 })
373
@@ -1,167 +1,167 b''
1 1 # encoding: utf-8
2 2 """IO capturing utilities."""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7
8 8 import sys
9 9 from io import StringIO
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Classes and functions
13 13 #-----------------------------------------------------------------------------
14 14
15 15
16 16 class RichOutput(object):
17 17 def __init__(self, data=None, metadata=None):
18 18 self.data = data or {}
19 19 self.metadata = metadata or {}
20 20
21 21 def display(self):
22 22 from IPython.display import publish_display_data
23 23 publish_display_data(data=self.data, metadata=self.metadata)
24 24
25 25 def _repr_mime_(self, mime):
26 26 if mime not in self.data:
27 27 return
28 28 data = self.data[mime]
29 29 if mime in self.metadata:
30 30 return data, self.metadata[mime]
31 31 else:
32 32 return data
33
33
34 def _repr_mimebundle_(self, include=None, exclude=None):
35 return self.data, self.metadata
36
34 37 def _repr_html_(self):
35 38 return self._repr_mime_("text/html")
36 39
37 40 def _repr_latex_(self):
38 41 return self._repr_mime_("text/latex")
39 42
40 43 def _repr_json_(self):
41 44 return self._repr_mime_("application/json")
42 45
43 46 def _repr_javascript_(self):
44 47 return self._repr_mime_("application/javascript")
45 48
46 49 def _repr_png_(self):
47 50 return self._repr_mime_("image/png")
48 51
49 52 def _repr_jpeg_(self):
50 53 return self._repr_mime_("image/jpeg")
51
52 def _repr_gif_(self):
53 return self._repr_mime_("image/gif")
54 54
55 55 def _repr_svg_(self):
56 56 return self._repr_mime_("image/svg+xml")
57 57
58 58
59 59 class CapturedIO(object):
60 60 """Simple object for containing captured stdout/err and rich display StringIO objects
61 61
62 62 Each instance `c` has three attributes:
63 63
64 64 - ``c.stdout`` : standard output as a string
65 65 - ``c.stderr`` : standard error as a string
66 66 - ``c.outputs``: a list of rich display outputs
67 67
68 68 Additionally, there's a ``c.show()`` method which will print all of the
69 69 above in the same order, and can be invoked simply via ``c()``.
70 70 """
71 71
72 72 def __init__(self, stdout, stderr, outputs=None):
73 73 self._stdout = stdout
74 74 self._stderr = stderr
75 75 if outputs is None:
76 76 outputs = []
77 77 self._outputs = outputs
78 78
79 79 def __str__(self):
80 80 return self.stdout
81 81
82 82 @property
83 83 def stdout(self):
84 84 "Captured standard output"
85 85 if not self._stdout:
86 86 return ''
87 87 return self._stdout.getvalue()
88 88
89 89 @property
90 90 def stderr(self):
91 91 "Captured standard error"
92 92 if not self._stderr:
93 93 return ''
94 94 return self._stderr.getvalue()
95 95
96 96 @property
97 97 def outputs(self):
98 98 """A list of the captured rich display outputs, if any.
99 99
100 100 If you have a CapturedIO object ``c``, these can be displayed in IPython
101 101 using::
102 102
103 103 from IPython.display import display
104 104 for o in c.outputs:
105 105 display(o)
106 106 """
107 107 return [ RichOutput(d, md) for d, md in self._outputs ]
108 108
109 109 def show(self):
110 110 """write my output to sys.stdout/err as appropriate"""
111 111 sys.stdout.write(self.stdout)
112 112 sys.stderr.write(self.stderr)
113 113 sys.stdout.flush()
114 114 sys.stderr.flush()
115 115 for data, metadata in self._outputs:
116 116 RichOutput(data, metadata).display()
117 117
118 118 __call__ = show
119 119
120 120
121 121 class capture_output(object):
122 122 """context manager for capturing stdout/err"""
123 123 stdout = True
124 124 stderr = True
125 125 display = True
126 126
127 127 def __init__(self, stdout=True, stderr=True, display=True):
128 128 self.stdout = stdout
129 129 self.stderr = stderr
130 130 self.display = display
131 131 self.shell = None
132 132
133 133 def __enter__(self):
134 134 from IPython.core.getipython import get_ipython
135 135 from IPython.core.displaypub import CapturingDisplayPublisher
136 136 from IPython.core.displayhook import CapturingDisplayHook
137 137
138 138 self.sys_stdout = sys.stdout
139 139 self.sys_stderr = sys.stderr
140 140
141 141 if self.display:
142 142 self.shell = get_ipython()
143 143 if self.shell is None:
144 144 self.save_display_pub = None
145 145 self.display = False
146 146
147 147 stdout = stderr = outputs = None
148 148 if self.stdout:
149 149 stdout = sys.stdout = StringIO()
150 150 if self.stderr:
151 151 stderr = sys.stderr = StringIO()
152 152 if self.display:
153 153 self.save_display_pub = self.shell.display_pub
154 154 self.shell.display_pub = CapturingDisplayPublisher()
155 155 outputs = self.shell.display_pub.outputs
156 156 self.save_display_hook = sys.displayhook
157 157 sys.displayhook = CapturingDisplayHook(shell=self.shell,
158 158 outputs=outputs)
159 159
160 160 return CapturedIO(stdout, stderr, outputs)
161 161
162 162 def __exit__(self, exc_type, exc_value, traceback):
163 163 sys.stdout = self.sys_stdout
164 164 sys.stderr = self.sys_stderr
165 165 if self.display and self.shell:
166 166 self.shell.display_pub = self.save_display_pub
167 167 sys.displayhook = self.save_display_hook
General Comments 0
You need to be logged in to leave comments. Login now