Show More
@@ -268,39 +268,47 b' var IPython = (function (IPython) {' | |||
|
268 | 268 | }); |
|
269 | 269 | return json; |
|
270 | 270 | }; |
|
271 | ||
|
271 | ||
|
272 | 272 | OutputArea.prototype.append_output = function (json) { |
|
273 | 273 | this.expand(); |
|
274 | ||
|
275 | // validate output data types | |
|
276 | json = this.validate_output(json); | |
|
277 | ||
|
274 | 278 | // Clear the output if clear is queued. |
|
275 | 279 | var needs_height_reset = false; |
|
276 | 280 | if (this.clear_queued) { |
|
277 | 281 | this.clear_output(false); |
|
278 | 282 | needs_height_reset = true; |
|
279 | 283 | } |
|
280 | ||
|
281 | // validate output data types | |
|
282 | json = this.validate_output(json); | |
|
283 | 284 | |
|
284 | 285 | if (json.output_type === 'pyout') { |
|
285 | 286 | this.append_pyout(json); |
|
286 | 287 | } else if (json.output_type === 'pyerr') { |
|
287 | 288 | this.append_pyerr(json); |
|
288 | } else if (json.output_type === 'display_data') { | |
|
289 | this.append_display_data(json); | |
|
290 | 289 | } else if (json.output_type === 'stream') { |
|
291 | 290 | this.append_stream(json); |
|
292 | 291 | } |
|
293 | ||
|
294 | this.outputs.push(json); | |
|
295 | ||
|
296 | // Only reset the height to automatic if the height is currently | |
|
297 | // fixed (done by wait=True flag on clear_output). | |
|
298 | if (needs_height_reset) { | |
|
299 | this.element.height(''); | |
|
300 | } | |
|
301 | 292 | |
|
293 | // We must release the animation fixed height in a callback since Gecko | |
|
294 | // (FireFox) doesn't render the image immediately as the data is | |
|
295 | // available. | |
|
302 | 296 | var that = this; |
|
303 | setTimeout(function(){that.element.trigger('resize');}, 100); | |
|
297 | var handle_appended = function ($el) { | |
|
298 | // Only reset the height to automatic if the height is currently | |
|
299 | // fixed (done by wait=True flag on clear_output). | |
|
300 | if (needs_height_reset) { | |
|
301 | that.element.height(''); | |
|
302 | } | |
|
303 | that.element.trigger('resize'); | |
|
304 | }; | |
|
305 | if (json.output_type === 'display_data') { | |
|
306 | this.append_display_data(json, handle_appended); | |
|
307 | } else { | |
|
308 | handle_appended(); | |
|
309 | } | |
|
310 | ||
|
311 | this.outputs.push(json); | |
|
304 | 312 | }; |
|
305 | 313 | |
|
306 | 314 | |
@@ -475,9 +483,9 b' var IPython = (function (IPython) {' | |||
|
475 | 483 | }; |
|
476 | 484 | |
|
477 | 485 | |
|
478 | OutputArea.prototype.append_display_data = function (json) { | |
|
486 | OutputArea.prototype.append_display_data = function (json, handle_inserted) { | |
|
479 | 487 | var toinsert = this.create_output_area(); |
|
480 | if (this.append_mime_type(json, toinsert)) { | |
|
488 | if (this.append_mime_type(json, toinsert, handle_inserted)) { | |
|
481 | 489 | this._safe_append(toinsert); |
|
482 | 490 | // If we just output latex, typeset it. |
|
483 | 491 | if ((json['text/latex'] !== undefined) || (json['text/html'] !== undefined)) { |
@@ -494,7 +502,7 b' var IPython = (function (IPython) {' | |||
|
494 | 502 | 'image/jpeg' : true |
|
495 | 503 | }; |
|
496 | 504 | |
|
497 | OutputArea.prototype.append_mime_type = function (json, element) { | |
|
505 | OutputArea.prototype.append_mime_type = function (json, element, handle_inserted) { | |
|
498 | 506 | for (var type_i in OutputArea.display_order) { |
|
499 | 507 | var type = OutputArea.display_order[type_i]; |
|
500 | 508 | var append = OutputArea.append_map[type]; |
@@ -511,7 +519,14 b' var IPython = (function (IPython) {' | |||
|
511 | 519 | } |
|
512 | 520 | } |
|
513 | 521 | var md = json.metadata || {}; |
|
514 | var toinsert = append.apply(this, [value, md, element]); | |
|
522 | var toinsert = append.apply(this, [value, md, element, handle_inserted]); | |
|
523 | // Since only the png and jpeg mime types call the inserted | |
|
524 | // callback, if the mime type is something other we must call the | |
|
525 | // inserted callback only when the element is actually inserted | |
|
526 | // into the DOM. Use a timeout of 0 to do this. | |
|
527 | if (['image/png', 'image/jpeg'].indexOf(type) < 0 && handle_inserted !== undefined) { | |
|
528 | setTimeout(handle_inserted, 0); | |
|
529 | } | |
|
515 | 530 | $([IPython.events]).trigger('output_appended.OutputArea', [type, value, md, toinsert]); |
|
516 | 531 | return toinsert; |
|
517 | 532 | } |
@@ -611,10 +626,16 b' var IPython = (function (IPython) {' | |||
|
611 | 626 | if (width !== undefined) img.attr('width', width); |
|
612 | 627 | }; |
|
613 | 628 | |
|
614 | var append_png = function (png, md, element) { | |
|
629 | var append_png = function (png, md, element, handle_inserted) { | |
|
615 | 630 | var type = 'image/png'; |
|
616 | 631 | var toinsert = this.create_output_subarea(md, "output_png", type); |
|
617 | var img = $("<img/>").attr('src','data:image/png;base64,'+png); | |
|
632 | var img = $("<img/>"); | |
|
633 | if (handle_inserted !== undefined) { | |
|
634 | img.on('load', function(){ | |
|
635 | handle_inserted(img); | |
|
636 | }); | |
|
637 | } | |
|
638 | img[0].src = 'data:image/png;base64,'+ png; | |
|
618 | 639 | set_width_height(img, md, 'image/png'); |
|
619 | 640 | this._dblclick_to_reset_size(img); |
|
620 | 641 | toinsert.append(img); |
@@ -623,10 +644,16 b' var IPython = (function (IPython) {' | |||
|
623 | 644 | }; |
|
624 | 645 | |
|
625 | 646 | |
|
626 | var append_jpeg = function (jpeg, md, element) { | |
|
647 | var append_jpeg = function (jpeg, md, element, handle_inserted) { | |
|
627 | 648 | var type = 'image/jpeg'; |
|
628 | 649 | var toinsert = this.create_output_subarea(md, "output_jpeg", type); |
|
629 | var img = $("<img/>").attr('src','data:image/jpeg;base64,'+jpeg); | |
|
650 | var img = $("<img/>"); | |
|
651 | if (handle_inserted !== undefined) { | |
|
652 | img.on('load', function(){ | |
|
653 | handle_inserted(img); | |
|
654 | }); | |
|
655 | } | |
|
656 | img[0].src = 'data:image/jpeg;base64,'+ jpeg; | |
|
630 | 657 | set_width_height(img, md, 'image/jpeg'); |
|
631 | 658 | this._dblclick_to_reset_size(img); |
|
632 | 659 | toinsert.append(img); |
@@ -748,7 +775,10 b' var IPython = (function (IPython) {' | |||
|
748 | 775 | this.clear_queued = false; |
|
749 | 776 | } |
|
750 | 777 | |
|
751 |
// |
|
|
778 | // Clear all | |
|
779 | // Remove load event handlers from img tags because we don't want | |
|
780 | // them to fire if the image is never added to the page. | |
|
781 | this.element.find('img').off('load'); | |
|
752 | 782 | this.element.html(""); |
|
753 | 783 | this.outputs = []; |
|
754 | 784 | this.trusted = true; |
@@ -90,11 +90,7 b' class ZMQDisplayPublisher(DisplayPublisher):' | |||
|
90 | 90 | |
|
91 | 91 | def clear_output(self, wait=False): |
|
92 | 92 | content = dict(wait=wait) |
|
93 | ||
|
94 | print('\r', file=sys.stdout, end='') | |
|
95 | print('\r', file=sys.stderr, end='') | |
|
96 | 93 | self._flush_streams() |
|
97 | ||
|
98 | 94 | self.session.send( |
|
99 | 95 | self.pub_socket, u'clear_output', content, |
|
100 | 96 | parent=self.parent_header, ident=self.topic, |
@@ -197,6 +197,9 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||
|
197 | 197 | self._local_kernel = kw.get('local_kernel', |
|
198 | 198 | FrontendWidget._local_kernel) |
|
199 | 199 | |
|
200 | # Whether or not a clear_output call is pending new output. | |
|
201 | self._pending_clearoutput = False | |
|
202 | ||
|
200 | 203 | #--------------------------------------------------------------------------- |
|
201 | 204 | # 'ConsoleWidget' public interface |
|
202 | 205 | #--------------------------------------------------------------------------- |
@@ -339,6 +342,14 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||
|
339 | 342 | #--------------------------------------------------------------------------- |
|
340 | 343 | # 'BaseFrontendMixin' abstract interface |
|
341 | 344 | #--------------------------------------------------------------------------- |
|
345 | def _handle_clear_output(self, msg): | |
|
346 | """Handle clear output messages.""" | |
|
347 | if not self._hidden and self._is_from_this_session(msg): | |
|
348 | wait = msg['content'].get('wait', True) | |
|
349 | if wait: | |
|
350 | self._pending_clearoutput = True | |
|
351 | else: | |
|
352 | self.clear_output() | |
|
342 | 353 | |
|
343 | 354 | def _handle_complete_reply(self, rep): |
|
344 | 355 | """ Handle replies for tab completion. |
@@ -520,6 +531,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||
|
520 | 531 | """ |
|
521 | 532 | self.log.debug("pyout: %s", msg.get('content', '')) |
|
522 | 533 | if not self._hidden and self._is_from_this_session(msg): |
|
534 | self.flush_clearoutput() | |
|
523 | 535 | text = msg['content']['data'] |
|
524 | 536 | self._append_plain_text(text + '\n', before_prompt=True) |
|
525 | 537 | |
@@ -528,13 +540,8 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||
|
528 | 540 | """ |
|
529 | 541 | self.log.debug("stream: %s", msg.get('content', '')) |
|
530 | 542 | if not self._hidden and self._is_from_this_session(msg): |
|
531 | # Most consoles treat tabs as being 8 space characters. Convert tabs | |
|
532 | # to spaces so that output looks as expected regardless of this | |
|
533 | # widget's tab width. | |
|
534 | text = msg['content']['data'].expandtabs(8) | |
|
535 | ||
|
536 | self._append_plain_text(text, before_prompt=True) | |
|
537 | self._control.moveCursor(QtGui.QTextCursor.End) | |
|
543 | self.flush_clearoutput() | |
|
544 | self.append_stream(msg['content']['data']) | |
|
538 | 545 | |
|
539 | 546 | def _handle_shutdown_reply(self, msg): |
|
540 | 547 | """ Handle shutdown signal, only if from other console. |
@@ -685,6 +692,29 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||
|
685 | 692 | before_prompt=True |
|
686 | 693 | ) |
|
687 | 694 | |
|
695 | def append_stream(self, text): | |
|
696 | """Appends text to the output stream.""" | |
|
697 | # Most consoles treat tabs as being 8 space characters. Convert tabs | |
|
698 | # to spaces so that output looks as expected regardless of this | |
|
699 | # widget's tab width. | |
|
700 | text = text.expandtabs(8) | |
|
701 | self._append_plain_text(text, before_prompt=True) | |
|
702 | self._control.moveCursor(QtGui.QTextCursor.End) | |
|
703 | ||
|
704 | def flush_clearoutput(self): | |
|
705 | """If a clearoutput is pending, execute it.""" | |
|
706 | if self._pending_clearoutput: | |
|
707 | self._pending_clearoutput = False | |
|
708 | self.clear_output() | |
|
709 | ||
|
710 | def clear_output(self): | |
|
711 | """Clears the current line of output.""" | |
|
712 | cursor = self._control.textCursor() | |
|
713 | cursor.beginEditBlock() | |
|
714 | cursor.movePosition(cursor.StartOfLine, cursor.KeepAnchor) | |
|
715 | cursor.insertText('') | |
|
716 | cursor.endEditBlock() | |
|
717 | ||
|
688 | 718 | #--------------------------------------------------------------------------- |
|
689 | 719 | # 'FrontendWidget' protected interface |
|
690 | 720 | #--------------------------------------------------------------------------- |
@@ -140,7 +140,6 b' class IPythonWidget(FrontendWidget):' | |||
|
140 | 140 | #--------------------------------------------------------------------------- |
|
141 | 141 | # 'BaseFrontendMixin' abstract interface |
|
142 | 142 | #--------------------------------------------------------------------------- |
|
143 | ||
|
144 | 143 | def _handle_complete_reply(self, rep): |
|
145 | 144 | """ Reimplemented to support IPython's improved completion machinery. |
|
146 | 145 | """ |
@@ -223,6 +222,7 b' class IPythonWidget(FrontendWidget):' | |||
|
223 | 222 | """ |
|
224 | 223 | self.log.debug("pyout: %s", msg.get('content', '')) |
|
225 | 224 | if not self._hidden and self._is_from_this_session(msg): |
|
225 | self.flush_clearoutput() | |
|
226 | 226 | content = msg['content'] |
|
227 | 227 | prompt_number = content.get('execution_count', 0) |
|
228 | 228 | data = content['data'] |
@@ -250,6 +250,7 b' class IPythonWidget(FrontendWidget):' | |||
|
250 | 250 | # eventually will as this allows all frontends to monitor the display |
|
251 | 251 | # data. But we need to figure out how to handle this in the GUI. |
|
252 | 252 | if not self._hidden and self._is_from_this_session(msg): |
|
253 | self.flush_clearoutput() | |
|
253 | 254 | source = msg['content']['source'] |
|
254 | 255 | data = msg['content']['data'] |
|
255 | 256 | metadata = msg['content']['metadata'] |
@@ -114,6 +114,7 b' class RichIPythonWidget(IPythonWidget):' | |||
|
114 | 114 | """ Overridden to handle rich data types, like SVG. |
|
115 | 115 | """ |
|
116 | 116 | if not self._hidden and self._is_from_this_session(msg): |
|
117 | self.flush_clearoutput() | |
|
117 | 118 | content = msg['content'] |
|
118 | 119 | prompt_number = content.get('execution_count', 0) |
|
119 | 120 | data = content['data'] |
@@ -140,6 +141,7 b' class RichIPythonWidget(IPythonWidget):' | |||
|
140 | 141 | """ Overridden to handle rich data types, like SVG. |
|
141 | 142 | """ |
|
142 | 143 | if not self._hidden and self._is_from_this_session(msg): |
|
144 | self.flush_clearoutput() | |
|
143 | 145 | source = msg['content']['source'] |
|
144 | 146 | data = msg['content']['data'] |
|
145 | 147 | metadata = msg['content']['metadata'] |
@@ -43,6 +43,7 b' class ZMQTerminalInteractiveShell(TerminalInteractiveShell):' | |||
|
43 | 43 | """A subclass of TerminalInteractiveShell that uses the 0MQ kernel""" |
|
44 | 44 | _executing = False |
|
45 | 45 | _execution_state = Unicode('') |
|
46 | _pending_clearoutput = False | |
|
46 | 47 | kernel_timeout = Float(60, config=True, |
|
47 | 48 | help="""Timeout for giving up on a kernel (in seconds). |
|
48 | 49 | |
@@ -241,13 +242,22 b' class ZMQTerminalInteractiveShell(TerminalInteractiveShell):' | |||
|
241 | 242 | self._execution_state = sub_msg["content"]["execution_state"] |
|
242 | 243 | elif msg_type == 'stream': |
|
243 | 244 | if sub_msg["content"]["name"] == "stdout": |
|
245 | if self._pending_clearoutput: | |
|
246 | print("\r", file=io.stdout, end="") | |
|
247 | self._pending_clearoutput = False | |
|
244 | 248 | print(sub_msg["content"]["data"], file=io.stdout, end="") |
|
245 | 249 | io.stdout.flush() |
|
246 | 250 | elif sub_msg["content"]["name"] == "stderr" : |
|
251 | if self._pending_clearoutput: | |
|
252 | print("\r", file=io.stderr, end="") | |
|
253 | self._pending_clearoutput = False | |
|
247 | 254 | print(sub_msg["content"]["data"], file=io.stderr, end="") |
|
248 | 255 | io.stderr.flush() |
|
249 | 256 | |
|
250 | 257 | elif msg_type == 'pyout': |
|
258 | if self._pending_clearoutput: | |
|
259 | print("\r", file=io.stdout, end="") | |
|
260 | self._pending_clearoutput = False | |
|
251 | 261 | self.execution_count = int(sub_msg["content"]["execution_count"]) |
|
252 | 262 | format_dict = sub_msg["content"]["data"] |
|
253 | 263 | self.handle_rich_data(format_dict) |
@@ -267,6 +277,12 b' class ZMQTerminalInteractiveShell(TerminalInteractiveShell):' | |||
|
267 | 277 | if 'text/plain' in data: |
|
268 | 278 | print(data['text/plain']) |
|
269 | 279 | |
|
280 | elif msg_type == 'clear_output': | |
|
281 | if sub_msg["content"]["wait"]: | |
|
282 | self._pending_clearoutput = True | |
|
283 | else: | |
|
284 | print("\r", file=io.stdout, end="") | |
|
285 | ||
|
270 | 286 | _imagemime = { |
|
271 | 287 | 'image/png': 'png', |
|
272 | 288 | 'image/jpeg': 'jpeg', |
General Comments 0
You need to be logged in to leave comments.
Login now