69 lines
1.8 KiB
Python
69 lines
1.8 KiB
Python
"""
|
|
@package pmsco.helpers
|
|
helper classes
|
|
|
|
a collection of small and generic code bits mostly collected from the www.
|
|
|
|
"""
|
|
|
|
import contextlib
|
|
import ctypes
|
|
import io
|
|
import os
|
|
import sys
|
|
from typing import BinaryIO
|
|
|
|
|
|
class BraceMessage(object):
|
|
"""
|
|
a string formatting proxy class useful for logging and exceptions.
|
|
|
|
use BraceMessage("{0} {1}", "formatted", "message")
|
|
in place of "{0} {1}".format("formatted", "message").
|
|
the advantage is that the format method is called only if the string is actually used.
|
|
"""
|
|
def __init__(self, fmt, *args, **kwargs):
|
|
self.fmt = fmt
|
|
self.args = args
|
|
self.kwargs = kwargs
|
|
|
|
def __str__(self):
|
|
return self.fmt.format(*self.args, **self.kwargs)
|
|
|
|
|
|
libc = ctypes.CDLL(None)
|
|
c_stdout = ctypes.c_void_p.in_dll(libc, 'stdout')
|
|
|
|
|
|
@contextlib.contextmanager
|
|
def stdout_redirected(dest_file: BinaryIO):
|
|
"""
|
|
A context manager to temporarily redirect stdout to a file.
|
|
|
|
Redirects all standard output from Python and the C library to the specified file.
|
|
This can be used, e.g., to capture output from Fortran code.
|
|
|
|
credit: https://eli.thegreenplace.net/2015/redirecting-all-kinds-of-stdout-in-python/
|
|
|
|
@param dest_file: binary file open for writing ('wb' mode).
|
|
This function requires just the fileno function.
|
|
@return: None
|
|
"""
|
|
|
|
original_stdout_fd = sys.stdout.fileno()
|
|
|
|
def _redirect_stdout(to_fd):
|
|
"""Redirect stdout to the given file descriptor."""
|
|
libc.fflush(c_stdout)
|
|
sys.stdout.close()
|
|
os.dup2(to_fd, original_stdout_fd)
|
|
sys.stdout = io.TextIOWrapper(os.fdopen(original_stdout_fd, 'wb'))
|
|
|
|
saved_stdout_fd = os.dup(original_stdout_fd)
|
|
try:
|
|
_redirect_stdout(dest_file.fileno())
|
|
yield
|
|
_redirect_stdout(saved_stdout_fd)
|
|
finally:
|
|
os.close(saved_stdout_fd)
|