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