Source code for schrodinger.test.ioredirect

import io
import os
import sys
import tempfile

import schrodinger.utils.log as log


[docs]def replace_output_logger_stream(stream): """ Replace the stream used by output loggers. """ handler = log.get_output_logger_handler() handler.flush() handler.stream = stream
[docs]class IORedirect: "Use to redirect stderr & stdout."
[docs] def __init__(self, stdout, stderr): self._stdout = stdout self._stderr = stderr
def __enter__(self): self.old_stdout, self.old_stderr = sys.stdout, sys.stderr sys.stdout.flush() sys.stderr.flush() sys.stdout, sys.stderr = self._stdout, self._stderr replace_output_logger_stream(self._stdout) def __exit__(self, exc_type, exc_value, traceback): self._stderr.flush(), self._stdout.flush() sys.stdout = self.old_stdout sys.stderr = self.old_stderr replace_output_logger_stream(self.old_stdout)
[docs]class IOCapture(IORedirect): "Use to redirect stderr & stdout to a StringIO object."
[docs] def __init__(self): self.string = io.StringIO() super().__init__(self.string, self.string)
def __enter__(self): super().__enter__() return self.string
[docs]class IOSilence: ''' A context manager for doing a "deep suppression" of stdout and stderr, which will point the file descriptors to devnull. Useful for cases where C/Fortran code does not use mmerr and there is an expected error message. '''
[docs] def __init__(self): # Open a pair of null files self.null_fds = [os.open(os.devnull, os.O_RDWR) for x in range(2)] # Save the actual stdout (1) and stderr (2) file descriptors. self.save_fds = (os.dup(1), os.dup(2))
def __enter__(self): # Assign the null pointers to stdout and stderr. os.dup2(self.null_fds[0], 1) os.dup2(self.null_fds[1], 2) def __exit__(self, *_): # Re-assign the real stdout/stderr back to (1) and (2) os.dup2(self.save_fds[0], 1) os.dup2(self.save_fds[1], 2) # Close the null files os.close(self.null_fds[0]) os.close(self.null_fds[1]) os.close(self.save_fds[0]) os.close(self.save_fds[1])
[docs]class FullIORedirect(IOSilence): """ Context manager returns an IOString with all output from stderr/stdout. Because of output from c / python, this output may not be in the correct order. This is indeed to be used to verify certain messages from errors, in tests only. """
[docs] def __init__(self): self.tempfile = tempfile.NamedTemporaryFile(delete=False) self.save_fds = (os.dup(1), os.dup(2)) self._stdout = sys.stdout self._stderr = sys.stderr self.string = io.StringIO()
def __enter__(self): # Assign the null pointers to stdout and stderr. sys.stdout.flush() sys.stderr.flush() os.dup2(self.tempfile.fileno(), 1) os.dup2(self.tempfile.fileno(), 2) sys.stdout = self.string sys.stderr = self.string return self.string def __exit__(self, *_): # Re-assign the real stdout/stderr back to (1) and (2) os.dup2(self.save_fds[0], 1) os.dup2(self.save_fds[1], 2) self.tempfile.close() sys.stdout = self._stdout sys.stderr = self._stderr with open(self.tempfile.name) as fh: self.string.writelines(fh.readlines()) os.remove(self.tempfile.name) os.close(self.save_fds[0]) os.close(self.save_fds[1])