Source code for ytjobs.logging.silencer

from functools import wraps
from contextlib import contextmanager
import sys
import os


[docs] def manage_output(mode="redirect"): """ Decorator factory that either suppresses output or redirects stdout to stderr. Args: mode: ``"suppress"`` for full silence, ``"redirect"`` to send stdout to stderr (keeps job stdout clean for JSON lines). Returns: A decorator, e.g. ``@manage_output(mode="redirect")`` above a function. """ def decorator(func): @wraps(func) def wrapper(*args, **kwargs): if mode == "suppress": with suppress_all_output(): return func(*args, **kwargs) elif mode == "redirect": with redirect_stdout_to_stderr(): return func(*args, **kwargs) else: raise ValueError( f"Invalid mode: {mode}. Must be 'suppress' or 'redirect'" ) return wrapper return decorator
[docs] @contextmanager def redirect_stdout_to_stderr(): """ Context manager that redirects stdout to stderr. This is useful for YTsaurus mappers where you need clean JSON on stdout, but processing functions might print debug messages. Usage: with redirect_stdout_to_stderr(): print("This goes to stderr") # Won't corrupt stdout some_function_that_prints() """ original_stdout = sys.stdout try: sys.stdout = sys.stderr yield finally: sys.stdout = original_stdout
[docs] @contextmanager def suppress_all_output(): """ Context manager that suppresses ALL output: stdout, stderr, and warnings. This is useful when you need complete silence from noisy libraries like OpenCV, Ultralytics YOLO, TensorFlow, Ceres Solver, etc. Usage: with suppress_all_output(): # All prints, warnings, and library output are suppressed model = YOLO('yolov8n.pt') # No output results = model(image) # No progress bars cv2.imread(path) # No warnings """ # Save original Python streams original_stdout = sys.stdout original_stderr = sys.stderr # Save original OS-level file descriptors original_stdout_fd = os.dup(1) # stdout FD original_stderr_fd = os.dup(2) # stderr FD # Open devnull for writing devnull = open(os.devnull, "w") devnull_fd = devnull.fileno() try: # Redirect Python streams to devnull sys.stdout = devnull sys.stderr = devnull # Redirect OS-level file descriptors (this catches C library output like Ceres) os.dup2(devnull_fd, 1) # Redirect stdout FD os.dup2(devnull_fd, 2) # Redirect stderr FD yield finally: # Restore OS-level file descriptors first os.dup2(original_stdout_fd, 1) os.dup2(original_stderr_fd, 2) # Close duplicate FDs os.close(original_stdout_fd) os.close(original_stderr_fd) # Restore Python streams sys.stdout = original_stdout sys.stderr = original_stderr # Close devnull devnull.close()