capture.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. # encoding: utf-8
  2. """IO capturing utilities."""
  3. # Copyright (c) IPython Development Team.
  4. # Distributed under the terms of the Modified BSD License.
  5. from __future__ import print_function, absolute_import
  6. import sys
  7. from IPython.utils.py3compat import PY3
  8. if PY3:
  9. from io import StringIO
  10. else:
  11. from StringIO import StringIO
  12. #-----------------------------------------------------------------------------
  13. # Classes and functions
  14. #-----------------------------------------------------------------------------
  15. class RichOutput(object):
  16. def __init__(self, data=None, metadata=None, transient=None, update=False):
  17. self.data = data or {}
  18. self.metadata = metadata or {}
  19. self.transient = transient or {}
  20. self.update = update
  21. def display(self):
  22. from IPython.display import publish_display_data
  23. publish_display_data(data=self.data, metadata=self.metadata,
  24. transient=self.transient, update=self.update)
  25. def _repr_mime_(self, mime):
  26. if mime not in self.data:
  27. return
  28. data = self.data[mime]
  29. if mime in self.metadata:
  30. return data, self.metadata[mime]
  31. else:
  32. return data
  33. def _repr_html_(self):
  34. return self._repr_mime_("text/html")
  35. def _repr_latex_(self):
  36. return self._repr_mime_("text/latex")
  37. def _repr_json_(self):
  38. return self._repr_mime_("application/json")
  39. def _repr_javascript_(self):
  40. return self._repr_mime_("application/javascript")
  41. def _repr_png_(self):
  42. return self._repr_mime_("image/png")
  43. def _repr_jpeg_(self):
  44. return self._repr_mime_("image/jpeg")
  45. def _repr_svg_(self):
  46. return self._repr_mime_("image/svg+xml")
  47. class CapturedIO(object):
  48. """Simple object for containing captured stdout/err and rich display StringIO objects
  49. Each instance `c` has three attributes:
  50. - ``c.stdout`` : standard output as a string
  51. - ``c.stderr`` : standard error as a string
  52. - ``c.outputs``: a list of rich display outputs
  53. Additionally, there's a ``c.show()`` method which will print all of the
  54. above in the same order, and can be invoked simply via ``c()``.
  55. """
  56. def __init__(self, stdout, stderr, outputs=None):
  57. self._stdout = stdout
  58. self._stderr = stderr
  59. if outputs is None:
  60. outputs = []
  61. self._outputs = outputs
  62. def __str__(self):
  63. return self.stdout
  64. @property
  65. def stdout(self):
  66. "Captured standard output"
  67. if not self._stdout:
  68. return ''
  69. return self._stdout.getvalue()
  70. @property
  71. def stderr(self):
  72. "Captured standard error"
  73. if not self._stderr:
  74. return ''
  75. return self._stderr.getvalue()
  76. @property
  77. def outputs(self):
  78. """A list of the captured rich display outputs, if any.
  79. If you have a CapturedIO object ``c``, these can be displayed in IPython
  80. using::
  81. from IPython.display import display
  82. for o in c.outputs:
  83. display(o)
  84. """
  85. return [ RichOutput(**kargs) for kargs in self._outputs ]
  86. def show(self):
  87. """write my output to sys.stdout/err as appropriate"""
  88. sys.stdout.write(self.stdout)
  89. sys.stderr.write(self.stderr)
  90. sys.stdout.flush()
  91. sys.stderr.flush()
  92. for kargs in self._outputs:
  93. RichOutput(**kargs).display()
  94. __call__ = show
  95. class capture_output(object):
  96. """context manager for capturing stdout/err"""
  97. stdout = True
  98. stderr = True
  99. display = True
  100. def __init__(self, stdout=True, stderr=True, display=True):
  101. self.stdout = stdout
  102. self.stderr = stderr
  103. self.display = display
  104. self.shell = None
  105. def __enter__(self):
  106. from IPython.core.getipython import get_ipython
  107. from IPython.core.displaypub import CapturingDisplayPublisher
  108. from IPython.core.displayhook import CapturingDisplayHook
  109. self.sys_stdout = sys.stdout
  110. self.sys_stderr = sys.stderr
  111. if self.display:
  112. self.shell = get_ipython()
  113. if self.shell is None:
  114. self.save_display_pub = None
  115. self.display = False
  116. stdout = stderr = outputs = None
  117. if self.stdout:
  118. stdout = sys.stdout = StringIO()
  119. if self.stderr:
  120. stderr = sys.stderr = StringIO()
  121. if self.display:
  122. self.save_display_pub = self.shell.display_pub
  123. self.shell.display_pub = CapturingDisplayPublisher()
  124. outputs = self.shell.display_pub.outputs
  125. self.save_display_hook = sys.displayhook
  126. sys.displayhook = CapturingDisplayHook(shell=self.shell,
  127. outputs=outputs)
  128. return CapturedIO(stdout, stderr, outputs)
  129. def __exit__(self, exc_type, exc_value, traceback):
  130. sys.stdout = self.sys_stdout
  131. sys.stderr = self.sys_stderr
  132. if self.display and self.shell:
  133. self.shell.display_pub = self.save_display_pub
  134. sys.displayhook = self.save_display_hook