1 """An interface for publishing rich data to frontends. 2 3 There are two components of the display system: 4 5 * Display formatters, which take a Python object and compute the 6 representation of the object in various formats (text, HTML, SVG, etc.). 7 * The display publisher that is used to send the representation data to the 8 various frontends. 9 10 This module defines the logic display publishing. The display publisher uses 11 the ``display_data`` message type that is defined in the IPython messaging 12 spec. 13 """ 14 15 # Copyright (c) IPython Development Team. 16 # Distributed under the terms of the Modified BSD License. 17 18 19 import sys 20 21 from traitlets.config.configurable import Configurable 22 from traitlets import List 23 24 # This used to be defined here - it is imported for backwards compatibility 25 from .display_functions import publish_display_data 26 27 import typing as t 28 29 # ----------------------------------------------------------------------------- 30 # Main payload class 31 #----------------------------------------------------------------------------- 32 33 34 class DisplayPublisher(Configurable): 35 """A traited class that publishes display data to frontends. 36 37 Instances of this class are created by the main IPython object and should 38 be accessed there. 39 """ 40 41 def __init__(self, shell=None, *args, **kwargs): 42 self.shell = shell 43 super().__init__(*args, **kwargs) 44 45 def _validate_data(self, data, metadata=None): 46 """Validate the display data. 47 48 Parameters 49 ---------- 50 data : dict 51 The formata data dictionary. 52 metadata : dict 53 Any metadata for the data. 54 """ 55 56 if not isinstance(data, dict): 57 raise TypeError('data must be a dict, got: %r' % data) 58 if metadata is not None: 59 if not isinstance(metadata, dict): 60 raise TypeError('metadata must be a dict, got: %r' % data) 61 62 # use * to indicate transient, update are keyword-only 63 def publish(self, data, metadata=None, source=None, *, transient=None, update=False, **kwargs) -> None: 64 """Publish data and metadata to all frontends. 65 66 See the ``display_data`` message in the messaging documentation for 67 more details about this message type. 68 69 The following MIME types are currently implemented: 70 71 * text/plain 72 * text/html 73 * text/markdown 74 * text/latex 75 * application/json 76 * application/javascript 77 * image/png 78 * image/jpeg 79 * image/svg+xml 80 81 Parameters 82 ---------- 83 data : dict 84 A dictionary having keys that are valid MIME types (like 85 'text/plain' or 'image/svg+xml') and values that are the data for 86 that MIME type. The data itself must be a JSON'able data 87 structure. Minimally all data should have the 'text/plain' data, 88 which can be displayed by all frontends. If more than the plain 89 text is given, it is up to the frontend to decide which 90 representation to use. 91 metadata : dict 92 A dictionary for metadata related to the data. This can contain 93 arbitrary key, value pairs that frontends can use to interpret 94 the data. Metadata specific to each mime-type can be specified 95 in the metadata dict with the same mime-type keys as 96 the data itself. 97 source : str, deprecated 98 Unused. 99 transient : dict, keyword-only 100 A dictionary for transient data. 101 Data in this dictionary should not be persisted as part of saving this output. 102 Examples include 'display_id'. 103 update : bool, keyword-only, default: False 104 If True, only update existing outputs with the same display_id, 105 rather than creating a new output. 106 """ 107 108 handlers: t.Dict = {} 109 if self.shell is not None: 110 handlers = getattr(self.shell, "mime_renderers", {}) 111 112 for mime, handler in handlers.items(): 113 if mime in data: 114 handler(data[mime], metadata.get(mime, None)) 115 return 116 117 if 'text/plain' in data: 118 print(data['text/plain']) 119 120 def clear_output(self, wait=False): 121 """Clear the output of the cell receiving output.""" 122 print('\033[2K\r', end='') 123 sys.stdout.flush() 124 print('\033[2K\r', end='') 125 sys.stderr.flush() 126 127 128 class CapturingDisplayPublisher(DisplayPublisher): 129 """A DisplayPublisher that stores""" 130 131 outputs: List = List() 132 133 def publish( 134 self, data, metadata=None, source=None, *, transient=None, update=False 135 ): 136 self.outputs.append( 137 { 138 "data": data, 139 "metadata": metadata, 140 "transient": transient, 141 "update": update, 142 } 143 ) 144 145 def clear_output(self, wait=False): 146 super(CapturingDisplayPublisher, self).clear_output(wait) 147 148 # empty the list, *do not* reassign a new list 149 self.outputs.clear() 150