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