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