capture.py 4.8 KB

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