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