In Python, capturing process output with contextlib.redirect_stdout / contextlib.redirect_stderr, or manual redirection of sys.stdout and sys.stderr works only when sys file objects are actually being used by the producer to write to standard output or error. If data streams are referred directly, for instance by an underlying C/C++ library invoked by the interpreter, hence eliding sys file objects, these methods are inadequate.
Fortunately, the os module lays on a number of file descriptor operations that can be availed to capture the actual standard streams. The capture_stream.py gist defines a context manager that is capable of capturing the given IO stream (e.g. sys.stdout or sys.stderr) and populates the returned Captured's data property on exit.
Following snippet exemplifies the usage of capture_stream context manager to capture OpenCV imread errors, not exposed by the Python API:
import cv2
import sys
from pathlib import Path
root = Path(r'/home/user/Pictures/')
for img in root.rglob(r'*.jpg'):
with capture_stream(sys.stderr) as error:
fatal = cv2.imread(img.as_posix()) is None
if error.data:
print(f'{img}: {error.data}')The context manager implementation follows the idea published in "In python, how to capture the stdout from a c++ shared library to a variable" and simply wraps the code available therein, so all credit goes to the original publisher!