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