def _buf_fixture(self): # try to simulate how sys.stdout looks - we send it u'' # but then it's trying to encode to something. buf = BytesIO() wrapper = TextIOWrapper(buf, encoding="ascii", line_buffering=True) wrapper.getvalue = buf.getvalue return wrapper
class OutputCapture: """Capture stdout and stderr by redirecting to inmemory streams :param raw: Expecting raw bytes from stdout and stderr :type raw: bool """ def __init__(self, raw: bool = False): self.raw = raw self._init_stdout(raw) self._init_stderr() self.formatter = logging.Formatter("%(message)s") self._init_list_capture() self._init_stats_capture() def _init_stdout(self, raw: bool): self.stdout = TextIOWrapper(BytesIO()) if raw else StringIO() self.stdout_original = sys.stdout sys.stdout = self.stdout def _init_stderr(self): self.stderr = StringIO() self.stderr_original = sys.stderr sys.stderr = self.stderr def _init_list_capture(self): self.list_handler = logging.StreamHandler(StringIO()) self.list_handler.setFormatter(self.formatter) self.list_handler.setLevel("INFO") self.list_logger = logging.getLogger("borg.output.list") self.list_logger.addHandler(self.list_handler) def _init_stats_capture(self): self.stats_handler = logging.StreamHandler(StringIO()) self.stats_handler.setFormatter(self.formatter) self.stats_handler.setLevel("INFO") self.stats_logger = logging.getLogger("borg.output.stats") self.stats_logger.addHandler(self.stats_handler) # pylint: disable=no-member def getvalues(self) -> Union[str, bytes]: """Get the captured values from the redirected stdout and stderr :return: Redirected values from stdout and stderr :rtype: Union[str, bytes] """ stdout_value = stderr_value = None if self.raw: stdout_value = self.stdout.buffer.getvalue() else: stdout_value = self.stdout.getvalue().strip() stderr_value = self.stderr.getvalue().strip() list_value = self.list_handler.stream.getvalue() stats_value = self.stats_handler.stream.getvalue() return { "stdout": stdout_value, "stderr": stderr_value, "list": list_value, "stats": stats_value, } def close(self): """Close the underlying IO streams and reset stdout and stderr""" try: self.stdout.close() self.stderr.close() self.list_handler.stream.close() self.list_logger.removeHandler(self.list_handler) self.stats_handler.stream.close() self.stats_logger.removeHandler(self.stats_handler) finally: sys.stdout = self.stdout_original sys.stderr = self.stderr_original
def _buf_fixture(self): # try to simulate how sys.stdout looks - we send it u'' # but then it's trying to encode to something. buf = BytesIO() wrapper = TextIOWrapper(buf, encoding='ascii', line_buffering=True) wrapper.getvalue = buf.getvalue return wrapper