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