1"""Top-level display functions for displaying object in different formats."""
2
3# Copyright (c) IPython Development Team.
4# Distributed under the terms of the Modified BSD License.
5
6
7from binascii import b2a_hex
8import os
9import sys
10import warnings
11
12__all__ = ['display', 'clear_output', 'publish_display_data', 'update_display', 'DisplayHandle']
13
14#-----------------------------------------------------------------------------
15# utility functions
16#-----------------------------------------------------------------------------
17
18
19def _merge(d1, d2):
20 """Like update, but merges sub-dicts instead of clobbering at the top level.
21
22 Updates d1 in-place
23 """
24
25 if not isinstance(d2, dict) or not isinstance(d1, dict):
26 return d2
27 for key, value in d2.items():
28 d1[key] = _merge(d1.get(key), value)
29 return d1
30
31
32#-----------------------------------------------------------------------------
33# Main functions
34#-----------------------------------------------------------------------------
35
36# use * to indicate transient is keyword-only
37def publish_display_data(data, metadata=None, *, transient=None, **kwargs):
38 """Publish data and metadata to all frontends.
39
40 See the ``display_data`` message in the messaging documentation for
41 more details about this message type.
42
43 Keys of data and metadata can be any mime-type.
44
45 Parameters
46 ----------
47 data : dict
48 A dictionary having keys that are valid MIME types (like
49 'text/plain' or 'image/svg+xml') and values that are the data for
50 that MIME type. The data itself must be a JSON'able data
51 structure. Minimally all data should have the 'text/plain' data,
52 which can be displayed by all frontends. If more than the plain
53 text is given, it is up to the frontend to decide which
54 representation to use.
55 metadata : dict
56 A dictionary for metadata related to the data. This can contain
57 arbitrary key, value pairs that frontends can use to interpret
58 the data. mime-type keys matching those in data can be used
59 to specify metadata about particular representations.
60 transient : dict, keyword-only
61 A dictionary of transient data, such as display_id.
62 """
63 from IPython.core.interactiveshell import InteractiveShell
64
65 display_pub = InteractiveShell.instance().display_pub
66
67 # only pass transient if supplied,
68 # to avoid errors with older ipykernel.
69 # TODO: We could check for ipykernel version and provide a detailed upgrade message.
70 if transient:
71 kwargs['transient'] = transient
72
73 display_pub.publish(
74 data=data,
75 metadata=metadata,
76 **kwargs
77 )
78
79
80def _new_id():
81 """Generate a new random text id with urandom"""
82 return b2a_hex(os.urandom(16)).decode('ascii')
83
84
85def display(
86 *objs,
87 include=None,
88 exclude=None,
89 metadata=None,
90 transient=None,
91 display_id=None,
92 raw=False,
93 clear=False,
94 **kwargs,
95):
96 """Display a Python object in all frontends.
97
98 By default all representations will be computed and sent to the frontends.
99 Frontends can decide which representation is used and how.
100
101 In terminal IPython this will be similar to using :func:`print`, for use in richer
102 frontends see Jupyter notebook examples with rich display logic.
103
104 Parameters
105 ----------
106 *objs : object
107 The Python objects to display.
108 raw : bool, optional
109 Are the objects to be displayed already mimetype-keyed dicts of raw display data,
110 or Python objects that need to be formatted before display? [default: False]
111 include : list, tuple or set, optional
112 A list of format type strings (MIME types) to include in the
113 format data dict. If this is set *only* the format types included
114 in this list will be computed.
115 exclude : list, tuple or set, optional
116 A list of format type strings (MIME types) to exclude in the format
117 data dict. If this is set all format types will be computed,
118 except for those included in this argument.
119 metadata : dict, optional
120 A dictionary of metadata to associate with the output.
121 mime-type keys in this dictionary will be associated with the individual
122 representation formats, if they exist.
123 transient : dict, optional
124 A dictionary of transient data to associate with the output.
125 Data in this dict should not be persisted to files (e.g. notebooks).
126 display_id : str, bool optional
127 Set an id for the display.
128 This id can be used for updating this display area later via update_display.
129 If given as `True`, generate a new `display_id`
130 clear : bool, optional
131 Should the output area be cleared before displaying anything? If True,
132 this will wait for additional output before clearing. [default: False]
133 **kwargs : additional keyword-args, optional
134 Additional keyword-arguments are passed through to the display publisher.
135
136 Returns
137 -------
138 handle: DisplayHandle
139 Returns a handle on updatable displays for use with :func:`update_display`,
140 if `display_id` is given. Returns :any:`None` if no `display_id` is given
141 (default).
142
143 Examples
144 --------
145 >>> class Json(object):
146 ... def __init__(self, json):
147 ... self.json = json
148 ... def _repr_pretty_(self, pp, cycle):
149 ... import json
150 ... pp.text(json.dumps(self.json, indent=2))
151 ... def __repr__(self):
152 ... return str(self.json)
153 ...
154
155 >>> d = Json({1:2, 3: {4:5}})
156
157 >>> print(d)
158 {1: 2, 3: {4: 5}}
159
160 >>> display(d)
161 {
162 "1": 2,
163 "3": {
164 "4": 5
165 }
166 }
167
168 >>> def int_formatter(integer, pp, cycle):
169 ... pp.text('I'*integer)
170
171 >>> plain = get_ipython().display_formatter.formatters['text/plain']
172 >>> plain.for_type(int, int_formatter)
173 <function _repr_pprint at 0x...>
174 >>> display(7-5)
175 II
176
177 >>> del plain.type_printers[int]
178 >>> display(7-5)
179 2
180
181 See Also
182 --------
183 :func:`update_display`
184
185 Notes
186 -----
187 In Python, objects can declare their textual representation using the
188 `__repr__` method. IPython expands on this idea and allows objects to declare
189 other, rich representations including:
190
191 - HTML
192 - JSON
193 - PNG
194 - JPEG
195 - SVG
196 - LaTeX
197
198 A single object can declare some or all of these representations; all are
199 handled by IPython's display system.
200
201 The main idea of the first approach is that you have to implement special
202 display methods when you define your class, one for each representation you
203 want to use. Here is a list of the names of the special methods and the
204 values they must return:
205
206 - `_repr_html_`: return raw HTML as a string, or a tuple (see below).
207 - `_repr_json_`: return a JSONable dict, or a tuple (see below).
208 - `_repr_jpeg_`: return raw JPEG data, or a tuple (see below).
209 - `_repr_png_`: return raw PNG data, or a tuple (see below).
210 - `_repr_svg_`: return raw SVG data as a string, or a tuple (see below).
211 - `_repr_latex_`: return LaTeX commands in a string surrounded by "$",
212 or a tuple (see below).
213 - `_repr_mimebundle_`: return a full mimebundle containing the mapping
214 from all mimetypes to data.
215 Use this for any mime-type not listed above.
216
217 The above functions may also return the object's metadata alonside the
218 data. If the metadata is available, the functions will return a tuple
219 containing the data and metadata, in that order. If there is no metadata
220 available, then the functions will return the data only.
221
222 When you are directly writing your own classes, you can adapt them for
223 display in IPython by following the above approach. But in practice, you
224 often need to work with existing classes that you can't easily modify.
225
226 You can refer to the documentation on integrating with the display system in
227 order to register custom formatters for already existing types
228 (:ref:`integrating_rich_display`).
229
230 .. versionadded:: 5.4 display available without import
231 .. versionadded:: 6.1 display available without import
232
233 Since IPython 5.4 and 6.1 :func:`display` is automatically made available to
234 the user without import. If you are using display in a document that might
235 be used in a pure python context or with older version of IPython, use the
236 following import at the top of your file::
237
238 from IPython.display import display
239
240 """
241 from IPython.core.interactiveshell import InteractiveShell
242
243 if not InteractiveShell.initialized():
244 # Directly print objects.
245 print(*objs)
246 return
247
248 if transient is None:
249 transient = {}
250 if metadata is None:
251 metadata={}
252 if display_id:
253 if display_id is True:
254 display_id = _new_id()
255 transient['display_id'] = display_id
256 if kwargs.get('update') and 'display_id' not in transient:
257 raise TypeError('display_id required for update_display')
258 if transient:
259 kwargs['transient'] = transient
260
261 if not objs and display_id:
262 # if given no objects, but still a request for a display_id,
263 # we assume the user wants to insert an empty output that
264 # can be updated later
265 objs = [{}]
266 raw = True
267
268 if not raw:
269 format = InteractiveShell.instance().display_formatter.format
270
271 if clear:
272 clear_output(wait=True)
273
274 for obj in objs:
275 if raw:
276 publish_display_data(data=obj, metadata=metadata, **kwargs)
277 else:
278 format_dict, md_dict = format(obj, include=include, exclude=exclude)
279 if not format_dict:
280 # nothing to display (e.g. _ipython_display_ took over)
281 continue
282 if metadata:
283 # kwarg-specified metadata gets precedence
284 _merge(md_dict, metadata)
285 publish_display_data(data=format_dict, metadata=md_dict, **kwargs)
286 if display_id:
287 return DisplayHandle(display_id)
288
289
290# use * for keyword-only display_id arg
291def update_display(obj, *, display_id, **kwargs):
292 """Update an existing display by id
293
294 Parameters
295 ----------
296 obj
297 The object with which to update the display
298 display_id : keyword-only
299 The id of the display to update
300
301 See Also
302 --------
303 :func:`display`
304 """
305 kwargs['update'] = True
306 display(obj, display_id=display_id, **kwargs)
307
308
309class DisplayHandle:
310 """A handle on an updatable display
311
312 Call `.update(obj)` to display a new object.
313
314 Call `.display(obj`) to add a new instance of this display,
315 and update existing instances.
316
317 See Also
318 --------
319
320 :func:`display`, :func:`update_display`
321
322 """
323
324 def __init__(self, display_id=None):
325 if display_id is None:
326 display_id = _new_id()
327 self.display_id = display_id
328
329 def __repr__(self):
330 return "<%s display_id=%s>" % (self.__class__.__name__, self.display_id)
331
332 def display(self, obj, **kwargs):
333 """Make a new display with my id, updating existing instances.
334
335 Parameters
336 ----------
337 obj
338 object to display
339 **kwargs
340 additional keyword arguments passed to display
341 """
342 display(obj, display_id=self.display_id, **kwargs)
343
344 def update(self, obj, **kwargs):
345 """Update existing displays with my id
346
347 Parameters
348 ----------
349 obj
350 object to display
351 **kwargs
352 additional keyword arguments passed to update_display
353 """
354 update_display(obj, display_id=self.display_id, **kwargs)
355
356
357def clear_output(wait=False):
358 """Clear the output of the current cell receiving output.
359
360 Parameters
361 ----------
362 wait : bool [default: false]
363 Wait to clear the output until new output is available to replace it."""
364 from IPython.core.interactiveshell import InteractiveShell
365 if InteractiveShell.initialized():
366 InteractiveShell.instance().display_pub.clear_output(wait)
367 else:
368 print('\033[2K\r', end='')
369 sys.stdout.flush()
370 print('\033[2K\r', end='')
371 sys.stderr.flush()