Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/IPython/core/displaypub.py: 34%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

64 statements  

1"""An interface for publishing rich data to frontends. 

2 

3There 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 

10This module defines the logic display publishing. The display publisher uses 

11the ``display_data`` message type that is defined in the IPython messaging 

12spec. 

13""" 

14from __future__ import annotations 

15 

16# Copyright (c) IPython Development Team. 

17# Distributed under the terms of the Modified BSD License. 

18 

19import sys 

20 

21from traitlets.config.configurable import Configurable 

22from traitlets import List 

23 

24# This used to be defined here - it is imported for backwards compatibility 

25from .display_functions import publish_display_data 

26from .history import HistoryOutput 

27 

28# ----------------------------------------------------------------------------- 

29# Main payload class 

30# ----------------------------------------------------------------------------- 

31 

32_sentinel = object() 

33 

34 

35class DisplayPublisher(Configurable): 

36 """A traited class that publishes display data to frontends. 

37 

38 Instances of this class are created by the main IPython object and should 

39 be accessed there. 

40 """ 

41 

42 def __init__(self, shell=None, *args, **kwargs): 

43 self.shell = shell 

44 self._is_publishing = False 

45 self._in_post_execute = False 

46 if self.shell: 

47 self._setup_execution_tracking() 

48 super().__init__(*args, **kwargs) 

49 

50 def _validate_data(self, data, metadata=None): 

51 """Validate the display data. 

52 

53 Parameters 

54 ---------- 

55 data : dict 

56 The formata data dictionary. 

57 metadata : dict 

58 Any metadata for the data. 

59 """ 

60 

61 if not isinstance(data, dict): 

62 raise TypeError("data must be a dict, got: %r" % data) 

63 if metadata is not None: 

64 if not isinstance(metadata, dict): 

65 raise TypeError("metadata must be a dict, got: %r" % data) 

66 

67 def _setup_execution_tracking(self): 

68 """Set up hooks to track execution state""" 

69 self.shell.events.register("post_execute", self._on_post_execute) 

70 self.shell.events.register("pre_execute", self._on_pre_execute) 

71 

72 def _on_post_execute(self): 

73 """Called at start of post_execute phase""" 

74 self._in_post_execute = True 

75 

76 def _on_pre_execute(self): 

77 """Called at start of pre_execute phase""" 

78 self._in_post_execute = False 

79 

80 # use * to indicate transient, update are keyword-only 

81 def publish( 

82 self, 

83 data, 

84 metadata=None, 

85 source=_sentinel, 

86 *, 

87 transient=None, 

88 update=False, 

89 **kwargs, 

90 ) -> None: 

91 """Publish data and metadata to all frontends. 

92 

93 See the ``display_data`` message in the messaging documentation for 

94 more details about this message type. 

95 

96 The following MIME types are currently implemented: 

97 

98 * text/plain 

99 * text/html 

100 * text/markdown 

101 * text/latex 

102 * application/json 

103 * application/javascript 

104 * image/png 

105 * image/jpeg 

106 * image/svg+xml 

107 

108 Parameters 

109 ---------- 

110 data : dict 

111 A dictionary having keys that are valid MIME types (like 

112 'text/plain' or 'image/svg+xml') and values that are the data for 

113 that MIME type. The data itself must be a JSON'able data 

114 structure. Minimally all data should have the 'text/plain' data, 

115 which can be displayed by all frontends. If more than the plain 

116 text is given, it is up to the frontend to decide which 

117 representation to use. 

118 metadata : dict 

119 A dictionary for metadata related to the data. This can contain 

120 arbitrary key, value pairs that frontends can use to interpret 

121 the data. Metadata specific to each mime-type can be specified 

122 in the metadata dict with the same mime-type keys as 

123 the data itself. 

124 source : str, deprecated 

125 Unused. 

126 transient : dict, keyword-only 

127 A dictionary for transient data. 

128 Data in this dictionary should not be persisted as part of saving this output. 

129 Examples include 'display_id'. 

130 update : bool, keyword-only, default: False 

131 If True, only update existing outputs with the same display_id, 

132 rather than creating a new output. 

133 """ 

134 

135 if source is not _sentinel: 

136 import warnings 

137 

138 warnings.warn( 

139 "The 'source' parameter is deprecated since IPython 3.0 and will be ignored " 

140 "(this warning is present since 9.0). `source` parameter will be removed in the future.", 

141 DeprecationWarning, 

142 stacklevel=2, 

143 ) 

144 

145 handlers: dict = {} 

146 if self.shell is not None: 

147 handlers = getattr(self.shell, "mime_renderers", {}) 

148 

149 outputs = self.shell.history_manager.outputs 

150 

151 target_execution_count = self.shell.execution_count - 1 

152 if self._in_post_execute: 

153 # We're in post_execute, so this is likely a matplotlib flush 

154 # Use execution_count - 1 to associate with the cell that created the plot 

155 target_execution_count = self.shell.execution_count - 1 

156 

157 outputs[target_execution_count].append( 

158 HistoryOutput(output_type="display_data", bundle=data) 

159 ) 

160 

161 for mime, handler in handlers.items(): 

162 if mime in data: 

163 handler(data[mime], metadata.get(mime, None)) 

164 return 

165 

166 self._is_publishing = True 

167 if "text/plain" in data: 

168 print(data["text/plain"]) 

169 self._is_publishing = False 

170 

171 @property 

172 def is_publishing(self): 

173 return self._is_publishing 

174 

175 def clear_output(self, wait=False): 

176 """Clear the output of the cell receiving output.""" 

177 print("\033[2K\r", end="") 

178 sys.stdout.flush() 

179 print("\033[2K\r", end="") 

180 sys.stderr.flush() 

181 

182 

183class CapturingDisplayPublisher(DisplayPublisher): 

184 """A DisplayPublisher that stores""" 

185 

186 outputs: List = List() 

187 

188 def publish( 

189 self, data, metadata=None, source=None, *, transient=None, update=False 

190 ): 

191 self.outputs.append( 

192 { 

193 "data": data, 

194 "metadata": metadata, 

195 "transient": transient, 

196 "update": update, 

197 } 

198 ) 

199 

200 def clear_output(self, wait=False): 

201 super().clear_output(wait) 

202 

203 # empty the list, *do not* reassign a new list 

204 self.outputs.clear()