166 lines
5.5 KiB
Python
166 lines
5.5 KiB
Python
|
# Copyright (c) Jupyter Development Team.
|
||
|
# Distributed under the terms of the Modified BSD License.
|
||
|
|
||
|
"""Output class.
|
||
|
|
||
|
Represents a widget that can be used to display output within the widget area.
|
||
|
"""
|
||
|
|
||
|
import sys
|
||
|
from functools import wraps
|
||
|
|
||
|
from .domwidget import DOMWidget
|
||
|
from .trait_types import TypedTuple
|
||
|
from .widget import register
|
||
|
from .._version import __jupyter_widgets_output_version__
|
||
|
|
||
|
from traitlets import Unicode, Dict
|
||
|
from IPython.core.interactiveshell import InteractiveShell
|
||
|
from IPython.display import clear_output
|
||
|
from IPython import get_ipython
|
||
|
|
||
|
|
||
|
@register
|
||
|
class Output(DOMWidget):
|
||
|
"""Widget used as a context manager to display output.
|
||
|
|
||
|
This widget can capture and display stdout, stderr, and rich output. To use
|
||
|
it, create an instance of it and display it.
|
||
|
|
||
|
You can then use the widget as a context manager: any output produced while in the
|
||
|
context will be captured and displayed in the widget instead of the standard output
|
||
|
area.
|
||
|
|
||
|
You can also use the .capture() method to decorate a function or a method. Any output
|
||
|
produced by the function will then go to the output widget. This is useful for
|
||
|
debugging widget callbacks, for example.
|
||
|
|
||
|
Example::
|
||
|
import ipywidgets as widgets
|
||
|
from IPython.display import display
|
||
|
out = widgets.Output()
|
||
|
display(out)
|
||
|
|
||
|
print('prints to output area')
|
||
|
|
||
|
with out:
|
||
|
print('prints to output widget')
|
||
|
|
||
|
@out.capture()
|
||
|
def func():
|
||
|
print('prints to output widget')
|
||
|
"""
|
||
|
_view_name = Unicode('OutputView').tag(sync=True)
|
||
|
_model_name = Unicode('OutputModel').tag(sync=True)
|
||
|
_view_module = Unicode('@jupyter-widgets/output').tag(sync=True)
|
||
|
_model_module = Unicode('@jupyter-widgets/output').tag(sync=True)
|
||
|
_view_module_version = Unicode(__jupyter_widgets_output_version__).tag(sync=True)
|
||
|
_model_module_version = Unicode(__jupyter_widgets_output_version__).tag(sync=True)
|
||
|
|
||
|
msg_id = Unicode('', help="Parent message id of messages to capture").tag(sync=True)
|
||
|
outputs = TypedTuple(trait=Dict(), help="The output messages synced from the frontend.").tag(sync=True)
|
||
|
|
||
|
__counter = 0
|
||
|
|
||
|
def clear_output(self, *pargs, **kwargs):
|
||
|
"""
|
||
|
Clear the content of the output widget.
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
|
||
|
wait: bool
|
||
|
If True, wait to clear the output until new output is
|
||
|
available to replace it. Default: False
|
||
|
"""
|
||
|
with self:
|
||
|
clear_output(*pargs, **kwargs)
|
||
|
|
||
|
# PY3: Force passing clear_output and clear_kwargs as kwargs
|
||
|
def capture(self, clear_output=False, *clear_args, **clear_kwargs):
|
||
|
"""
|
||
|
Decorator to capture the stdout and stderr of a function.
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
|
||
|
clear_output: bool
|
||
|
If True, clear the content of the output widget at every
|
||
|
new function call. Default: False
|
||
|
|
||
|
wait: bool
|
||
|
If True, wait to clear the output until new output is
|
||
|
available to replace it. This is only used if clear_output
|
||
|
is also True.
|
||
|
Default: False
|
||
|
"""
|
||
|
def capture_decorator(func):
|
||
|
@wraps(func)
|
||
|
def inner(*args, **kwargs):
|
||
|
if clear_output:
|
||
|
self.clear_output(*clear_args, **clear_kwargs)
|
||
|
with self:
|
||
|
return func(*args, **kwargs)
|
||
|
return inner
|
||
|
return capture_decorator
|
||
|
|
||
|
def __enter__(self):
|
||
|
"""Called upon entering output widget context manager."""
|
||
|
self._flush()
|
||
|
ip = get_ipython()
|
||
|
if ip and hasattr(ip, 'kernel') and hasattr(ip.kernel, '_parent_header'):
|
||
|
self.msg_id = ip.kernel._parent_header['header']['msg_id']
|
||
|
self.__counter += 1
|
||
|
|
||
|
def __exit__(self, etype, evalue, tb):
|
||
|
"""Called upon exiting output widget context manager."""
|
||
|
ip = get_ipython()
|
||
|
if etype is not None:
|
||
|
if ip:
|
||
|
ip.showtraceback((etype, evalue, tb), tb_offset=0)
|
||
|
self._flush()
|
||
|
self.__counter -= 1
|
||
|
if self.__counter == 0:
|
||
|
self.msg_id = ''
|
||
|
# suppress exceptions when in IPython, since they are shown above,
|
||
|
# otherwise let someone else handle it
|
||
|
return True if ip else None
|
||
|
|
||
|
def _flush(self):
|
||
|
"""Flush stdout and stderr buffers."""
|
||
|
sys.stdout.flush()
|
||
|
sys.stderr.flush()
|
||
|
|
||
|
def _append_stream_output(self, text, stream_name):
|
||
|
"""Append a stream output."""
|
||
|
self.outputs += (
|
||
|
{'output_type': 'stream', 'name': stream_name, 'text': text},
|
||
|
)
|
||
|
|
||
|
def append_stdout(self, text):
|
||
|
"""Append text to the stdout stream."""
|
||
|
self._append_stream_output(text, stream_name='stdout')
|
||
|
|
||
|
def append_stderr(self, text):
|
||
|
"""Append text to the stderr stream."""
|
||
|
self._append_stream_output(text, stream_name='stderr')
|
||
|
|
||
|
def append_display_data(self, display_object):
|
||
|
"""Append a display object as an output.
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
display_object : IPython.core.display.DisplayObject
|
||
|
The object to display (e.g., an instance of
|
||
|
`IPython.display.Markdown` or `IPython.display.Image`).
|
||
|
"""
|
||
|
fmt = InteractiveShell.instance().display_formatter.format
|
||
|
data, metadata = fmt(display_object)
|
||
|
self.outputs += (
|
||
|
{
|
||
|
'output_type': 'display_data',
|
||
|
'data': data,
|
||
|
'metadata': metadata
|
||
|
},
|
||
|
)
|