|
|
|
"""IO capturing utilities.""" |
|
|
|
|
|
|
|
|
|
|
|
import sys |
|
from io import StringIO |
|
|
|
|
|
|
|
|
|
|
|
|
|
class RichOutput(object): |
|
def __init__(self, data=None, metadata=None, transient=None, update=False): |
|
self.data = data or {} |
|
self.metadata = metadata or {} |
|
self.transient = transient or {} |
|
self.update = update |
|
|
|
def display(self): |
|
from IPython.display import publish_display_data |
|
publish_display_data(data=self.data, metadata=self.metadata, |
|
transient=self.transient, update=self.update) |
|
|
|
def _repr_mime_(self, mime): |
|
if mime not in self.data: |
|
return |
|
data = self.data[mime] |
|
if mime in self.metadata: |
|
return data, self.metadata[mime] |
|
else: |
|
return data |
|
|
|
def _repr_mimebundle_(self, include=None, exclude=None): |
|
return self.data, self.metadata |
|
|
|
def _repr_html_(self): |
|
return self._repr_mime_("text/html") |
|
|
|
def _repr_latex_(self): |
|
return self._repr_mime_("text/latex") |
|
|
|
def _repr_json_(self): |
|
return self._repr_mime_("application/json") |
|
|
|
def _repr_javascript_(self): |
|
return self._repr_mime_("application/javascript") |
|
|
|
def _repr_png_(self): |
|
return self._repr_mime_("image/png") |
|
|
|
def _repr_jpeg_(self): |
|
return self._repr_mime_("image/jpeg") |
|
|
|
def _repr_svg_(self): |
|
return self._repr_mime_("image/svg+xml") |
|
|
|
|
|
class CapturedIO(object): |
|
"""Simple object for containing captured stdout/err and rich display StringIO objects |
|
|
|
Each instance `c` has three attributes: |
|
|
|
- ``c.stdout`` : standard output as a string |
|
- ``c.stderr`` : standard error as a string |
|
- ``c.outputs``: a list of rich display outputs |
|
|
|
Additionally, there's a ``c.show()`` method which will print all of the |
|
above in the same order, and can be invoked simply via ``c()``. |
|
""" |
|
|
|
def __init__(self, stdout, stderr, outputs=None): |
|
self._stdout = stdout |
|
self._stderr = stderr |
|
if outputs is None: |
|
outputs = [] |
|
self._outputs = outputs |
|
|
|
def __str__(self): |
|
return self.stdout |
|
|
|
@property |
|
def stdout(self): |
|
"Captured standard output" |
|
if not self._stdout: |
|
return '' |
|
return self._stdout.getvalue() |
|
|
|
@property |
|
def stderr(self): |
|
"Captured standard error" |
|
if not self._stderr: |
|
return '' |
|
return self._stderr.getvalue() |
|
|
|
@property |
|
def outputs(self): |
|
"""A list of the captured rich display outputs, if any. |
|
|
|
If you have a CapturedIO object ``c``, these can be displayed in IPython |
|
using:: |
|
|
|
from IPython.display import display |
|
for o in c.outputs: |
|
display(o) |
|
""" |
|
return [ RichOutput(**kargs) for kargs in self._outputs ] |
|
|
|
def show(self): |
|
"""write my output to sys.stdout/err as appropriate""" |
|
sys.stdout.write(self.stdout) |
|
sys.stderr.write(self.stderr) |
|
sys.stdout.flush() |
|
sys.stderr.flush() |
|
for kargs in self._outputs: |
|
RichOutput(**kargs).display() |
|
|
|
__call__ = show |
|
|
|
|
|
class capture_output(object): |
|
"""context manager for capturing stdout/err""" |
|
stdout = True |
|
stderr = True |
|
display = True |
|
|
|
def __init__(self, stdout=True, stderr=True, display=True): |
|
self.stdout = stdout |
|
self.stderr = stderr |
|
self.display = display |
|
self.shell = None |
|
|
|
def __enter__(self): |
|
from IPython.core.getipython import get_ipython |
|
from IPython.core.displaypub import CapturingDisplayPublisher |
|
from IPython.core.displayhook import CapturingDisplayHook |
|
|
|
self.sys_stdout = sys.stdout |
|
self.sys_stderr = sys.stderr |
|
|
|
if self.display: |
|
self.shell = get_ipython() |
|
if self.shell is None: |
|
self.save_display_pub = None |
|
self.display = False |
|
|
|
stdout = stderr = outputs = None |
|
if self.stdout: |
|
stdout = sys.stdout = StringIO() |
|
if self.stderr: |
|
stderr = sys.stderr = StringIO() |
|
if self.display: |
|
self.save_display_pub = self.shell.display_pub |
|
self.shell.display_pub = CapturingDisplayPublisher() |
|
outputs = self.shell.display_pub.outputs |
|
self.save_display_hook = sys.displayhook |
|
sys.displayhook = CapturingDisplayHook(shell=self.shell, |
|
outputs=outputs) |
|
|
|
return CapturedIO(stdout, stderr, outputs) |
|
|
|
def __exit__(self, exc_type, exc_value, traceback): |
|
sys.stdout = self.sys_stdout |
|
sys.stderr = self.sys_stderr |
|
if self.display and self.shell: |
|
self.shell.display_pub = self.save_display_pub |
|
sys.displayhook = self.save_display_hook |
|
|