##// END OF EJS Templates
Adding transient and update, change to dict for outputs
Henry Fredrick Schreiner -
Show More
@@ -1,124 +1,125 b''
1 1 """An interface for publishing rich data to frontends.
2 2
3 3 There are two components of the display system:
4 4
5 5 * Display formatters, which take a Python object and compute the
6 6 representation of the object in various formats (text, HTML, SVG, etc.).
7 7 * The display publisher that is used to send the representation data to the
8 8 various frontends.
9 9
10 10 This module defines the logic display publishing. The display publisher uses
11 11 the ``display_data`` message type that is defined in the IPython messaging
12 12 spec.
13 13 """
14 14
15 15 # Copyright (c) IPython Development Team.
16 16 # Distributed under the terms of the Modified BSD License.
17 17
18 18
19 19 import sys
20 20
21 21 from traitlets.config.configurable import Configurable
22 22 from traitlets import List
23 23
24 24 # This used to be defined here - it is imported for backwards compatibility
25 25 from .display import publish_display_data
26 26
27 27 #-----------------------------------------------------------------------------
28 28 # Main payload class
29 29 #-----------------------------------------------------------------------------
30 30
31 31 class DisplayPublisher(Configurable):
32 32 """A traited class that publishes display data to frontends.
33 33
34 34 Instances of this class are created by the main IPython object and should
35 35 be accessed there.
36 36 """
37 37
38 38 def _validate_data(self, data, metadata=None):
39 39 """Validate the display data.
40 40
41 41 Parameters
42 42 ----------
43 43 data : dict
44 44 The formata data dictionary.
45 45 metadata : dict
46 46 Any metadata for the data.
47 47 """
48 48
49 49 if not isinstance(data, dict):
50 50 raise TypeError('data must be a dict, got: %r' % data)
51 51 if metadata is not None:
52 52 if not isinstance(metadata, dict):
53 53 raise TypeError('metadata must be a dict, got: %r' % data)
54 54
55 55 # use * to indicate transient, update are keyword-only
56 56 def publish(self, data, metadata=None, source=None, *, transient=None, update=False, **kwargs):
57 57 """Publish data and metadata to all frontends.
58 58
59 59 See the ``display_data`` message in the messaging documentation for
60 60 more details about this message type.
61 61
62 62 The following MIME types are currently implemented:
63 63
64 64 * text/plain
65 65 * text/html
66 66 * text/markdown
67 67 * text/latex
68 68 * application/json
69 69 * application/javascript
70 70 * image/png
71 71 * image/jpeg
72 72 * image/svg+xml
73 73
74 74 Parameters
75 75 ----------
76 76 data : dict
77 77 A dictionary having keys that are valid MIME types (like
78 78 'text/plain' or 'image/svg+xml') and values that are the data for
79 79 that MIME type. The data itself must be a JSON'able data
80 80 structure. Minimally all data should have the 'text/plain' data,
81 81 which can be displayed by all frontends. If more than the plain
82 82 text is given, it is up to the frontend to decide which
83 83 representation to use.
84 84 metadata : dict
85 85 A dictionary for metadata related to the data. This can contain
86 86 arbitrary key, value pairs that frontends can use to interpret
87 87 the data. Metadata specific to each mime-type can be specified
88 88 in the metadata dict with the same mime-type keys as
89 89 the data itself.
90 90 source : str, deprecated
91 91 Unused.
92 92 transient: dict, keyword-only
93 93 A dictionary for transient data.
94 94 Data in this dictionary should not be persisted as part of saving this output.
95 95 Examples include 'display_id'.
96 96 update: bool, keyword-only, default: False
97 97 If True, only update existing outputs with the same display_id,
98 98 rather than creating a new output.
99 99 """
100 100
101 101 # The default is to simply write the plain text data using sys.stdout.
102 102 if 'text/plain' in data:
103 103 print(data['text/plain'])
104 104
105 105 def clear_output(self, wait=False):
106 106 """Clear the output of the cell receiving output."""
107 107 print('\033[2K\r', end='')
108 108 sys.stdout.flush()
109 109 print('\033[2K\r', end='')
110 110 sys.stderr.flush()
111 111
112 112
113 113 class CapturingDisplayPublisher(DisplayPublisher):
114 114 """A DisplayPublisher that stores"""
115 115 outputs = List()
116 116
117 117 def publish(self, data, metadata=None, source=None, *, transient=None, update=False):
118 self.outputs.append((data, metadata))
118 self.outputs.append({'data':data, 'metadata':metadata,
119 'transient':transient, 'update':update})
119 120
120 121 def clear_output(self, wait=False):
121 122 super(CapturingDisplayPublisher, self).clear_output(wait)
122 123
123 124 # empty the list, *do not* reassign a new list
124 del self.outputs[:]
125 self.outputs.clear()
@@ -1,167 +1,170 b''
1 1 # encoding: utf-8
2 2 """IO capturing utilities."""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7
8 8 import sys
9 9 from io import StringIO
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Classes and functions
13 13 #-----------------------------------------------------------------------------
14 14
15 15
16 16 class RichOutput(object):
17 def __init__(self, data=None, metadata=None):
17 def __init__(self, data=None, metadata=None, transient=None, update=False):
18 18 self.data = data or {}
19 19 self.metadata = metadata or {}
20
20 self.transient = transient or {}
21 self.update = update
22
21 23 def display(self):
22 24 from IPython.display import publish_display_data
23 publish_display_data(data=self.data, metadata=self.metadata)
24
25 publish_display_data(data=self.data, metadata=self.metadata,
26 transient=self.transient, update=self.update)
27
25 28 def _repr_mime_(self, mime):
26 29 if mime not in self.data:
27 30 return
28 31 data = self.data[mime]
29 32 if mime in self.metadata:
30 33 return data, self.metadata[mime]
31 34 else:
32 35 return data
33 36
34 37 def _repr_mimebundle_(self, include=None, exclude=None):
35 38 return self.data, self.metadata
36 39
37 40 def _repr_html_(self):
38 41 return self._repr_mime_("text/html")
39
42
40 43 def _repr_latex_(self):
41 44 return self._repr_mime_("text/latex")
42
45
43 46 def _repr_json_(self):
44 47 return self._repr_mime_("application/json")
45
48
46 49 def _repr_javascript_(self):
47 50 return self._repr_mime_("application/javascript")
48
51
49 52 def _repr_png_(self):
50 53 return self._repr_mime_("image/png")
51
54
52 55 def _repr_jpeg_(self):
53 56 return self._repr_mime_("image/jpeg")
54
57
55 58 def _repr_svg_(self):
56 59 return self._repr_mime_("image/svg+xml")
57 60
58 61
59 62 class CapturedIO(object):
60 63 """Simple object for containing captured stdout/err and rich display StringIO objects
61 64
62 65 Each instance `c` has three attributes:
63 66
64 67 - ``c.stdout`` : standard output as a string
65 68 - ``c.stderr`` : standard error as a string
66 69 - ``c.outputs``: a list of rich display outputs
67 70
68 71 Additionally, there's a ``c.show()`` method which will print all of the
69 72 above in the same order, and can be invoked simply via ``c()``.
70 73 """
71
74
72 75 def __init__(self, stdout, stderr, outputs=None):
73 76 self._stdout = stdout
74 77 self._stderr = stderr
75 78 if outputs is None:
76 79 outputs = []
77 80 self._outputs = outputs
78
81
79 82 def __str__(self):
80 83 return self.stdout
81
84
82 85 @property
83 86 def stdout(self):
84 87 "Captured standard output"
85 88 if not self._stdout:
86 89 return ''
87 90 return self._stdout.getvalue()
88
91
89 92 @property
90 93 def stderr(self):
91 94 "Captured standard error"
92 95 if not self._stderr:
93 96 return ''
94 97 return self._stderr.getvalue()
95
98
96 99 @property
97 100 def outputs(self):
98 101 """A list of the captured rich display outputs, if any.
99
102
100 103 If you have a CapturedIO object ``c``, these can be displayed in IPython
101 104 using::
102 105
103 106 from IPython.display import display
104 107 for o in c.outputs:
105 108 display(o)
106 109 """
107 return [ RichOutput(d, md) for d, md in self._outputs ]
108
110 return [ RichOutput(**kargs) for kargs in self._outputs ]
111
109 112 def show(self):
110 113 """write my output to sys.stdout/err as appropriate"""
111 114 sys.stdout.write(self.stdout)
112 115 sys.stderr.write(self.stderr)
113 116 sys.stdout.flush()
114 117 sys.stderr.flush()
115 for data, metadata in self._outputs:
116 RichOutput(data, metadata).display()
117
118 for kargs in self._outputs:
119 RichOutput(**kargs).display()
120
118 121 __call__ = show
119 122
120 123
121 124 class capture_output(object):
122 125 """context manager for capturing stdout/err"""
123 126 stdout = True
124 127 stderr = True
125 128 display = True
126
129
127 130 def __init__(self, stdout=True, stderr=True, display=True):
128 131 self.stdout = stdout
129 132 self.stderr = stderr
130 133 self.display = display
131 134 self.shell = None
132
135
133 136 def __enter__(self):
134 137 from IPython.core.getipython import get_ipython
135 138 from IPython.core.displaypub import CapturingDisplayPublisher
136 139 from IPython.core.displayhook import CapturingDisplayHook
137
140
138 141 self.sys_stdout = sys.stdout
139 142 self.sys_stderr = sys.stderr
140
143
141 144 if self.display:
142 145 self.shell = get_ipython()
143 146 if self.shell is None:
144 147 self.save_display_pub = None
145 148 self.display = False
146
149
147 150 stdout = stderr = outputs = None
148 151 if self.stdout:
149 152 stdout = sys.stdout = StringIO()
150 153 if self.stderr:
151 154 stderr = sys.stderr = StringIO()
152 155 if self.display:
153 156 self.save_display_pub = self.shell.display_pub
154 157 self.shell.display_pub = CapturingDisplayPublisher()
155 158 outputs = self.shell.display_pub.outputs
156 159 self.save_display_hook = sys.displayhook
157 160 sys.displayhook = CapturingDisplayHook(shell=self.shell,
158 161 outputs=outputs)
159
162
160 163 return CapturedIO(stdout, stderr, outputs)
161
164
162 165 def __exit__(self, exc_type, exc_value, traceback):
163 166 sys.stdout = self.sys_stdout
164 167 sys.stderr = self.sys_stderr
165 168 if self.display and self.shell:
166 169 self.shell.display_pub = self.save_display_pub
167 170 sys.displayhook = self.save_display_hook
General Comments 0
You need to be logged in to leave comments. Login now