##// END OF EJS Templates
Make PNG images in the Qt console work in Python 3.
Grahame Bowland -
Show More
@@ -1,252 +1,252 b''
1 1 # Standard libary imports.
2 2 from base64 import decodestring
3 3 import os
4 4 import re
5 5
6 6 # System libary imports.
7 7 from IPython.external.qt import QtCore, QtGui
8 8
9 9 # Local imports
10 10 from IPython.frontend.qt.svg import save_svg, svg_to_clipboard, svg_to_image
11 11 from ipython_widget import IPythonWidget
12 12
13 13
14 14 class RichIPythonWidget(IPythonWidget):
15 15 """ An IPythonWidget that supports rich text, including lists, images, and
16 16 tables. Note that raw performance will be reduced compared to the plain
17 17 text version.
18 18 """
19 19
20 20 # RichIPythonWidget protected class variables.
21 21 _payload_source_plot = 'IPython.zmq.pylab.backend_payload.add_plot_payload'
22 22
23 23 #---------------------------------------------------------------------------
24 24 # 'object' interface
25 25 #---------------------------------------------------------------------------
26 26
27 27 def __init__(self, *args, **kw):
28 28 """ Create a RichIPythonWidget.
29 29 """
30 30 kw['kind'] = 'rich'
31 31 super(RichIPythonWidget, self).__init__(*args, **kw)
32 32
33 33 # Configure the ConsoleWidget HTML exporter for our formats.
34 34 self._html_exporter.image_tag = self._get_image_tag
35 35
36 36 # Dictionary for resolving document resource names to SVG data.
37 37 self._name_to_svg_map = {}
38 38
39 39 #---------------------------------------------------------------------------
40 40 # 'ConsoleWidget' protected interface
41 41 #---------------------------------------------------------------------------
42 42
43 43 def _context_menu_make(self, pos):
44 44 """ Reimplemented to return a custom context menu for images.
45 45 """
46 46 format = self._control.cursorForPosition(pos).charFormat()
47 47 name = format.stringProperty(QtGui.QTextFormat.ImageName)
48 48 if name:
49 49 menu = QtGui.QMenu()
50 50
51 51 menu.addAction('Copy Image', lambda: self._copy_image(name))
52 52 menu.addAction('Save Image As...', lambda: self._save_image(name))
53 53 menu.addSeparator()
54 54
55 55 svg = self._name_to_svg_map.get(name, None)
56 56 if svg is not None:
57 57 menu.addSeparator()
58 58 menu.addAction('Copy SVG', lambda: svg_to_clipboard(svg))
59 59 menu.addAction('Save SVG As...',
60 60 lambda: save_svg(svg, self._control))
61 61 else:
62 62 menu = super(RichIPythonWidget, self)._context_menu_make(pos)
63 63 return menu
64 64
65 65 #---------------------------------------------------------------------------
66 66 # 'BaseFrontendMixin' abstract interface
67 67 #---------------------------------------------------------------------------
68 68
69 69 def _handle_pyout(self, msg):
70 70 """ Overridden to handle rich data types, like SVG.
71 71 """
72 72 if not self._hidden and self._is_from_this_session(msg):
73 73 content = msg['content']
74 74 prompt_number = content['execution_count']
75 75 data = content['data']
76 76 if data.has_key('image/svg+xml'):
77 77 self._append_plain_text(self.output_sep, True)
78 78 self._append_html(self._make_out_prompt(prompt_number), True)
79 79 self._append_svg(data['image/svg+xml'], True)
80 80 self._append_html(self.output_sep2, True)
81 81 elif data.has_key('image/png'):
82 82 self._append_plain_text(self.output_sep, True)
83 83 self._append_html(self._make_out_prompt(prompt_number), True)
84 84 # This helps the output to look nice.
85 85 self._append_plain_text('\n', True)
86 self._append_png(decodestring(data['image/png']), True)
86 self._append_png(decodestring(data['image/png'].encode('ascii')), True)
87 87 self._append_html(self.output_sep2, True)
88 88 else:
89 89 # Default back to the plain text representation.
90 90 return super(RichIPythonWidget, self)._handle_pyout(msg)
91 91
92 92 def _handle_display_data(self, msg):
93 93 """ Overridden to handle rich data types, like SVG.
94 94 """
95 95 if not self._hidden and self._is_from_this_session(msg):
96 96 source = msg['content']['source']
97 97 data = msg['content']['data']
98 98 metadata = msg['content']['metadata']
99 99 # Try to use the svg or html representations.
100 100 # FIXME: Is this the right ordering of things to try?
101 101 if data.has_key('image/svg+xml'):
102 102 svg = data['image/svg+xml']
103 103 self._append_svg(svg, True)
104 104 elif data.has_key('image/png'):
105 105 # PNG data is base64 encoded as it passes over the network
106 106 # in a JSON structure so we decode it.
107 png = decodestring(data['image/png'])
107 png = decodestring(data['image/png'].encode('ascii'))
108 108 self._append_png(png, True)
109 109 else:
110 110 # Default back to the plain text representation.
111 111 return super(RichIPythonWidget, self)._handle_display_data(msg)
112 112
113 113 #---------------------------------------------------------------------------
114 114 # 'RichIPythonWidget' protected interface
115 115 #---------------------------------------------------------------------------
116 116
117 117 def _append_png(self, png, before_prompt=False):
118 118 """ Append raw PNG data to the widget.
119 119 """
120 120 self._append_custom(self._insert_png, png, before_prompt)
121 121
122 122 def _append_svg(self, svg, before_prompt=False):
123 123 """ Append raw SVG data to the widget.
124 124 """
125 125 self._append_custom(self._insert_svg, svg, before_prompt)
126 126
127 127 def _add_image(self, image):
128 128 """ Adds the specified QImage to the document and returns a
129 129 QTextImageFormat that references it.
130 130 """
131 131 document = self._control.document()
132 132 name = str(image.cacheKey())
133 133 document.addResource(QtGui.QTextDocument.ImageResource,
134 134 QtCore.QUrl(name), image)
135 135 format = QtGui.QTextImageFormat()
136 136 format.setName(name)
137 137 return format
138 138
139 139 def _copy_image(self, name):
140 140 """ Copies the ImageResource with 'name' to the clipboard.
141 141 """
142 142 image = self._get_image(name)
143 143 QtGui.QApplication.clipboard().setImage(image)
144 144
145 145 def _get_image(self, name):
146 146 """ Returns the QImage stored as the ImageResource with 'name'.
147 147 """
148 148 document = self._control.document()
149 149 image = document.resource(QtGui.QTextDocument.ImageResource,
150 150 QtCore.QUrl(name))
151 151 return image
152 152
153 153 def _get_image_tag(self, match, path = None, format = "png"):
154 154 """ Return (X)HTML mark-up for the image-tag given by match.
155 155
156 156 Parameters
157 157 ----------
158 158 match : re.SRE_Match
159 159 A match to an HTML image tag as exported by Qt, with
160 160 match.group("Name") containing the matched image ID.
161 161
162 162 path : string|None, optional [default None]
163 163 If not None, specifies a path to which supporting files may be
164 164 written (e.g., for linked images). If None, all images are to be
165 165 included inline.
166 166
167 167 format : "png"|"svg", optional [default "png"]
168 168 Format for returned or referenced images.
169 169 """
170 170 if format == "png":
171 171 try:
172 172 image = self._get_image(match.group("name"))
173 173 except KeyError:
174 174 return "<b>Couldn't find image %s</b>" % match.group("name")
175 175
176 176 if path is not None:
177 177 if not os.path.exists(path):
178 178 os.mkdir(path)
179 179 relpath = os.path.basename(path)
180 180 if image.save("%s/qt_img%s.png" % (path,match.group("name")),
181 181 "PNG"):
182 182 return '<img src="%s/qt_img%s.png">' % (relpath,
183 183 match.group("name"))
184 184 else:
185 185 return "<b>Couldn't save image!</b>"
186 186 else:
187 187 ba = QtCore.QByteArray()
188 188 buffer_ = QtCore.QBuffer(ba)
189 189 buffer_.open(QtCore.QIODevice.WriteOnly)
190 190 image.save(buffer_, "PNG")
191 191 buffer_.close()
192 192 return '<img src="data:image/png;base64,\n%s\n" />' % (
193 193 re.sub(r'(.{60})',r'\1\n',str(ba.toBase64())))
194 194
195 195 elif format == "svg":
196 196 try:
197 197 svg = str(self._name_to_svg_map[match.group("name")])
198 198 except KeyError:
199 199 return "<b>Couldn't find image %s</b>" % match.group("name")
200 200
201 201 # Not currently checking path, because it's tricky to find a
202 202 # cross-browser way to embed external SVG images (e.g., via
203 203 # object or embed tags).
204 204
205 205 # Chop stand-alone header from matplotlib SVG
206 206 offset = svg.find("<svg")
207 207 assert(offset > -1)
208 208
209 209 return svg[offset:]
210 210
211 211 else:
212 212 return '<b>Unrecognized image format</b>'
213 213
214 214 def _insert_png(self, cursor, png):
215 215 """ Insert raw PNG data into the widget.
216 216 """
217 217 try:
218 218 image = QtGui.QImage()
219 219 image.loadFromData(png, 'PNG')
220 220 except ValueError:
221 221 self._insert_plain_text(cursor, 'Received invalid PNG data.')
222 222 else:
223 223 format = self._add_image(image)
224 224 cursor.insertBlock()
225 225 cursor.insertImage(format)
226 226 cursor.insertBlock()
227 227
228 228 def _insert_svg(self, cursor, svg):
229 229 """ Insert raw SVG data into the widet.
230 230 """
231 231 try:
232 232 image = svg_to_image(svg)
233 233 except ValueError:
234 234 self._insert_plain_text(cursor, 'Received invalid SVG data.')
235 235 else:
236 236 format = self._add_image(image)
237 237 self._name_to_svg_map[format.name()] = svg
238 238 cursor.insertBlock()
239 239 cursor.insertImage(format)
240 240 cursor.insertBlock()
241 241
242 242 def _save_image(self, name, format='PNG'):
243 243 """ Shows a save dialog for the ImageResource with 'name'.
244 244 """
245 245 dialog = QtGui.QFileDialog(self._control, 'Save Image')
246 246 dialog.setAcceptMode(QtGui.QFileDialog.AcceptSave)
247 247 dialog.setDefaultSuffix(format.lower())
248 248 dialog.setNameFilter('%s file (*.%s)' % (format, format.lower()))
249 249 if dialog.exec_():
250 250 filename = dialog.selectedFiles()[0]
251 251 image = self._get_image(name)
252 252 image.save(filename, format)
@@ -1,322 +1,322 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Pylab (matplotlib) support utilities.
3 3
4 4 Authors
5 5 -------
6 6
7 7 * Fernando Perez.
8 8 * Brian Granger
9 9 """
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Copyright (C) 2009 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 from cStringIO import StringIO
22 from io import BytesIO
23 23
24 24 from IPython.utils.decorators import flag_calls
25 25
26 26 # If user specifies a GUI, that dictates the backend, otherwise we read the
27 27 # user's mpl default from the mpl rc structure
28 28 backends = {'tk': 'TkAgg',
29 29 'gtk': 'GTKAgg',
30 30 'wx': 'WXAgg',
31 31 'qt': 'Qt4Agg', # qt3 not supported
32 32 'qt4': 'Qt4Agg',
33 33 'osx': 'MacOSX',
34 34 'inline' : 'module://IPython.zmq.pylab.backend_inline'}
35 35
36 36 # We also need a reverse backends2guis mapping that will properly choose which
37 37 # GUI support to activate based on the desired matplotlib backend. For the
38 38 # most part it's just a reverse of the above dict, but we also need to add a
39 39 # few others that map to the same GUI manually:
40 40 backend2gui = dict(zip(backends.values(), backends.keys()))
41 41 # In the reverse mapping, there are a few extra valid matplotlib backends that
42 42 # map to the same GUI support
43 43 backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'
44 44 backend2gui['WX'] = 'wx'
45 45 backend2gui['CocoaAgg'] = 'osx'
46 46
47 47 #-----------------------------------------------------------------------------
48 48 # Matplotlib utilities
49 49 #-----------------------------------------------------------------------------
50 50
51 51
52 52 def getfigs(*fig_nums):
53 53 """Get a list of matplotlib figures by figure numbers.
54 54
55 55 If no arguments are given, all available figures are returned. If the
56 56 argument list contains references to invalid figures, a warning is printed
57 57 but the function continues pasting further figures.
58 58
59 59 Parameters
60 60 ----------
61 61 figs : tuple
62 62 A tuple of ints giving the figure numbers of the figures to return.
63 63 """
64 64 from matplotlib._pylab_helpers import Gcf
65 65 if not fig_nums:
66 66 fig_managers = Gcf.get_all_fig_managers()
67 67 return [fm.canvas.figure for fm in fig_managers]
68 68 else:
69 69 figs = []
70 70 for num in fig_nums:
71 71 f = Gcf.figs.get(num)
72 72 if f is None:
73 73 print('Warning: figure %s not available.' % num)
74 74 else:
75 75 figs.append(f.canvas.figure)
76 76 return figs
77 77
78 78
79 79 def figsize(sizex, sizey):
80 80 """Set the default figure size to be [sizex, sizey].
81 81
82 82 This is just an easy to remember, convenience wrapper that sets::
83 83
84 84 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
85 85 """
86 86 import matplotlib
87 87 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
88 88
89 89
90 90 def print_figure(fig, fmt='png'):
91 91 """Convert a figure to svg or png for inline display."""
92 92 # When there's an empty figure, we shouldn't return anything, otherwise we
93 93 # get big blank areas in the qt console.
94 94 if not fig.axes:
95 95 return
96 96
97 97 fc = fig.get_facecolor()
98 98 ec = fig.get_edgecolor()
99 99 fig.set_facecolor('white')
100 100 fig.set_edgecolor('white')
101 101 try:
102 string_io = StringIO()
102 bytes_io = BytesIO()
103 103 # use 72 dpi to match QTConsole's dpi
104 fig.canvas.print_figure(string_io, format=fmt, dpi=72,
104 fig.canvas.print_figure(bytes_io, format=fmt, dpi=72,
105 105 bbox_inches='tight')
106 data = string_io.getvalue()
106 data = bytes_io.getvalue()
107 107 finally:
108 108 fig.set_facecolor(fc)
109 109 fig.set_edgecolor(ec)
110 110 return data
111 111
112 112
113 113 # We need a little factory function here to create the closure where
114 114 # safe_execfile can live.
115 115 def mpl_runner(safe_execfile):
116 116 """Factory to return a matplotlib-enabled runner for %run.
117 117
118 118 Parameters
119 119 ----------
120 120 safe_execfile : function
121 121 This must be a function with the same interface as the
122 122 :meth:`safe_execfile` method of IPython.
123 123
124 124 Returns
125 125 -------
126 126 A function suitable for use as the ``runner`` argument of the %run magic
127 127 function.
128 128 """
129 129
130 130 def mpl_execfile(fname,*where,**kw):
131 131 """matplotlib-aware wrapper around safe_execfile.
132 132
133 133 Its interface is identical to that of the :func:`execfile` builtin.
134 134
135 135 This is ultimately a call to execfile(), but wrapped in safeties to
136 136 properly handle interactive rendering."""
137 137
138 138 import matplotlib
139 139 import matplotlib.pylab as pylab
140 140
141 141 #print '*** Matplotlib runner ***' # dbg
142 142 # turn off rendering until end of script
143 143 is_interactive = matplotlib.rcParams['interactive']
144 144 matplotlib.interactive(False)
145 145 safe_execfile(fname,*where,**kw)
146 146 matplotlib.interactive(is_interactive)
147 147 # make rendering call now, if the user tried to do it
148 148 if pylab.draw_if_interactive.called:
149 149 pylab.draw()
150 150 pylab.draw_if_interactive.called = False
151 151
152 152 return mpl_execfile
153 153
154 154
155 155 def select_figure_format(shell, fmt):
156 156 """Select figure format for inline backend, either 'png' or 'svg'.
157 157
158 158 Using this method ensures only one figure format is active at a time.
159 159 """
160 160 from matplotlib.figure import Figure
161 161 from IPython.zmq.pylab import backend_inline
162 162
163 163 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
164 164 png_formatter = shell.display_formatter.formatters['image/png']
165 165
166 166 if fmt=='png':
167 167 svg_formatter.type_printers.pop(Figure, None)
168 168 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png'))
169 169 elif fmt=='svg':
170 170 png_formatter.type_printers.pop(Figure, None)
171 171 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg'))
172 172 else:
173 173 raise ValueError("supported formats are: 'png', 'svg', not %r"%fmt)
174 174
175 175 # set the format to be used in the backend()
176 176 backend_inline._figure_format = fmt
177 177
178 178 #-----------------------------------------------------------------------------
179 179 # Code for initializing matplotlib and importing pylab
180 180 #-----------------------------------------------------------------------------
181 181
182 182
183 183 def find_gui_and_backend(gui=None):
184 184 """Given a gui string return the gui and mpl backend.
185 185
186 186 Parameters
187 187 ----------
188 188 gui : str
189 189 Can be one of ('tk','gtk','wx','qt','qt4','inline').
190 190
191 191 Returns
192 192 -------
193 193 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
194 194 'WXAgg','Qt4Agg','module://IPython.zmq.pylab.backend_inline').
195 195 """
196 196
197 197 import matplotlib
198 198
199 199 if gui:
200 200 # select backend based on requested gui
201 201 backend = backends[gui]
202 202 else:
203 203 backend = matplotlib.rcParams['backend']
204 204 # In this case, we need to find what the appropriate gui selection call
205 205 # should be for IPython, so we can activate inputhook accordingly
206 206 gui = backend2gui.get(backend, None)
207 207 return gui, backend
208 208
209 209
210 210 def activate_matplotlib(backend):
211 211 """Activate the given backend and set interactive to True."""
212 212
213 213 import matplotlib
214 214 if backend.startswith('module://'):
215 215 # Work around bug in matplotlib: matplotlib.use converts the
216 216 # backend_id to lowercase even if a module name is specified!
217 217 matplotlib.rcParams['backend'] = backend
218 218 else:
219 219 matplotlib.use(backend)
220 220 matplotlib.interactive(True)
221 221
222 222 # This must be imported last in the matplotlib series, after
223 223 # backend/interactivity choices have been made
224 224 import matplotlib.pylab as pylab
225 225
226 226 # XXX For now leave this commented out, but depending on discussions with
227 227 # mpl-dev, we may be able to allow interactive switching...
228 228 #import matplotlib.pyplot
229 229 #matplotlib.pyplot.switch_backend(backend)
230 230
231 231 pylab.show._needmain = False
232 232 # We need to detect at runtime whether show() is called by the user.
233 233 # For this, we wrap it into a decorator which adds a 'called' flag.
234 234 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
235 235
236 236 def import_pylab(user_ns, backend, import_all=True, shell=None):
237 237 """Import the standard pylab symbols into user_ns."""
238 238
239 239 # Import numpy as np/pyplot as plt are conventions we're trying to
240 240 # somewhat standardize on. Making them available to users by default
241 241 # will greatly help this.
242 242 s = ("import numpy\n"
243 243 "import matplotlib\n"
244 244 "from matplotlib import pylab, mlab, pyplot\n"
245 245 "np = numpy\n"
246 246 "plt = pyplot\n"
247 247 )
248 248 exec s in user_ns
249 249
250 250 if shell is not None:
251 251 exec s in shell.user_ns_hidden
252 252 # If using our svg payload backend, register the post-execution
253 253 # function that will pick up the results for display. This can only be
254 254 # done with access to the real shell object.
255 255 #
256 256 from IPython.zmq.pylab.backend_inline import InlineBackendConfig
257 257
258 258 cfg = InlineBackendConfig.instance(config=shell.config)
259 259 cfg.shell = shell
260 260
261 261 if backend == backends['inline']:
262 262 from IPython.zmq.pylab.backend_inline import flush_figures
263 263 from matplotlib import pyplot
264 264 shell.register_post_execute(flush_figures)
265 265 # load inline_rc
266 266 pyplot.rcParams.update(cfg.rc)
267 267
268 268 # Add 'figsize' to pyplot and to the user's namespace
269 269 user_ns['figsize'] = pyplot.figsize = figsize
270 270 shell.user_ns_hidden['figsize'] = figsize
271 271
272 272 # Setup the default figure format
273 273 fmt = cfg.figure_format
274 274 select_figure_format(shell, fmt)
275 275
276 276 # The old pastefig function has been replaced by display
277 277 from IPython.core.display import display
278 278 # Add display and display_png to the user's namespace
279 279 user_ns['display'] = display
280 280 shell.user_ns_hidden['display'] = display
281 281 user_ns['getfigs'] = getfigs
282 282 shell.user_ns_hidden['getfigs'] = getfigs
283 283
284 284 if import_all:
285 285 s = ("from matplotlib.pylab import *\n"
286 286 "from numpy import *\n")
287 287 exec s in user_ns
288 288 if shell is not None:
289 289 exec s in shell.user_ns_hidden
290 290
291 291
292 292 def pylab_activate(user_ns, gui=None, import_all=True):
293 293 """Activate pylab mode in the user's namespace.
294 294
295 295 Loads and initializes numpy, matplotlib and friends for interactive use.
296 296
297 297 Parameters
298 298 ----------
299 299 user_ns : dict
300 300 Namespace where the imports will occur.
301 301
302 302 gui : optional, string
303 303 A valid gui name following the conventions of the %gui magic.
304 304
305 305 import_all : optional, boolean
306 306 If true, an 'import *' is done from numpy and pylab.
307 307
308 308 Returns
309 309 -------
310 310 The actual gui used (if not given as input, it was obtained from matplotlib
311 311 itself, and will be needed next to configure IPython's gui integration.
312 312 """
313 313 gui, backend = find_gui_and_backend(gui)
314 314 activate_matplotlib(backend)
315 315 import_pylab(user_ns, backend, import_all)
316 316
317 317 print """
318 318 Welcome to pylab, a matplotlib-based Python environment [backend: %s].
319 319 For more information, type 'help(pylab)'.""" % backend
320 320
321 321 return gui
322 322
@@ -1,68 +1,68 b''
1 1 import __builtin__
2 2 from base64 import encodestring
3 3
4 4 from IPython.core.displayhook import DisplayHook
5 5 from IPython.utils.traitlets import Instance, Dict
6 6 from session import extract_header, Session
7 7
8 8 class ZMQDisplayHook(object):
9 9 """A simple displayhook that publishes the object's repr over a ZeroMQ
10 10 socket."""
11 11 topic=None
12 12
13 13 def __init__(self, session, pub_socket):
14 14 self.session = session
15 15 self.pub_socket = pub_socket
16 16 self.parent_header = {}
17 17
18 18 def __call__(self, obj):
19 19 if obj is None:
20 20 return
21 21
22 22 __builtin__._ = obj
23 23 msg = self.session.send(self.pub_socket, u'pyout', {u'data':repr(obj)},
24 24 parent=self.parent_header, ident=self.topic)
25 25
26 26 def set_parent(self, parent):
27 27 self.parent_header = extract_header(parent)
28 28
29 29
30 30 def _encode_binary(format_dict):
31 31 pngdata = format_dict.get('image/png')
32 32 if pngdata is not None:
33 format_dict['image/png'] = encodestring(pngdata)
33 format_dict['image/png'] = encodestring(pngdata).decode('ascii')
34 34 jpegdata = format_dict.get('image/jpeg')
35 35 if jpegdata is not None:
36 format_dict['image/jpeg'] = encodestring(jpegdata)
36 format_dict['image/jpeg'] = encodestring(jpegdata).decode('ascii')
37 37
38 38
39 39 class ZMQShellDisplayHook(DisplayHook):
40 40 """A displayhook subclass that publishes data using ZeroMQ. This is intended
41 41 to work with an InteractiveShell instance. It sends a dict of different
42 42 representations of the object."""
43 43
44 44 session = Instance(Session)
45 45 pub_socket = Instance('zmq.Socket')
46 46 parent_header = Dict({})
47 47
48 48 def set_parent(self, parent):
49 49 """Set the parent for outbound messages."""
50 50 self.parent_header = extract_header(parent)
51 51
52 52 def start_displayhook(self):
53 53 self.msg = self.session.msg(u'pyout', {}, parent=self.parent_header)
54 54
55 55 def write_output_prompt(self):
56 56 """Write the output prompt."""
57 57 if self.do_full_cache:
58 58 self.msg['content']['execution_count'] = self.prompt_count
59 59
60 60 def write_format_data(self, format_dict):
61 61 _encode_binary(format_dict)
62 62 self.msg['content']['data'] = format_dict
63 63
64 64 def finish_displayhook(self):
65 65 """Finish up all displayhook activities."""
66 66 self.session.send(self.pub_socket, self.msg)
67 67 self.msg = None
68 68
General Comments 0
You need to be logged in to leave comments. Login now