1# Copyright (c) Jupyter Development Team. 2# Distributed under the terms of the Modified BSD License. 3 4"""Output class. 5 6Represents a widget that can be used to display output within the widget area. 7""" 8 9import sys 10from functools import wraps 11 12from .domwidget import DOMWidget 13from .trait_types import TypedTuple 14from .widget import register 15from .._version import __jupyter_widgets_output_version__ 16 17from traitlets import Unicode, Dict 18from IPython.core.interactiveshell import InteractiveShell 19from IPython.display import clear_output 20from IPython import get_ipython 21 22 23@register 24class Output(DOMWidget): 25 """Widget used as a context manager to display output. 26 27 This widget can capture and display stdout, stderr, and rich output. To use 28 it, create an instance of it and display it. 29 30 You can then use the widget as a context manager: any output produced while in the 31 context will be captured and displayed in the widget instead of the standard output 32 area. 33 34 You can also use the .capture() method to decorate a function or a method. Any output 35 produced by the function will then go to the output widget. This is useful for 36 debugging widget callbacks, for example. 37 38 Example:: 39 import ipywidgets as widgets 40 from IPython.display import display 41 out = widgets.Output() 42 display(out) 43 44 print('prints to output area') 45 46 with out: 47 print('prints to output widget') 48 49 @out.capture() 50 def func(): 51 print('prints to output widget') 52 """ 53 _view_name = Unicode('OutputView').tag(sync=True) 54 _model_name = Unicode('OutputModel').tag(sync=True) 55 _view_module = Unicode('@jupyter-widgets/output').tag(sync=True) 56 _model_module = Unicode('@jupyter-widgets/output').tag(sync=True) 57 _view_module_version = Unicode(__jupyter_widgets_output_version__).tag(sync=True) 58 _model_module_version = Unicode(__jupyter_widgets_output_version__).tag(sync=True) 59 60 msg_id = Unicode('', help="Parent message id of messages to capture").tag(sync=True) 61 outputs = TypedTuple(trait=Dict(), help="The output messages synced from the frontend.").tag(sync=True) 62 63 __counter = 0 64 65 def clear_output(self, *pargs, **kwargs): 66 """ 67 Clear the content of the output widget. 68 69 Parameters 70 ---------- 71 72 wait: bool 73 If True, wait to clear the output until new output is 74 available to replace it. Default: False 75 """ 76 with self: 77 clear_output(*pargs, **kwargs) 78 79 # PY3: Force passing clear_output and clear_kwargs as kwargs 80 def capture(self, clear_output=False, *clear_args, **clear_kwargs): 81 """ 82 Decorator to capture the stdout and stderr of a function. 83 84 Parameters 85 ---------- 86 87 clear_output: bool 88 If True, clear the content of the output widget at every 89 new function call. Default: False 90 91 wait: bool 92 If True, wait to clear the output until new output is 93 available to replace it. This is only used if clear_output 94 is also True. 95 Default: False 96 """ 97 def capture_decorator(func): 98 @wraps(func) 99 def inner(*args, **kwargs): 100 if clear_output: 101 self.clear_output(*clear_args, **clear_kwargs) 102 with self: 103 return func(*args, **kwargs) 104 return inner 105 return capture_decorator 106 107 def __enter__(self): 108 """Called upon entering output widget context manager.""" 109 self._flush() 110 ip = get_ipython() 111 if ip and hasattr(ip, 'kernel') and hasattr(ip.kernel, '_parent_header'): 112 self.msg_id = ip.kernel._parent_header['header']['msg_id'] 113 self.__counter += 1 114 115 def __exit__(self, etype, evalue, tb): 116 """Called upon exiting output widget context manager.""" 117 ip = get_ipython() 118 if etype is not None: 119 if ip: 120 ip.showtraceback((etype, evalue, tb), tb_offset=0) 121 self._flush() 122 self.__counter -= 1 123 if self.__counter == 0: 124 self.msg_id = '' 125 # suppress exceptions when in IPython, since they are shown above, 126 # otherwise let someone else handle it 127 return True if ip else None 128 129 def _flush(self): 130 """Flush stdout and stderr buffers.""" 131 sys.stdout.flush() 132 sys.stderr.flush() 133 134 def _append_stream_output(self, text, stream_name): 135 """Append a stream output.""" 136 self.outputs += ( 137 {'output_type': 'stream', 'name': stream_name, 'text': text}, 138 ) 139 140 def append_stdout(self, text): 141 """Append text to the stdout stream.""" 142 self._append_stream_output(text, stream_name='stdout') 143 144 def append_stderr(self, text): 145 """Append text to the stderr stream.""" 146 self._append_stream_output(text, stream_name='stderr') 147 148 def append_display_data(self, display_object): 149 """Append a display object as an output. 150 151 Parameters 152 ---------- 153 display_object : IPython.core.display.DisplayObject 154 The object to display (e.g., an instance of 155 `IPython.display.Markdown` or `IPython.display.Image`). 156 """ 157 fmt = InteractiveShell.instance().display_formatter.format 158 data, metadata = fmt(display_object) 159 self.outputs += ( 160 { 161 'output_type': 'display_data', 162 'data': data, 163 'metadata': metadata 164 }, 165 ) 166