##// END OF EJS Templates
do't define redundant _publish in core.display
MinRK -
Show More
@@ -1,614 +1,609 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
24 24 from IPython.utils.py3compat import string_types
25 25
26 from .displaypub import publish_display_data
27
26 28 #-----------------------------------------------------------------------------
27 29 # utility functions
28 30 #-----------------------------------------------------------------------------
29 31
30 32 def _safe_exists(path):
31 33 """Check path, but don't let exceptions raise"""
32 34 try:
33 35 return os.path.exists(path)
34 36 except Exception:
35 37 return False
36 38
37 def _publish(data, metadata):
38 """publish a display message"""
39 from IPython.core.interactiveshell import InteractiveShell
40 return InteractiveShell.instance().display_pub.publish(
41 "display", data, metadata
42 )
43
44 39 def _merge(d1, d2):
45 40 """Like update, but merges sub-dicts instead of clobbering at the top level.
46 41
47 42 Updates d1 in-place
48 43 """
49 44
50 45 if not isinstance(d2, dict) or not isinstance(d1, dict):
51 46 return d2
52 47 for key, value in d2.items():
53 48 d1[key] = _merge(d1.get(key), value)
54 49 return d1
55 50
51 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
52 """internal implementation of all display_foo methods
53
54 Parameters
55 ----------
56 mimetype : str
57 The mimetype to be published (e.g. 'image/png')
58 objs : tuple of objects
59 The Python objects to display, or if raw=True raw text data to
60 display.
61 raw : bool
62 Are the data objects raw data or Python objects that need to be
63 formatted before display? [default: False]
64 metadata : dict (optional)
65 Metadata to be associated with the output.
66 """
67 if raw:
68 for obj in objs:
69 publish_display_data('display', {mimetype : obj}, metadata)
70 else:
71 display(*objs, metadata=metadata, include=[mimetype])
72
56 73 #-----------------------------------------------------------------------------
57 74 # Main functions
58 75 #-----------------------------------------------------------------------------
59 76
60 77 def display(*objs, **kwargs):
61 78 """Display a Python object in all frontends.
62 79
63 80 By default all representations will be computed and sent to the frontends.
64 81 Frontends can decide which representation is used and how.
65 82
66 83 Parameters
67 84 ----------
68 85 objs : tuple of objects
69 86 The Python objects to display.
70 87 include : list or tuple, optional
71 88 A list of format type strings (MIME types) to include in the
72 89 format data dict. If this is set *only* the format types included
73 90 in this list will be computed.
74 91 exclude : list or tuple, optional
75 92 A list of format type strings (MIME types) to exclude in the format
76 93 data dict. If this is set all format types will be computed,
77 94 except for those included in this argument.
78 95 metadata : dict, optional
79 96 A dictionary of metadata to associate with the output.
80 97 mime-type keys in this dictionary will be associated with the individual
81 98 representation formats, if they exist.
82 99 """
83 100 include = kwargs.get('include')
84 101 exclude = kwargs.get('exclude')
85 102 metadata = kwargs.get('metadata')
86 103
87 104 from IPython.core.interactiveshell import InteractiveShell
88 105 format = InteractiveShell.instance().display_formatter.format
89 106
90 107 for obj in objs:
91 108 format_dict, md_dict = format(obj, include=include, exclude=exclude)
92 109 if metadata:
93 110 # kwarg-specified metadata gets precedence
94 111 _merge(md_dict, metadata)
95 _publish(format_dict, md_dict)
96
97 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
98 """internal implementation of all display_foo methods
112 publish_display_data('display', format_dict, md_dict)
99 113
100 Parameters
101 ----------
102 mimetype : str
103 The mimetype to be published (e.g. 'image/png')
104 objs : tuple of objects
105 The Python objects to display, or if raw=True raw text data to
106 display.
107 raw : bool
108 Are the data objects raw data or Python objects that need to be
109 formatted before display? [default: False]
110 metadata : dict (optional)
111 Metadata to be associated with the output.
112 """
113 if raw:
114 for obj in objs:
115 _publish({mimetype : obj}, metadata)
116 else:
117 display(*objs, metadata=metadata, include=[mimetype])
118
119 114
120 115 def display_pretty(*objs, **kwargs):
121 116 """Display the pretty (default) representation of an object.
122 117
123 118 Parameters
124 119 ----------
125 120 objs : tuple of objects
126 121 The Python objects to display, or if raw=True raw text data to
127 122 display.
128 123 raw : bool
129 124 Are the data objects raw data or Python objects that need to be
130 125 formatted before display? [default: False]
131 126 metadata : dict (optional)
132 127 Metadata to be associated with the output.
133 128 """
134 129 _display_mimetype('text/plain', objs, **kwargs)
135 130
136 131
137 132 def display_html(*objs, **kwargs):
138 133 """Display the HTML representation of an object.
139 134
140 135 Parameters
141 136 ----------
142 137 objs : tuple of objects
143 138 The Python objects to display, or if raw=True raw HTML data to
144 139 display.
145 140 raw : bool
146 141 Are the data objects raw data or Python objects that need to be
147 142 formatted before display? [default: False]
148 143 metadata : dict (optional)
149 144 Metadata to be associated with the output.
150 145 """
151 146 _display_mimetype('text/html', objs, **kwargs)
152 147
153 148
154 149 def display_svg(*objs, **kwargs):
155 150 """Display the SVG representation of an object.
156 151
157 152 Parameters
158 153 ----------
159 154 objs : tuple of objects
160 155 The Python objects to display, or if raw=True raw svg data to
161 156 display.
162 157 raw : bool
163 158 Are the data objects raw data or Python objects that need to be
164 159 formatted before display? [default: False]
165 160 metadata : dict (optional)
166 161 Metadata to be associated with the output.
167 162 """
168 163 _display_mimetype('image/svg+xml', objs, **kwargs)
169 164
170 165
171 166 def display_png(*objs, **kwargs):
172 167 """Display the PNG representation of an object.
173 168
174 169 Parameters
175 170 ----------
176 171 objs : tuple of objects
177 172 The Python objects to display, or if raw=True raw png data to
178 173 display.
179 174 raw : bool
180 175 Are the data objects raw data or Python objects that need to be
181 176 formatted before display? [default: False]
182 177 metadata : dict (optional)
183 178 Metadata to be associated with the output.
184 179 """
185 180 _display_mimetype('image/png', objs, **kwargs)
186 181
187 182
188 183 def display_jpeg(*objs, **kwargs):
189 184 """Display the JPEG representation of an object.
190 185
191 186 Parameters
192 187 ----------
193 188 objs : tuple of objects
194 189 The Python objects to display, or if raw=True raw JPEG data to
195 190 display.
196 191 raw : bool
197 192 Are the data objects raw data or Python objects that need to be
198 193 formatted before display? [default: False]
199 194 metadata : dict (optional)
200 195 Metadata to be associated with the output.
201 196 """
202 197 _display_mimetype('image/jpeg', objs, **kwargs)
203 198
204 199
205 200 def display_latex(*objs, **kwargs):
206 201 """Display the LaTeX representation of an object.
207 202
208 203 Parameters
209 204 ----------
210 205 objs : tuple of objects
211 206 The Python objects to display, or if raw=True raw latex data to
212 207 display.
213 208 raw : bool
214 209 Are the data objects raw data or Python objects that need to be
215 210 formatted before display? [default: False]
216 211 metadata : dict (optional)
217 212 Metadata to be associated with the output.
218 213 """
219 214 _display_mimetype('text/latex', objs, **kwargs)
220 215
221 216
222 217 def display_json(*objs, **kwargs):
223 218 """Display the JSON representation of an object.
224 219
225 220 Note that not many frontends support displaying JSON.
226 221
227 222 Parameters
228 223 ----------
229 224 objs : tuple of objects
230 225 The Python objects to display, or if raw=True raw json data to
231 226 display.
232 227 raw : bool
233 228 Are the data objects raw data or Python objects that need to be
234 229 formatted before display? [default: False]
235 230 metadata : dict (optional)
236 231 Metadata to be associated with the output.
237 232 """
238 233 _display_mimetype('application/json', objs, **kwargs)
239 234
240 235
241 236 def display_javascript(*objs, **kwargs):
242 237 """Display the Javascript representation of an object.
243 238
244 239 Parameters
245 240 ----------
246 241 objs : tuple of objects
247 242 The Python objects to display, or if raw=True raw javascript data to
248 243 display.
249 244 raw : bool
250 245 Are the data objects raw data or Python objects that need to be
251 246 formatted before display? [default: False]
252 247 metadata : dict (optional)
253 248 Metadata to be associated with the output.
254 249 """
255 250 _display_mimetype('application/javascript', objs, **kwargs)
256 251
257 252 #-----------------------------------------------------------------------------
258 253 # Smart classes
259 254 #-----------------------------------------------------------------------------
260 255
261 256
262 257 class DisplayObject(object):
263 258 """An object that wraps data to be displayed."""
264 259
265 260 _read_flags = 'r'
266 261
267 262 def __init__(self, data=None, url=None, filename=None):
268 263 """Create a display object given raw data.
269 264
270 265 When this object is returned by an expression or passed to the
271 266 display function, it will result in the data being displayed
272 267 in the frontend. The MIME type of the data should match the
273 268 subclasses used, so the Png subclass should be used for 'image/png'
274 269 data. If the data is a URL, the data will first be downloaded
275 270 and then displayed. If
276 271
277 272 Parameters
278 273 ----------
279 274 data : unicode, str or bytes
280 275 The raw data or a URL or file to load the data from
281 276 url : unicode
282 277 A URL to download the data from.
283 278 filename : unicode
284 279 Path to a local file to load the data from.
285 280 """
286 281 if data is not None and isinstance(data, string_types):
287 282 if data.startswith('http') and url is None:
288 283 url = data
289 284 filename = None
290 285 data = None
291 286 elif _safe_exists(data) and filename is None:
292 287 url = None
293 288 filename = data
294 289 data = None
295 290
296 291 self.data = data
297 292 self.url = url
298 293 self.filename = None if filename is None else unicode(filename)
299 294
300 295 self.reload()
301 296
302 297 def reload(self):
303 298 """Reload the raw data from file or URL."""
304 299 if self.filename is not None:
305 300 with open(self.filename, self._read_flags) as f:
306 301 self.data = f.read()
307 302 elif self.url is not None:
308 303 try:
309 304 import urllib2
310 305 response = urllib2.urlopen(self.url)
311 306 self.data = response.read()
312 307 # extract encoding from header, if there is one:
313 308 encoding = None
314 309 for sub in response.headers['content-type'].split(';'):
315 310 sub = sub.strip()
316 311 if sub.startswith('charset'):
317 312 encoding = sub.split('=')[-1].strip()
318 313 break
319 314 # decode data, if an encoding was specified
320 315 if encoding:
321 316 self.data = self.data.decode(encoding, 'replace')
322 317 except:
323 318 self.data = None
324 319
325 320 class Pretty(DisplayObject):
326 321
327 322 def _repr_pretty_(self):
328 323 return self.data
329 324
330 325
331 326 class HTML(DisplayObject):
332 327
333 328 def _repr_html_(self):
334 329 return self.data
335 330
336 331
337 332 class Math(DisplayObject):
338 333
339 334 def _repr_latex_(self):
340 335 s = self.data.strip('$')
341 336 return "$$%s$$" % s
342 337
343 338
344 339 class Latex(DisplayObject):
345 340
346 341 def _repr_latex_(self):
347 342 return self.data
348 343
349 344
350 345 class SVG(DisplayObject):
351 346
352 347 # wrap data in a property, which extracts the <svg> tag, discarding
353 348 # document headers
354 349 _data = None
355 350
356 351 @property
357 352 def data(self):
358 353 return self._data
359 354
360 355 @data.setter
361 356 def data(self, svg):
362 357 if svg is None:
363 358 self._data = None
364 359 return
365 360 # parse into dom object
366 361 from xml.dom import minidom
367 362 x = minidom.parseString(svg)
368 363 # get svg tag (should be 1)
369 364 found_svg = x.getElementsByTagName('svg')
370 365 if found_svg:
371 366 svg = found_svg[0].toxml()
372 367 else:
373 368 # fallback on the input, trust the user
374 369 # but this is probably an error.
375 370 pass
376 371 self._data = svg
377 372
378 373 def _repr_svg_(self):
379 374 return self.data
380 375
381 376
382 377 class JSON(DisplayObject):
383 378
384 379 def _repr_json_(self):
385 380 return self.data
386 381
387 382 css_t = """$("head").append($("<link/>").attr({
388 383 rel: "stylesheet",
389 384 type: "text/css",
390 385 href: "%s"
391 386 }));
392 387 """
393 388
394 389 lib_t1 = """$.getScript("%s", function () {
395 390 """
396 391 lib_t2 = """});
397 392 """
398 393
399 394 class Javascript(DisplayObject):
400 395
401 396 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
402 397 """Create a Javascript display object given raw data.
403 398
404 399 When this object is returned by an expression or passed to the
405 400 display function, it will result in the data being displayed
406 401 in the frontend. If the data is a URL, the data will first be
407 402 downloaded and then displayed.
408 403
409 404 In the Notebook, the containing element will be available as `element`,
410 405 and jQuery will be available. The output area starts hidden, so if
411 406 the js appends content to `element` that should be visible, then
412 407 it must call `container.show()` to unhide the area.
413 408
414 409 Parameters
415 410 ----------
416 411 data : unicode, str or bytes
417 412 The Javascript source code or a URL to download it from.
418 413 url : unicode
419 414 A URL to download the data from.
420 415 filename : unicode
421 416 Path to a local file to load the data from.
422 417 lib : list or str
423 418 A sequence of Javascript library URLs to load asynchronously before
424 419 running the source code. The full URLs of the libraries should
425 420 be given. A single Javascript library URL can also be given as a
426 421 string.
427 422 css: : list or str
428 423 A sequence of css files to load before running the source code.
429 424 The full URLs of the css files should be given. A single css URL
430 425 can also be given as a string.
431 426 """
432 427 if isinstance(lib, basestring):
433 428 lib = [lib]
434 429 elif lib is None:
435 430 lib = []
436 431 if isinstance(css, basestring):
437 432 css = [css]
438 433 elif css is None:
439 434 css = []
440 435 if not isinstance(lib, (list,tuple)):
441 436 raise TypeError('expected sequence, got: %r' % lib)
442 437 if not isinstance(css, (list,tuple)):
443 438 raise TypeError('expected sequence, got: %r' % css)
444 439 self.lib = lib
445 440 self.css = css
446 441 super(Javascript, self).__init__(data=data, url=url, filename=filename)
447 442
448 443 def _repr_javascript_(self):
449 444 r = ''
450 445 for c in self.css:
451 446 r += css_t % c
452 447 for l in self.lib:
453 448 r += lib_t1 % l
454 449 r += self.data
455 450 r += lib_t2*len(self.lib)
456 451 return r
457 452
458 453 # constants for identifying png/jpeg data
459 454 _PNG = b'\x89PNG\r\n\x1a\n'
460 455 _JPEG = b'\xff\xd8'
461 456
462 457 class Image(DisplayObject):
463 458
464 459 _read_flags = 'rb'
465 460 _FMT_JPEG = u'jpeg'
466 461 _FMT_PNG = u'png'
467 462 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
468 463
469 464 def __init__(self, data=None, url=None, filename=None, format=u'png', embed=None, width=None, height=None):
470 465 """Create a display an PNG/JPEG image given raw data.
471 466
472 467 When this object is returned by an expression or passed to the
473 468 display function, it will result in the image being displayed
474 469 in the frontend.
475 470
476 471 Parameters
477 472 ----------
478 473 data : unicode, str or bytes
479 474 The raw data or a URL to download the data from.
480 475 url : unicode
481 476 A URL to download the data from.
482 477 filename : unicode
483 478 Path to a local file to load the data from.
484 479 format : unicode
485 480 The format of the image data (png/jpeg/jpg). If a filename or URL is given
486 481 for format will be inferred from the filename extension.
487 482 embed : bool
488 483 Should the image data be embedded using a data URI (True) or be
489 484 loaded using an <img> tag. Set this to True if you want the image
490 485 to be viewable later with no internet connection in the notebook.
491 486
492 487 Default is `True`, unless the keyword argument `url` is set, then
493 488 default value is `False`.
494 489
495 490 Note that QtConsole is not able to display images if `embed` is set to `False`
496 491 width : int
497 492 Width to which to constrain the image in html
498 493 height : int
499 494 Height to which to constrain the image in html
500 495
501 496 Examples
502 497 --------
503 498 # embed implicitly True, works in qtconsole and notebook
504 499 Image('http://www.google.fr/images/srpr/logo3w.png')
505 500
506 501 # embed implicitly False, does not works in qtconsole but works in notebook if
507 502 # internet connection available
508 503 Image(url='http://www.google.fr/images/srpr/logo3w.png')
509 504
510 505 """
511 506 if filename is not None:
512 507 ext = self._find_ext(filename)
513 508 elif url is not None:
514 509 ext = self._find_ext(url)
515 510 elif data is None:
516 511 raise ValueError("No image data found. Expecting filename, url, or data.")
517 512 elif isinstance(data, string_types) and (
518 513 data.startswith('http') or _safe_exists(data)
519 514 ):
520 515 ext = self._find_ext(data)
521 516 else:
522 517 ext = None
523 518
524 519 if ext is not None:
525 520 format = ext.lower()
526 521 if ext == u'jpg' or ext == u'jpeg':
527 522 format = self._FMT_JPEG
528 523 if ext == u'png':
529 524 format = self._FMT_PNG
530 525 elif isinstance(data, bytes) and format == 'png':
531 526 # infer image type from image data header,
532 527 # only if format might not have been specified.
533 528 if data[:2] == _JPEG:
534 529 format = 'jpeg'
535 530
536 531 self.format = unicode(format).lower()
537 532 self.embed = embed if embed is not None else (url is None)
538 533
539 534 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
540 535 raise ValueError("Cannot embed the '%s' image format" % (self.format))
541 536 self.width = width
542 537 self.height = height
543 538 super(Image, self).__init__(data=data, url=url, filename=filename)
544 539
545 540 def reload(self):
546 541 """Reload the raw data from file or URL."""
547 542 if self.embed:
548 543 super(Image,self).reload()
549 544
550 545 def _repr_html_(self):
551 546 if not self.embed:
552 547 width = height = ''
553 548 if self.width:
554 549 width = ' width="%d"' % self.width
555 550 if self.height:
556 551 height = ' height="%d"' % self.height
557 552 return u'<img src="%s"%s%s/>' % (self.url, width, height)
558 553
559 554 def _data_and_metadata(self):
560 555 """shortcut for returning metadata with shape information, if defined"""
561 556 md = {}
562 557 if self.width:
563 558 md['width'] = self.width
564 559 if self.height:
565 560 md['height'] = self.height
566 561 if md:
567 562 return self.data, md
568 563 else:
569 564 return self.data
570 565
571 566 def _repr_png_(self):
572 567 if self.embed and self.format == u'png':
573 568 return self._data_and_metadata()
574 569
575 570 def _repr_jpeg_(self):
576 571 if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
577 572 return self._data_and_metadata()
578 573
579 574 def _find_ext(self, s):
580 575 return unicode(s.split('.')[-1].lower())
581 576
582 577
583 578 def clear_output(stdout=True, stderr=True, other=True):
584 579 """Clear the output of the current cell receiving output.
585 580
586 581 Optionally, each of stdout/stderr or other non-stream data (e.g. anything
587 582 produced by display()) can be excluded from the clear event.
588 583
589 584 By default, everything is cleared.
590 585
591 586 Parameters
592 587 ----------
593 588 stdout : bool [default: True]
594 589 Whether to clear stdout.
595 590 stderr : bool [default: True]
596 591 Whether to clear stderr.
597 592 other : bool [default: True]
598 593 Whether to clear everything else that is not stdout/stderr
599 594 (e.g. figures,images,HTML, any result of display()).
600 595 """
601 596 from IPython.core.interactiveshell import InteractiveShell
602 597 if InteractiveShell.initialized():
603 598 InteractiveShell.instance().display_pub.clear_output(
604 599 stdout=stdout, stderr=stderr, other=other,
605 600 )
606 601 else:
607 602 from IPython.utils import io
608 603 if stdout:
609 604 print('\033[2K\r', file=io.stdout, end='')
610 605 io.stdout.flush()
611 606 if stderr:
612 607 print('\033[2K\r', file=io.stderr, end='')
613 608 io.stderr.flush()
614 609
General Comments 0
You need to be logged in to leave comments. Login now