widget_output.py 5.5 KB

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