##// END OF EJS Templates
clear_output implies '\r' for terminal frontends
MinRK -
Show More
@@ -1,501 +1,513 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Top-level display functions for displaying object in different formats.
3 3
4 4 Authors:
5 5
6 6 * Brian Granger
7 7 """
8 8
9 9 #-----------------------------------------------------------------------------
10 10 # Copyright (C) 2008-2011 The IPython Development Team
11 11 #
12 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
14 14 #-----------------------------------------------------------------------------
15 15
16 16 #-----------------------------------------------------------------------------
17 17 # Imports
18 18 #-----------------------------------------------------------------------------
19 19
20 from __future__ import print_function
21
20 22 from xml.dom import minidom
21 23
22 24 from .displaypub import (
23 25 publish_pretty, publish_html,
24 26 publish_latex, publish_svg,
25 27 publish_png, publish_json,
26 28 publish_javascript, publish_jpeg
27 29 )
28 30
29 31 #-----------------------------------------------------------------------------
30 32 # Main functions
31 33 #-----------------------------------------------------------------------------
32 34
33 35 def display(*objs, **kwargs):
34 36 """Display a Python object in all frontends.
35 37
36 38 By default all representations will be computed and sent to the frontends.
37 39 Frontends can decide which representation is used and how.
38 40
39 41 Parameters
40 42 ----------
41 43 objs : tuple of objects
42 44 The Python objects to display.
43 45 include : list or tuple, optional
44 46 A list of format type strings (MIME types) to include in the
45 47 format data dict. If this is set *only* the format types included
46 48 in this list will be computed.
47 49 exclude : list or tuple, optional
48 50 A list of format type string (MIME types) to exclue in the format
49 51 data dict. If this is set all format types will be computed,
50 52 except for those included in this argument.
51 53 """
52 54 include = kwargs.get('include')
53 55 exclude = kwargs.get('exclude')
54 56
55 57 from IPython.core.interactiveshell import InteractiveShell
56 58 inst = InteractiveShell.instance()
57 59 format = inst.display_formatter.format
58 60 publish = inst.display_pub.publish
59 61
60 62 for obj in objs:
61 63 format_dict = format(obj, include=include, exclude=exclude)
62 64 publish('IPython.core.display.display', format_dict)
63 65
64 66
65 67 def display_pretty(*objs, **kwargs):
66 68 """Display the pretty (default) representation of an object.
67 69
68 70 Parameters
69 71 ----------
70 72 objs : tuple of objects
71 73 The Python objects to display, or if raw=True raw text data to
72 74 display.
73 75 raw : bool
74 76 Are the data objects raw data or Python objects that need to be
75 77 formatted before display? [default: False]
76 78 """
77 79 raw = kwargs.pop('raw',False)
78 80 if raw:
79 81 for obj in objs:
80 82 publish_pretty(obj)
81 83 else:
82 84 display(*objs, include=['text/plain'])
83 85
84 86
85 87 def display_html(*objs, **kwargs):
86 88 """Display the HTML representation of an object.
87 89
88 90 Parameters
89 91 ----------
90 92 objs : tuple of objects
91 93 The Python objects to display, or if raw=True raw HTML data to
92 94 display.
93 95 raw : bool
94 96 Are the data objects raw data or Python objects that need to be
95 97 formatted before display? [default: False]
96 98 """
97 99 raw = kwargs.pop('raw',False)
98 100 if raw:
99 101 for obj in objs:
100 102 publish_html(obj)
101 103 else:
102 104 display(*objs, include=['text/plain','text/html'])
103 105
104 106
105 107 def display_svg(*objs, **kwargs):
106 108 """Display the SVG representation of an object.
107 109
108 110 Parameters
109 111 ----------
110 112 objs : tuple of objects
111 113 The Python objects to display, or if raw=True raw svg data to
112 114 display.
113 115 raw : bool
114 116 Are the data objects raw data or Python objects that need to be
115 117 formatted before display? [default: False]
116 118 """
117 119 raw = kwargs.pop('raw',False)
118 120 if raw:
119 121 for obj in objs:
120 122 publish_svg(obj)
121 123 else:
122 124 display(*objs, include=['text/plain','image/svg+xml'])
123 125
124 126
125 127 def display_png(*objs, **kwargs):
126 128 """Display the PNG representation of an object.
127 129
128 130 Parameters
129 131 ----------
130 132 objs : tuple of objects
131 133 The Python objects to display, or if raw=True raw png data to
132 134 display.
133 135 raw : bool
134 136 Are the data objects raw data or Python objects that need to be
135 137 formatted before display? [default: False]
136 138 """
137 139 raw = kwargs.pop('raw',False)
138 140 if raw:
139 141 for obj in objs:
140 142 publish_png(obj)
141 143 else:
142 144 display(*objs, include=['text/plain','image/png'])
143 145
144 146
145 147 def display_jpeg(*objs, **kwargs):
146 148 """Display the JPEG representation of an object.
147 149
148 150 Parameters
149 151 ----------
150 152 objs : tuple of objects
151 153 The Python objects to display, or if raw=True raw JPEG data to
152 154 display.
153 155 raw : bool
154 156 Are the data objects raw data or Python objects that need to be
155 157 formatted before display? [default: False]
156 158 """
157 159 raw = kwargs.pop('raw',False)
158 160 if raw:
159 161 for obj in objs:
160 162 publish_jpeg(obj)
161 163 else:
162 164 display(*objs, include=['text/plain','image/jpeg'])
163 165
164 166
165 167 def display_latex(*objs, **kwargs):
166 168 """Display the LaTeX representation of an object.
167 169
168 170 Parameters
169 171 ----------
170 172 objs : tuple of objects
171 173 The Python objects to display, or if raw=True raw latex data to
172 174 display.
173 175 raw : bool
174 176 Are the data objects raw data or Python objects that need to be
175 177 formatted before display? [default: False]
176 178 """
177 179 raw = kwargs.pop('raw',False)
178 180 if raw:
179 181 for obj in objs:
180 182 publish_latex(obj)
181 183 else:
182 184 display(*objs, include=['text/plain','text/latex'])
183 185
184 186
185 187 def display_json(*objs, **kwargs):
186 188 """Display the JSON representation of an object.
187 189
188 190 Parameters
189 191 ----------
190 192 objs : tuple of objects
191 193 The Python objects to display, or if raw=True raw json data to
192 194 display.
193 195 raw : bool
194 196 Are the data objects raw data or Python objects that need to be
195 197 formatted before display? [default: False]
196 198 """
197 199 raw = kwargs.pop('raw',False)
198 200 if raw:
199 201 for obj in objs:
200 202 publish_json(obj)
201 203 else:
202 204 display(*objs, include=['text/plain','application/json'])
203 205
204 206
205 207 def display_javascript(*objs, **kwargs):
206 208 """Display the Javascript representation of an object.
207 209
208 210 Parameters
209 211 ----------
210 212 objs : tuple of objects
211 213 The Python objects to display, or if raw=True raw javascript data to
212 214 display.
213 215 raw : bool
214 216 Are the data objects raw data or Python objects that need to be
215 217 formatted before display? [default: False]
216 218 """
217 219 raw = kwargs.pop('raw',False)
218 220 if raw:
219 221 for obj in objs:
220 222 publish_javascript(obj)
221 223 else:
222 224 display(*objs, include=['text/plain','application/javascript'])
223 225
224 226 #-----------------------------------------------------------------------------
225 227 # Smart classes
226 228 #-----------------------------------------------------------------------------
227 229
228 230
229 231 class DisplayObject(object):
230 232 """An object that wraps data to be displayed."""
231 233
232 234 _read_flags = 'r'
233 235
234 236 def __init__(self, data=None, url=None, filename=None):
235 237 """Create a display object given raw data.
236 238
237 239 When this object is returned by an expression or passed to the
238 240 display function, it will result in the data being displayed
239 241 in the frontend. The MIME type of the data should match the
240 242 subclasses used, so the Png subclass should be used for 'image/png'
241 243 data. If the data is a URL, the data will first be downloaded
242 244 and then displayed. If
243 245
244 246 Parameters
245 247 ----------
246 248 data : unicode, str or bytes
247 249 The raw data or a URL to download the data from.
248 250 url : unicode
249 251 A URL to download the data from.
250 252 filename : unicode
251 253 Path to a local file to load the data from.
252 254 """
253 255 if data is not None and data.startswith('http'):
254 256 self.url = data
255 257 self.filename = None
256 258 self.data = None
257 259 else:
258 260 self.data = data
259 261 self.url = url
260 262 self.filename = None if filename is None else unicode(filename)
261 263 self.reload()
262 264
263 265 def reload(self):
264 266 """Reload the raw data from file or URL."""
265 267 if self.filename is not None:
266 268 with open(self.filename, self._read_flags) as f:
267 269 self.data = f.read()
268 270 elif self.url is not None:
269 271 try:
270 272 import urllib2
271 273 response = urllib2.urlopen(self.url)
272 274 self.data = response.read()
273 275 # extract encoding from header, if there is one:
274 276 encoding = None
275 277 for sub in response.headers['content-type'].split(';'):
276 278 sub = sub.strip()
277 279 if sub.startswith('charset'):
278 280 encoding = sub.split('=')[-1].strip()
279 281 break
280 282 # decode data, if an encoding was specified
281 283 if encoding:
282 284 self.data = self.data.decode(encoding, 'replace')
283 285 except:
284 286 self.data = None
285 287
286 288 class Pretty(DisplayObject):
287 289
288 290 def _repr_pretty_(self):
289 291 return self.data
290 292
291 293
292 294 class HTML(DisplayObject):
293 295
294 296 def _repr_html_(self):
295 297 return self.data
296 298
297 299
298 300 class Math(DisplayObject):
299 301
300 302 def _repr_latex_(self):
301 303 s = self.data.strip('$')
302 304 return "$$%s$$" % s
303 305
304 306
305 307 class Latex(DisplayObject):
306 308
307 309 def _repr_latex_(self):
308 310 return self.data
309 311
310 312
311 313 class SVG(DisplayObject):
312 314
313 315 # wrap data in a property, which extracts the <svg> tag, discarding
314 316 # document headers
315 317 _data = None
316 318
317 319 @property
318 320 def data(self):
319 321 return self._data
320 322
321 323 @data.setter
322 324 def data(self, svg):
323 325 if svg is None:
324 326 self._data = None
325 327 return
326 328 # parse into dom object
327 329 x = minidom.parseString(svg)
328 330 # get svg tag (should be 1)
329 331 found_svg = x.getElementsByTagName('svg')
330 332 if found_svg:
331 333 svg = found_svg[0].toxml()
332 334 else:
333 335 # fallback on the input, trust the user
334 336 # but this is probably an error.
335 337 pass
336 338 self._data = svg
337 339
338 340 def _repr_svg_(self):
339 341 return self.data
340 342
341 343
342 344 class JSON(DisplayObject):
343 345
344 346 def _repr_json_(self):
345 347 return self.data
346 348
347 349 css_t = """$("head").append($("<link/>").attr({
348 350 rel: "stylesheet",
349 351 type: "text/css",
350 352 href: "%s"
351 353 }));
352 354 """
353 355
354 356 lib_t1 = """$.getScript("%s", function () {
355 357 """
356 358 lib_t2 = """});
357 359 """
358 360
359 361 class Javascript(DisplayObject):
360 362
361 363 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
362 364 """Create a Javascript display object given raw data.
363 365
364 366 When this object is returned by an expression or passed to the
365 367 display function, it will result in the data being displayed
366 368 in the frontend. If the data is a URL, the data will first be
367 369 downloaded and then displayed.
368 370
369 371 Parameters
370 372 ----------
371 373 data : unicode, str or bytes
372 374 The Javascript source code or a URL to download it from.
373 375 url : unicode
374 376 A URL to download the data from.
375 377 filename : unicode
376 378 Path to a local file to load the data from.
377 379 lib : list or str
378 380 A sequence of Javascript library URLs to load asynchronously before
379 381 running the source code. The full URLs of the libraries should
380 382 be given. A single Javascript library URL can also be given as a
381 383 string.
382 384 css: : list or str
383 385 A sequence of css files to load before running the source code.
384 386 The full URLs of the css files should be give. A single css URL
385 387 can also be given as a string.
386 388 """
387 389 if isinstance(lib, basestring):
388 390 lib = [lib]
389 391 elif lib is None:
390 392 lib = []
391 393 if isinstance(css, basestring):
392 394 css = [css]
393 395 elif css is None:
394 396 css = []
395 397 if not isinstance(lib, (list,tuple)):
396 398 raise TypeError('expected sequence, got: %r' % lib)
397 399 if not isinstance(css, (list,tuple)):
398 400 raise TypeError('expected sequence, got: %r' % css)
399 401 self.lib = lib
400 402 self.css = css
401 403 super(Javascript, self).__init__(data=data, url=url, filename=filename)
402 404
403 405 def _repr_javascript_(self):
404 406 r = ''
405 407 for c in self.css:
406 408 r += css_t % c
407 409 for l in self.lib:
408 410 r += lib_t1 % l
409 411 r += self.data
410 412 r += lib_t2*len(self.lib)
411 413 return r
412 414
413 415
414 416 class Image(DisplayObject):
415 417
416 418 _read_flags = 'rb'
417 419
418 420 def __init__(self, data=None, url=None, filename=None, format=u'png', embed=False):
419 421 """Create a display an PNG/JPEG image given raw data.
420 422
421 423 When this object is returned by an expression or passed to the
422 424 display function, it will result in the image being displayed
423 425 in the frontend.
424 426
425 427 Parameters
426 428 ----------
427 429 data : unicode, str or bytes
428 430 The raw data or a URL to download the data from.
429 431 url : unicode
430 432 A URL to download the data from.
431 433 filename : unicode
432 434 Path to a local file to load the data from.
433 435 format : unicode
434 436 The format of the image data (png/jpeg/jpg). If a filename or URL is given
435 437 for format will be inferred from the filename extension.
436 438 embed : bool
437 439 Should the image data be embedded in the notebook using a data URI (True)
438 440 or be loaded using an <img> tag. Set this to True if you want the image
439 441 to be viewable later with no internet connection. If a filename is given
440 442 embed is always set to True.
441 443 """
442 444 if filename is not None:
443 445 ext = self._find_ext(filename)
444 446 elif url is not None:
445 447 ext = self._find_ext(url)
446 448 elif data.startswith('http'):
447 449 ext = self._find_ext(data)
448 450 else:
449 451 ext = None
450 452 if ext is not None:
451 453 if ext == u'jpg' or ext == u'jpeg':
452 454 format = u'jpeg'
453 455 if ext == u'png':
454 456 format = u'png'
455 457 self.format = unicode(format).lower()
456 458 self.embed = True if filename is not None else embed
457 459 super(Image, self).__init__(data=data, url=url, filename=filename)
458 460
459 461 def reload(self):
460 462 """Reload the raw data from file or URL."""
461 463 if self.embed:
462 464 super(Image,self).reload()
463 465
464 466 def _repr_html_(self):
465 467 if not self.embed:
466 468 return u'<img src="%s" />' % self.url
467 469
468 470 def _repr_png_(self):
469 471 if self.embed and self.format == u'png':
470 472 return self.data
471 473
472 474 def _repr_jpeg_(self):
473 475 if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
474 476 return self.data
475 477
476 478 def _find_ext(self, s):
477 479 return unicode(s.split('.')[-1].lower())
478 480
479 481
480 482 def clear_output(stdout=True, stderr=True, other=True):
481 483 """Clear the output of the current cell receiving output.
482 484
483 485 Optionally, each of stdout/stderr or other non-stream data (e.g. anything
484 486 produced by display()) can be excluded from the clear event.
485 487
486 488 By default, everything is cleared.
487 489
488 490 Parameters
489 491 ----------
490 492 stdout : bool [default: True]
491 493 Whether to clear stdout.
492 494 stderr : bool [default: True]
493 495 Whether to clear stderr.
494 496 other : bool [default: True]
495 497 Whether to clear everything else that is not stdout/stderr
496 498 (e.g. figures,images,HTML, any result of display()).
497 499 """
498 500 from IPython.core.interactiveshell import InteractiveShell
499 InteractiveShell.instance().display_pub.clear_output(
500 stdout=stdout, stderr=stderr, other=other,
501 )
501 if InteractiveShell.initialized():
502 InteractiveShell.instance().display_pub.clear_output(
503 stdout=stdout, stderr=stderr, other=other,
504 )
505 else:
506 from IPython.utils import io
507 if stdout:
508 print('\033[2K\r', file=io.stdout, end='')
509 io.stdout.flush()
510 if stderr:
511 print('\033[2K\r', file=io.stderr, end='')
512 io.stderr.flush()
513
@@ -1,302 +1,309 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 Authors:
15 15
16 16 * Brian Granger
17 17 """
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Copyright (C) 2008-2011 The IPython Development Team
21 21 #
22 22 # Distributed under the terms of the BSD License. The full license is in
23 23 # the file COPYING, distributed as part of this software.
24 24 #-----------------------------------------------------------------------------
25 25
26 26 #-----------------------------------------------------------------------------
27 27 # Imports
28 28 #-----------------------------------------------------------------------------
29 29
30 30 from __future__ import print_function
31 31
32 32 from IPython.config.configurable import Configurable
33 from IPython.utils import io
33 34
34 35 #-----------------------------------------------------------------------------
35 36 # Main payload class
36 37 #-----------------------------------------------------------------------------
37 38
38 39 class DisplayPublisher(Configurable):
39 40 """A traited class that publishes display data to frontends.
40 41
41 42 Instances of this class are created by the main IPython object and should
42 43 be accessed there.
43 44 """
44 45
45 46 def _validate_data(self, source, data, metadata=None):
46 47 """Validate the display data.
47 48
48 49 Parameters
49 50 ----------
50 51 source : str
51 52 The fully dotted name of the callable that created the data, like
52 53 :func:`foo.bar.my_formatter`.
53 54 data : dict
54 55 The formata data dictionary.
55 56 metadata : dict
56 57 Any metadata for the data.
57 58 """
58 59
59 60 if not isinstance(source, basestring):
60 61 raise TypeError('source must be a str, got: %r' % source)
61 62 if not isinstance(data, dict):
62 63 raise TypeError('data must be a dict, got: %r' % data)
63 64 if metadata is not None:
64 65 if not isinstance(metadata, dict):
65 66 raise TypeError('metadata must be a dict, got: %r' % data)
66 67
67 68 def publish(self, source, data, metadata=None):
68 69 """Publish data and metadata to all frontends.
69 70
70 71 See the ``display_data`` message in the messaging documentation for
71 72 more details about this message type.
72 73
73 74 The following MIME types are currently implemented:
74 75
75 76 * text/plain
76 77 * text/html
77 78 * text/latex
78 79 * application/json
79 80 * application/javascript
80 81 * image/png
81 82 * image/jpeg
82 83 * image/svg+xml
83 84
84 85 Parameters
85 86 ----------
86 87 source : str
87 88 A string that give the function or method that created the data,
88 89 such as 'IPython.core.page'.
89 90 data : dict
90 91 A dictionary having keys that are valid MIME types (like
91 92 'text/plain' or 'image/svg+xml') and values that are the data for
92 93 that MIME type. The data itself must be a JSON'able data
93 94 structure. Minimally all data should have the 'text/plain' data,
94 95 which can be displayed by all frontends. If more than the plain
95 96 text is given, it is up to the frontend to decide which
96 97 representation to use.
97 98 metadata : dict
98 99 A dictionary for metadata related to the data. This can contain
99 100 arbitrary key, value pairs that frontends can use to interpret
100 101 the data.
101 102 """
102 from IPython.utils import io
103
103 104 # The default is to simply write the plain text data using io.stdout.
104 105 if data.has_key('text/plain'):
105 106 print(data['text/plain'], file=io.stdout)
106 107
107 def clear_output(self, stdout=True, stderr=True, other=True):
108 """Clear the output of the cell receiving output."""
109 pass
108 def clear_output(self, stdout=True, stderr=True, other=True):
109 """Clear the output of the cell receiving output."""
110 if stdout:
111 print('\033[2K\r', file=io.stdout, end='')
112 io.stdout.flush()
113 if stderr:
114 print('\033[2K\r', file=io.stderr, end='')
115 io.stderr.flush()
116
110 117
111 118
112 119 def publish_display_data(source, data, metadata=None):
113 120 """Publish data and metadata to all frontends.
114 121
115 122 See the ``display_data`` message in the messaging documentation for
116 123 more details about this message type.
117 124
118 125 The following MIME types are currently implemented:
119 126
120 127 * text/plain
121 128 * text/html
122 129 * text/latex
123 130 * application/json
124 131 * application/javascript
125 132 * image/png
126 133 * image/jpeg
127 134 * image/svg+xml
128 135
129 136 Parameters
130 137 ----------
131 138 source : str
132 139 A string that give the function or method that created the data,
133 140 such as 'IPython.core.page'.
134 141 data : dict
135 142 A dictionary having keys that are valid MIME types (like
136 143 'text/plain' or 'image/svg+xml') and values that are the data for
137 144 that MIME type. The data itself must be a JSON'able data
138 145 structure. Minimally all data should have the 'text/plain' data,
139 146 which can be displayed by all frontends. If more than the plain
140 147 text is given, it is up to the frontend to decide which
141 148 representation to use.
142 149 metadata : dict
143 150 A dictionary for metadata related to the data. This can contain
144 151 arbitrary key, value pairs that frontends can use to interpret
145 152 the data.
146 153 """
147 154 from IPython.core.interactiveshell import InteractiveShell
148 155 InteractiveShell.instance().display_pub.publish(
149 156 source,
150 157 data,
151 158 metadata
152 159 )
153 160
154 161
155 162 def publish_pretty(data, metadata=None):
156 163 """Publish raw text data to all frontends.
157 164
158 165 Parameters
159 166 ----------
160 167 data : unicode
161 168 The raw text data to publish.
162 169 metadata : dict
163 170 A dictionary for metadata related to the data. This can contain
164 171 arbitrary key, value pairs that frontends can use to interpret
165 172 the data.
166 173 """
167 174 publish_display_data(
168 175 u'IPython.core.displaypub.publish_pretty',
169 176 {'text/plain':data},
170 177 metadata=metadata
171 178 )
172 179
173 180
174 181 def publish_html(data, metadata=None):
175 182 """Publish raw HTML data to all frontends.
176 183
177 184 Parameters
178 185 ----------
179 186 data : unicode
180 187 The raw HTML data to publish.
181 188 metadata : dict
182 189 A dictionary for metadata related to the data. This can contain
183 190 arbitrary key, value pairs that frontends can use to interpret
184 191 the data.
185 192 """
186 193 publish_display_data(
187 194 u'IPython.core.displaypub.publish_html',
188 195 {'text/html':data},
189 196 metadata=metadata
190 197 )
191 198
192 199
193 200 def publish_latex(data, metadata=None):
194 201 """Publish raw LaTeX data to all frontends.
195 202
196 203 Parameters
197 204 ----------
198 205 data : unicode
199 206 The raw LaTeX data to publish.
200 207 metadata : dict
201 208 A dictionary for metadata related to the data. This can contain
202 209 arbitrary key, value pairs that frontends can use to interpret
203 210 the data.
204 211 """
205 212 publish_display_data(
206 213 u'IPython.core.displaypub.publish_latex',
207 214 {'text/latex':data},
208 215 metadata=metadata
209 216 )
210 217
211 218 def publish_png(data, metadata=None):
212 219 """Publish raw binary PNG data to all frontends.
213 220
214 221 Parameters
215 222 ----------
216 223 data : str/bytes
217 224 The raw binary PNG data to publish.
218 225 metadata : dict
219 226 A dictionary for metadata related to the data. This can contain
220 227 arbitrary key, value pairs that frontends can use to interpret
221 228 the data.
222 229 """
223 230 publish_display_data(
224 231 u'IPython.core.displaypub.publish_png',
225 232 {'image/png':data},
226 233 metadata=metadata
227 234 )
228 235
229 236
230 237 def publish_jpeg(data, metadata=None):
231 238 """Publish raw binary JPEG data to all frontends.
232 239
233 240 Parameters
234 241 ----------
235 242 data : str/bytes
236 243 The raw binary JPEG data to publish.
237 244 metadata : dict
238 245 A dictionary for metadata related to the data. This can contain
239 246 arbitrary key, value pairs that frontends can use to interpret
240 247 the data.
241 248 """
242 249 publish_display_data(
243 250 u'IPython.core.displaypub.publish_jpeg',
244 251 {'image/jpeg':data},
245 252 metadata=metadata
246 253 )
247 254
248 255
249 256 def publish_svg(data, metadata=None):
250 257 """Publish raw SVG data to all frontends.
251 258
252 259 Parameters
253 260 ----------
254 261 data : unicode
255 262 The raw SVG data to publish.
256 263 metadata : dict
257 264 A dictionary for metadata related to the data. This can contain
258 265 arbitrary key, value pairs that frontends can use to interpret
259 266 the data.
260 267 """
261 268 publish_display_data(
262 269 u'IPython.core.displaypub.publish_svg',
263 270 {'image/svg+xml':data},
264 271 metadata=metadata
265 272 )
266 273
267 274 def publish_json(data, metadata=None):
268 275 """Publish raw JSON data to all frontends.
269 276
270 277 Parameters
271 278 ----------
272 279 data : unicode
273 280 The raw JSON data to publish.
274 281 metadata : dict
275 282 A dictionary for metadata related to the data. This can contain
276 283 arbitrary key, value pairs that frontends can use to interpret
277 284 the data.
278 285 """
279 286 publish_display_data(
280 287 u'IPython.core.displaypub.publish_json',
281 288 {'application/json':data},
282 289 metadata=metadata
283 290 )
284 291
285 292 def publish_javascript(data, metadata=None):
286 293 """Publish raw Javascript data to all frontends.
287 294
288 295 Parameters
289 296 ----------
290 297 data : unicode
291 298 The raw Javascript data to publish.
292 299 metadata : dict
293 300 A dictionary for metadata related to the data. This can contain
294 301 arbitrary key, value pairs that frontends can use to interpret
295 302 the data.
296 303 """
297 304 publish_display_data(
298 305 u'IPython.core.displaypub.publish_javascript',
299 306 {'application/javascript':data},
300 307 metadata=metadata
301 308 )
302 309
@@ -1,516 +1,523 b''
1 1 """A ZMQ-based subclass of InteractiveShell.
2 2
3 3 This code is meant to ease the refactoring of the base InteractiveShell into
4 4 something with a cleaner architecture for 2-process use, without actually
5 5 breaking InteractiveShell itself. So we're doing something a bit ugly, where
6 6 we subclass and override what we want to fix. Once this is working well, we
7 7 can go back to the base class and refactor the code for a cleaner inheritance
8 8 implementation that doesn't rely on so much monkeypatching.
9 9
10 10 But this lets us maintain a fully working IPython as we develop the new
11 11 machinery. This should thus be thought of as scaffolding.
12 12 """
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16 from __future__ import print_function
17 17
18 18 # Stdlib
19 19 import inspect
20 20 import os
21 21 import sys
22 22 from subprocess import Popen, PIPE
23 23
24 24 # Our own
25 25 from IPython.core.interactiveshell import (
26 26 InteractiveShell, InteractiveShellABC
27 27 )
28 28 from IPython.core import page, pylabtools
29 29 from IPython.core.autocall import ZMQExitAutocall
30 30 from IPython.core.displaypub import DisplayPublisher
31 31 from IPython.core.macro import Macro
32 32 from IPython.core.magic import MacroToEdit
33 33 from IPython.core.payloadpage import install_payload_page
34 34 from IPython.lib.kernel import (
35 35 get_connection_file, get_connection_info, connect_qtconsole
36 36 )
37 37 from IPython.utils import io
38 38 from IPython.utils.jsonutil import json_clean
39 39 from IPython.utils.path import get_py_filename
40 40 from IPython.utils.process import arg_split
41 41 from IPython.utils.traitlets import Instance, Type, Dict, CBool
42 42 from IPython.utils.warn import warn, error
43 43 from IPython.zmq.displayhook import ZMQShellDisplayHook, _encode_binary
44 44 from IPython.zmq.session import extract_header
45 45 from session import Session
46 46
47 47
48 48 #-----------------------------------------------------------------------------
49 49 # Functions and classes
50 50 #-----------------------------------------------------------------------------
51 51
52 52 class ZMQDisplayPublisher(DisplayPublisher):
53 53 """A display publisher that publishes data using a ZeroMQ PUB socket."""
54 54
55 55 session = Instance(Session)
56 56 pub_socket = Instance('zmq.Socket')
57 57 parent_header = Dict({})
58 58
59 59 def set_parent(self, parent):
60 60 """Set the parent for outbound messages."""
61 61 self.parent_header = extract_header(parent)
62 62
63 63 def _flush_streams(self):
64 64 """flush IO Streams prior to display"""
65 65 sys.stdout.flush()
66 66 sys.stderr.flush()
67 67
68 68 def publish(self, source, data, metadata=None):
69 69 self._flush_streams()
70 70 if metadata is None:
71 71 metadata = {}
72 72 self._validate_data(source, data, metadata)
73 73 content = {}
74 74 content['source'] = source
75 75 _encode_binary(data)
76 76 content['data'] = data
77 77 content['metadata'] = metadata
78 78 self.session.send(
79 79 self.pub_socket, u'display_data', json_clean(content),
80 80 parent=self.parent_header
81 81 )
82 82
83 83 def clear_output(self, stdout=True, stderr=True, other=True):
84 self._flush_streams()
85 84 content = dict(stdout=stdout, stderr=stderr, other=other)
85
86 if stdout:
87 print('\r', file=sys.stdout, end='')
88 if stderr:
89 print('\r', file=sys.stderr, end='')
90
91 self._flush_streams()
92
86 93 self.session.send(
87 94 self.pub_socket, u'clear_output', content,
88 95 parent=self.parent_header
89 96 )
90 97
91 98 class ZMQInteractiveShell(InteractiveShell):
92 99 """A subclass of InteractiveShell for ZMQ."""
93 100
94 101 displayhook_class = Type(ZMQShellDisplayHook)
95 102 display_pub_class = Type(ZMQDisplayPublisher)
96 103
97 104 # Override the traitlet in the parent class, because there's no point using
98 105 # readline for the kernel. Can be removed when the readline code is moved
99 106 # to the terminal frontend.
100 107 colors_force = CBool(True)
101 108 readline_use = CBool(False)
102 109 # autoindent has no meaning in a zmqshell, and attempting to enable it
103 110 # will print a warning in the absence of readline.
104 111 autoindent = CBool(False)
105 112
106 113 exiter = Instance(ZMQExitAutocall)
107 114 def _exiter_default(self):
108 115 return ZMQExitAutocall(self)
109 116
110 117 keepkernel_on_exit = None
111 118
112 119 # Over ZeroMQ, GUI control isn't done with PyOS_InputHook as there is no
113 120 # interactive input being read; we provide event loop support in ipkernel
114 121 from .eventloops import enable_gui
115 122 enable_gui = staticmethod(enable_gui)
116 123
117 124 def init_environment(self):
118 125 """Configure the user's environment.
119 126
120 127 """
121 128 env = os.environ
122 129 # These two ensure 'ls' produces nice coloring on BSD-derived systems
123 130 env['TERM'] = 'xterm-color'
124 131 env['CLICOLOR'] = '1'
125 132 # Since normal pagers don't work at all (over pexpect we don't have
126 133 # single-key control of the subprocess), try to disable paging in
127 134 # subprocesses as much as possible.
128 135 env['PAGER'] = 'cat'
129 136 env['GIT_PAGER'] = 'cat'
130 137
131 138 # And install the payload version of page.
132 139 install_payload_page()
133 140
134 141 def auto_rewrite_input(self, cmd):
135 142 """Called to show the auto-rewritten input for autocall and friends.
136 143
137 144 FIXME: this payload is currently not correctly processed by the
138 145 frontend.
139 146 """
140 147 new = self.prompt_manager.render('rewrite') + cmd
141 148 payload = dict(
142 149 source='IPython.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input',
143 150 transformed_input=new,
144 151 )
145 152 self.payload_manager.write_payload(payload)
146 153
147 154 def ask_exit(self):
148 155 """Engage the exit actions."""
149 156 payload = dict(
150 157 source='IPython.zmq.zmqshell.ZMQInteractiveShell.ask_exit',
151 158 exit=True,
152 159 keepkernel=self.keepkernel_on_exit,
153 160 )
154 161 self.payload_manager.write_payload(payload)
155 162
156 163 def _showtraceback(self, etype, evalue, stb):
157 164
158 165 exc_content = {
159 166 u'traceback' : stb,
160 167 u'ename' : unicode(etype.__name__),
161 168 u'evalue' : unicode(evalue)
162 169 }
163 170
164 171 dh = self.displayhook
165 172 # Send exception info over pub socket for other clients than the caller
166 173 # to pick up
167 174 exc_msg = dh.session.send(dh.pub_socket, u'pyerr', json_clean(exc_content), dh.parent_header)
168 175
169 176 # FIXME - Hack: store exception info in shell object. Right now, the
170 177 # caller is reading this info after the fact, we need to fix this logic
171 178 # to remove this hack. Even uglier, we need to store the error status
172 179 # here, because in the main loop, the logic that sets it is being
173 180 # skipped because runlines swallows the exceptions.
174 181 exc_content[u'status'] = u'error'
175 182 self._reply_content = exc_content
176 183 # /FIXME
177 184
178 185 return exc_content
179 186
180 187 #------------------------------------------------------------------------
181 188 # Magic overrides
182 189 #------------------------------------------------------------------------
183 190 # Once the base class stops inheriting from magic, this code needs to be
184 191 # moved into a separate machinery as well. For now, at least isolate here
185 192 # the magics which this class needs to implement differently from the base
186 193 # class, or that are unique to it.
187 194
188 195 def magic_doctest_mode(self,parameter_s=''):
189 196 """Toggle doctest mode on and off.
190 197
191 198 This mode is intended to make IPython behave as much as possible like a
192 199 plain Python shell, from the perspective of how its prompts, exceptions
193 200 and output look. This makes it easy to copy and paste parts of a
194 201 session into doctests. It does so by:
195 202
196 203 - Changing the prompts to the classic ``>>>`` ones.
197 204 - Changing the exception reporting mode to 'Plain'.
198 205 - Disabling pretty-printing of output.
199 206
200 207 Note that IPython also supports the pasting of code snippets that have
201 208 leading '>>>' and '...' prompts in them. This means that you can paste
202 209 doctests from files or docstrings (even if they have leading
203 210 whitespace), and the code will execute correctly. You can then use
204 211 '%history -t' to see the translated history; this will give you the
205 212 input after removal of all the leading prompts and whitespace, which
206 213 can be pasted back into an editor.
207 214
208 215 With these features, you can switch into this mode easily whenever you
209 216 need to do testing and changes to doctests, without having to leave
210 217 your existing IPython session.
211 218 """
212 219
213 220 from IPython.utils.ipstruct import Struct
214 221
215 222 # Shorthands
216 223 shell = self.shell
217 224 disp_formatter = self.shell.display_formatter
218 225 ptformatter = disp_formatter.formatters['text/plain']
219 226 # dstore is a data store kept in the instance metadata bag to track any
220 227 # changes we make, so we can undo them later.
221 228 dstore = shell.meta.setdefault('doctest_mode', Struct())
222 229 save_dstore = dstore.setdefault
223 230
224 231 # save a few values we'll need to recover later
225 232 mode = save_dstore('mode', False)
226 233 save_dstore('rc_pprint', ptformatter.pprint)
227 234 save_dstore('rc_plain_text_only',disp_formatter.plain_text_only)
228 235 save_dstore('xmode', shell.InteractiveTB.mode)
229 236
230 237 if mode == False:
231 238 # turn on
232 239 ptformatter.pprint = False
233 240 disp_formatter.plain_text_only = True
234 241 shell.magic_xmode('Plain')
235 242 else:
236 243 # turn off
237 244 ptformatter.pprint = dstore.rc_pprint
238 245 disp_formatter.plain_text_only = dstore.rc_plain_text_only
239 246 shell.magic_xmode(dstore.xmode)
240 247
241 248 # Store new mode and inform on console
242 249 dstore.mode = bool(1-int(mode))
243 250 mode_label = ['OFF','ON'][dstore.mode]
244 251 print('Doctest mode is:', mode_label)
245 252
246 253 # Send the payload back so that clients can modify their prompt display
247 254 payload = dict(
248 255 source='IPython.zmq.zmqshell.ZMQInteractiveShell.magic_doctest_mode',
249 256 mode=dstore.mode)
250 257 self.payload_manager.write_payload(payload)
251 258
252 259 def magic_edit(self,parameter_s='',last_call=['','']):
253 260 """Bring up an editor and execute the resulting code.
254 261
255 262 Usage:
256 263 %edit [options] [args]
257 264
258 265 %edit runs an external text editor. You will need to set the command for
259 266 this editor via the ``TerminalInteractiveShell.editor`` option in your
260 267 configuration file before it will work.
261 268
262 269 This command allows you to conveniently edit multi-line code right in
263 270 your IPython session.
264 271
265 272 If called without arguments, %edit opens up an empty editor with a
266 273 temporary file and will execute the contents of this file when you
267 274 close it (don't forget to save it!).
268 275
269 276
270 277 Options:
271 278
272 279 -n <number>: open the editor at a specified line number. By default,
273 280 the IPython editor hook uses the unix syntax 'editor +N filename', but
274 281 you can configure this by providing your own modified hook if your
275 282 favorite editor supports line-number specifications with a different
276 283 syntax.
277 284
278 285 -p: this will call the editor with the same data as the previous time
279 286 it was used, regardless of how long ago (in your current session) it
280 287 was.
281 288
282 289 -r: use 'raw' input. This option only applies to input taken from the
283 290 user's history. By default, the 'processed' history is used, so that
284 291 magics are loaded in their transformed version to valid Python. If
285 292 this option is given, the raw input as typed as the command line is
286 293 used instead. When you exit the editor, it will be executed by
287 294 IPython's own processor.
288 295
289 296 -x: do not execute the edited code immediately upon exit. This is
290 297 mainly useful if you are editing programs which need to be called with
291 298 command line arguments, which you can then do using %run.
292 299
293 300
294 301 Arguments:
295 302
296 303 If arguments are given, the following possibilites exist:
297 304
298 305 - The arguments are numbers or pairs of colon-separated numbers (like
299 306 1 4:8 9). These are interpreted as lines of previous input to be
300 307 loaded into the editor. The syntax is the same of the %macro command.
301 308
302 309 - If the argument doesn't start with a number, it is evaluated as a
303 310 variable and its contents loaded into the editor. You can thus edit
304 311 any string which contains python code (including the result of
305 312 previous edits).
306 313
307 314 - If the argument is the name of an object (other than a string),
308 315 IPython will try to locate the file where it was defined and open the
309 316 editor at the point where it is defined. You can use `%edit function`
310 317 to load an editor exactly at the point where 'function' is defined,
311 318 edit it and have the file be executed automatically.
312 319
313 320 If the object is a macro (see %macro for details), this opens up your
314 321 specified editor with a temporary file containing the macro's data.
315 322 Upon exit, the macro is reloaded with the contents of the file.
316 323
317 324 Note: opening at an exact line is only supported under Unix, and some
318 325 editors (like kedit and gedit up to Gnome 2.8) do not understand the
319 326 '+NUMBER' parameter necessary for this feature. Good editors like
320 327 (X)Emacs, vi, jed, pico and joe all do.
321 328
322 329 - If the argument is not found as a variable, IPython will look for a
323 330 file with that name (adding .py if necessary) and load it into the
324 331 editor. It will execute its contents with execfile() when you exit,
325 332 loading any code in the file into your interactive namespace.
326 333
327 334 After executing your code, %edit will return as output the code you
328 335 typed in the editor (except when it was an existing file). This way
329 336 you can reload the code in further invocations of %edit as a variable,
330 337 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
331 338 the output.
332 339
333 340 Note that %edit is also available through the alias %ed.
334 341
335 342 This is an example of creating a simple function inside the editor and
336 343 then modifying it. First, start up the editor:
337 344
338 345 In [1]: ed
339 346 Editing... done. Executing edited code...
340 347 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
341 348
342 349 We can then call the function foo():
343 350
344 351 In [2]: foo()
345 352 foo() was defined in an editing session
346 353
347 354 Now we edit foo. IPython automatically loads the editor with the
348 355 (temporary) file where foo() was previously defined:
349 356
350 357 In [3]: ed foo
351 358 Editing... done. Executing edited code...
352 359
353 360 And if we call foo() again we get the modified version:
354 361
355 362 In [4]: foo()
356 363 foo() has now been changed!
357 364
358 365 Here is an example of how to edit a code snippet successive
359 366 times. First we call the editor:
360 367
361 368 In [5]: ed
362 369 Editing... done. Executing edited code...
363 370 hello
364 371 Out[5]: "print 'hello'n"
365 372
366 373 Now we call it again with the previous output (stored in _):
367 374
368 375 In [6]: ed _
369 376 Editing... done. Executing edited code...
370 377 hello world
371 378 Out[6]: "print 'hello world'n"
372 379
373 380 Now we call it with the output #8 (stored in _8, also as Out[8]):
374 381
375 382 In [7]: ed _8
376 383 Editing... done. Executing edited code...
377 384 hello again
378 385 Out[7]: "print 'hello again'n"
379 386 """
380 387
381 388 opts,args = self.parse_options(parameter_s,'prn:')
382 389
383 390 try:
384 391 filename, lineno, _ = self._find_edit_target(args, opts, last_call)
385 392 except MacroToEdit as e:
386 393 # TODO: Implement macro editing over 2 processes.
387 394 print("Macro editing not yet implemented in 2-process model.")
388 395 return
389 396
390 397 # Make sure we send to the client an absolute path, in case the working
391 398 # directory of client and kernel don't match
392 399 filename = os.path.abspath(filename)
393 400
394 401 payload = {
395 402 'source' : 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic',
396 403 'filename' : filename,
397 404 'line_number' : lineno
398 405 }
399 406 self.payload_manager.write_payload(payload)
400 407
401 408 # A few magics that are adapted to the specifics of using pexpect and a
402 409 # remote terminal
403 410
404 411 def magic_clear(self, arg_s):
405 412 """Clear the terminal."""
406 413 if os.name == 'posix':
407 414 self.shell.system("clear")
408 415 else:
409 416 self.shell.system("cls")
410 417
411 418 if os.name == 'nt':
412 419 # This is the usual name in windows
413 420 magic_cls = magic_clear
414 421
415 422 # Terminal pagers won't work over pexpect, but we do have our own pager
416 423
417 424 def magic_less(self, arg_s):
418 425 """Show a file through the pager.
419 426
420 427 Files ending in .py are syntax-highlighted."""
421 428 cont = open(arg_s).read()
422 429 if arg_s.endswith('.py'):
423 430 cont = self.shell.pycolorize(cont)
424 431 page.page(cont)
425 432
426 433 magic_more = magic_less
427 434
428 435 # Man calls a pager, so we also need to redefine it
429 436 if os.name == 'posix':
430 437 def magic_man(self, arg_s):
431 438 """Find the man page for the given command and display in pager."""
432 439 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
433 440 split=False))
434 441
435 442 # FIXME: this is specific to the GUI, so we should let the gui app load
436 443 # magics at startup that are only for the gui. Once the gui app has proper
437 444 # profile and configuration management, we can have it initialize a kernel
438 445 # with a special config file that provides these.
439 446 def magic_guiref(self, arg_s):
440 447 """Show a basic reference about the GUI console."""
441 448 from IPython.core.usage import gui_reference
442 449 page.page(gui_reference, auto_html=True)
443 450
444 451 def magic_connect_info(self, arg_s):
445 452 """Print information for connecting other clients to this kernel
446 453
447 454 It will print the contents of this session's connection file, as well as
448 455 shortcuts for local clients.
449 456
450 457 In the simplest case, when called from the most recently launched kernel,
451 458 secondary clients can be connected, simply with:
452 459
453 460 $> ipython <app> --existing
454 461
455 462 """
456 463
457 464 from IPython.core.application import BaseIPythonApplication as BaseIPApp
458 465
459 466 if BaseIPApp.initialized():
460 467 app = BaseIPApp.instance()
461 468 security_dir = app.profile_dir.security_dir
462 469 profile = app.profile
463 470 else:
464 471 profile = 'default'
465 472 security_dir = ''
466 473
467 474 try:
468 475 connection_file = get_connection_file()
469 476 info = get_connection_info(unpack=False)
470 477 except Exception as e:
471 478 error("Could not get connection info: %r" % e)
472 479 return
473 480
474 481 # add profile flag for non-default profile
475 482 profile_flag = "--profile %s" % profile if profile != 'default' else ""
476 483
477 484 # if it's in the security dir, truncate to basename
478 485 if security_dir == os.path.dirname(connection_file):
479 486 connection_file = os.path.basename(connection_file)
480 487
481 488
482 489 print (info + '\n')
483 490 print ("Paste the above JSON into a file, and connect with:\n"
484 491 " $> ipython <app> --existing <file>\n"
485 492 "or, if you are local, you can connect with just:\n"
486 493 " $> ipython <app> --existing {0} {1}\n"
487 494 "or even just:\n"
488 495 " $> ipython <app> --existing {1}\n"
489 496 "if this is the most recent IPython session you have started.".format(
490 497 connection_file, profile_flag
491 498 )
492 499 )
493 500
494 501 def magic_qtconsole(self, arg_s):
495 502 """Open a qtconsole connected to this kernel.
496 503
497 504 Useful for connecting a qtconsole to running notebooks, for better
498 505 debugging.
499 506 """
500 507 try:
501 508 p = connect_qtconsole(argv=arg_split(arg_s, os.name=='posix'))
502 509 except Exception as e:
503 510 error("Could not start qtconsole: %r" % e)
504 511 return
505 512
506 513 def set_next_input(self, text):
507 514 """Send the specified text to the frontend to be presented at the next
508 515 input cell."""
509 516 payload = dict(
510 517 source='IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input',
511 518 text=text
512 519 )
513 520 self.payload_manager.write_payload(payload)
514 521
515 522
516 523 InteractiveShellABC.register(ZMQInteractiveShell)
General Comments 0
You need to be logged in to leave comments. Login now