test_widget_output.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. import sys
  2. from unittest import TestCase
  3. from contextlib import contextmanager
  4. from IPython.display import Markdown, Image
  5. from ipywidgets import widget_output
  6. class TestOutputWidget(TestCase):
  7. @contextmanager
  8. def _mocked_ipython(self, get_ipython, clear_output):
  9. """ Context manager that monkeypatches get_ipython and clear_output """
  10. original_clear_output = widget_output.clear_output
  11. original_get_ipython = widget_output.get_ipython
  12. widget_output.get_ipython = get_ipython
  13. widget_output.clear_output = clear_output
  14. try:
  15. yield
  16. finally:
  17. widget_output.clear_output = original_clear_output
  18. widget_output.get_ipython = original_get_ipython
  19. def _mock_get_ipython(self, msg_id):
  20. """ Returns a mock IPython application with a mocked kernel """
  21. kernel = type(
  22. 'mock_kernel',
  23. (object, ),
  24. {'_parent_header': {'header': {'msg_id': msg_id}}}
  25. )
  26. # Specifically override this so the traceback
  27. # is still printed to screen
  28. def showtraceback(self_, exc_tuple, *args, **kwargs):
  29. etype, evalue, tb = exc_tuple
  30. raise etype(evalue)
  31. ipython = type(
  32. 'mock_ipython',
  33. (object, ),
  34. {'kernel': kernel, 'showtraceback': showtraceback}
  35. )
  36. return ipython
  37. def _mock_clear_output(self):
  38. """ Mock function that records calls to it """
  39. calls = []
  40. def clear_output(*args, **kwargs):
  41. calls.append((args, kwargs))
  42. clear_output.calls = calls
  43. return clear_output
  44. def test_set_msg_id_when_capturing(self):
  45. msg_id = 'msg-id'
  46. get_ipython = self._mock_get_ipython(msg_id)
  47. clear_output = self._mock_clear_output()
  48. with self._mocked_ipython(get_ipython, clear_output):
  49. widget = widget_output.Output()
  50. assert widget.msg_id == ''
  51. with widget:
  52. assert widget.msg_id == msg_id
  53. assert widget.msg_id == ''
  54. def test_clear_output(self):
  55. msg_id = 'msg-id'
  56. get_ipython = self._mock_get_ipython(msg_id)
  57. clear_output = self._mock_clear_output()
  58. with self._mocked_ipython(get_ipython, clear_output):
  59. widget = widget_output.Output()
  60. widget.clear_output(wait=True)
  61. assert len(clear_output.calls) == 1
  62. assert clear_output.calls[0] == ((), {'wait': True})
  63. def test_capture_decorator(self):
  64. msg_id = 'msg-id'
  65. get_ipython = self._mock_get_ipython(msg_id)
  66. clear_output = self._mock_clear_output()
  67. expected_argument = 'arg'
  68. expected_keyword_argument = True
  69. captee_calls = []
  70. with self._mocked_ipython(get_ipython, clear_output):
  71. widget = widget_output.Output()
  72. assert widget.msg_id == ''
  73. @widget.capture()
  74. def captee(*args, **kwargs):
  75. # Check that we are capturing output
  76. assert widget.msg_id == msg_id
  77. # Check that arguments are passed correctly
  78. captee_calls.append((args, kwargs))
  79. captee(
  80. expected_argument, keyword_argument=expected_keyword_argument)
  81. assert widget.msg_id == ''
  82. captee()
  83. assert len(captee_calls) == 2
  84. assert captee_calls[0] == (
  85. (expected_argument, ),
  86. {'keyword_argument': expected_keyword_argument}
  87. )
  88. assert captee_calls[1] == ((), {})
  89. def test_capture_decorator_clear_output(self):
  90. msg_id = 'msg-id'
  91. get_ipython = self._mock_get_ipython(msg_id)
  92. clear_output = self._mock_clear_output()
  93. with self._mocked_ipython(get_ipython, clear_output):
  94. widget = widget_output.Output()
  95. @widget.capture(clear_output=True, wait=True)
  96. def captee(*args, **kwargs):
  97. # Check that we are capturing output
  98. assert widget.msg_id == msg_id
  99. captee()
  100. captee()
  101. assert len(clear_output.calls) == 2
  102. assert clear_output.calls[0] == clear_output.calls[1] == \
  103. ((), {'wait': True})
  104. def test_capture_decorator_no_clear_output(self):
  105. msg_id = 'msg-id'
  106. get_ipython = self._mock_get_ipython(msg_id)
  107. clear_output = self._mock_clear_output()
  108. with self._mocked_ipython(get_ipython, clear_output):
  109. widget = widget_output.Output()
  110. @widget.capture(clear_output=False)
  111. def captee(*args, **kwargs):
  112. # Check that we are capturing output
  113. assert widget.msg_id == msg_id
  114. captee()
  115. captee()
  116. assert len(clear_output.calls) == 0
  117. def _make_stream_output(text, name):
  118. return {
  119. 'output_type': 'stream',
  120. 'name': name,
  121. 'text': text
  122. }
  123. def test_append_stdout():
  124. widget = widget_output.Output()
  125. # Try appending a message to stdout.
  126. widget.append_stdout("snakes!")
  127. expected = (_make_stream_output("snakes!", "stdout"),)
  128. assert widget.outputs == expected, repr(widget.outputs)
  129. # Try appending a second message.
  130. widget.append_stdout("more snakes!")
  131. expected += (_make_stream_output("more snakes!", "stdout"),)
  132. assert widget.outputs == expected, repr(widget.outputs)
  133. def test_append_stderr():
  134. widget = widget_output.Output()
  135. # Try appending a message to stderr.
  136. widget.append_stderr("snakes!")
  137. expected = (_make_stream_output("snakes!", "stderr"),)
  138. assert widget.outputs == expected, repr(widget.outputs)
  139. # Try appending a second message.
  140. widget.append_stderr("more snakes!")
  141. expected += (_make_stream_output("more snakes!", "stderr"),)
  142. assert widget.outputs == expected, repr(widget.outputs)
  143. def test_append_display_data():
  144. widget = widget_output.Output()
  145. # Try appending a Markdown object.
  146. widget.append_display_data(Markdown("# snakes!"))
  147. expected = (
  148. {
  149. 'output_type': 'display_data',
  150. 'data': {
  151. 'text/plain': '<IPython.core.display.Markdown object>',
  152. 'text/markdown': '# snakes!'
  153. },
  154. 'metadata': {}
  155. },
  156. )
  157. assert widget.outputs == expected, repr(widget.outputs)
  158. # Now try appending an Image.
  159. image_data = b"foobar"
  160. image_data_b64 = image_data if sys.version_info[0] < 3 else 'Zm9vYmFy\n'
  161. widget.append_display_data(Image(image_data, width=123, height=456))
  162. expected += (
  163. {
  164. 'output_type': 'display_data',
  165. 'data': {
  166. 'image/png': image_data_b64,
  167. 'text/plain': '<IPython.core.display.Image object>'
  168. },
  169. 'metadata': {
  170. 'image/png': {
  171. 'width': 123,
  172. 'height': 456
  173. }
  174. }
  175. },
  176. )
  177. assert widget.outputs == expected, repr(widget.outputs)