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""" 

14 

15# Copyright (c) IPython Development Team. 

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

17 

18import sys 

19 

20from traitlets.config.configurable import Configurable 

21from traitlets import List 

22 

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

24from .display_functions import publish_display_data 

25from .history import HistoryOutput 

26 

27import typing as t 

28 

29# ----------------------------------------------------------------------------- 

30# Main payload class 

31# ----------------------------------------------------------------------------- 

32 

33_sentinel = object() 

34 

35 

36class DisplayPublisher(Configurable): 

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

38 

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

40 be accessed there. 

41 """ 

42 

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

44 self.shell = shell 

45 self._is_publishing = False 

46 self._in_post_execute = False 

47 if self.shell: 

48 self._setup_execution_tracking() 

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

50 

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

52 """Validate the display data. 

53 

54 Parameters 

55 ---------- 

56 data : dict 

57 The formata data dictionary. 

58 metadata : dict 

59 Any metadata for the data. 

60 """ 

61 

62 if not isinstance(data, dict): 

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

64 if metadata is not None: 

65 if not isinstance(metadata, dict): 

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

67 

68 def _setup_execution_tracking(self): 

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

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

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

72 

73 def _on_post_execute(self): 

74 """Called at start of post_execute phase""" 

75 self._in_post_execute = True 

76 

77 def _on_pre_execute(self): 

78 """Called at start of pre_execute phase""" 

79 self._in_post_execute = False 

80 

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

82 def publish( 

83 self, 

84 data, 

85 metadata=None, 

86 source=_sentinel, 

87 *, 

88 transient=None, 

89 update=False, 

90 **kwargs, 

91 ) -> None: 

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

93 

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

95 more details about this message type. 

96 

97 The following MIME types are currently implemented: 

98 

99 * text/plain 

100 * text/html 

101 * text/markdown 

102 * text/latex 

103 * application/json 

104 * application/javascript 

105 * image/png 

106 * image/jpeg 

107 * image/svg+xml 

108 

109 Parameters 

110 ---------- 

111 data : dict 

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

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

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

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

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

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

118 representation to use. 

119 metadata : dict 

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

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

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

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

124 the data itself. 

125 source : str, deprecated 

126 Unused. 

127 transient : dict, keyword-only 

128 A dictionary for transient data. 

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

130 Examples include 'display_id'. 

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

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

133 rather than creating a new output. 

134 """ 

135 

136 if source is not _sentinel: 

137 import warnings 

138 

139 warnings.warn( 

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

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

142 DeprecationWarning, 

143 stacklevel=2, 

144 ) 

145 

146 handlers: t.Dict = {} 

147 if self.shell is not None: 

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

149 

150 outputs = self.shell.history_manager.outputs 

151 

152 target_execution_count = self.shell.execution_count 

153 if self._in_post_execute: 

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

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

156 target_execution_count = self.shell.execution_count - 1 

157 

158 outputs[target_execution_count].append( 

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

160 ) 

161 

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

163 if mime in data: 

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

165 return 

166 

167 self._is_publishing = True 

168 if "text/plain" in data: 

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

170 self._is_publishing = False 

171 

172 @property 

173 def is_publishing(self): 

174 return self._is_publishing 

175 

176 def clear_output(self, wait=False): 

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

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

179 sys.stdout.flush() 

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

181 sys.stderr.flush() 

182 

183 

184class CapturingDisplayPublisher(DisplayPublisher): 

185 """A DisplayPublisher that stores""" 

186 

187 outputs: List = List() 

188 

189 def publish( 

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

191 ): 

192 self.outputs.append( 

193 { 

194 "data": data, 

195 "metadata": metadata, 

196 "transient": transient, 

197 "update": update, 

198 } 

199 ) 

200 

201 def clear_output(self, wait=False): 

202 super(CapturingDisplayPublisher, self).clear_output(wait) 

203 

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

205 self.outputs.clear()