CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-wurlitzer

Capture C-level stdout/stderr pipes in Python via os.dup2

Overview
Eval results
Files

permanent-redirection.mddocs/

Permanent Redirection

Enable and disable permanent C-level output forwarding without context managers, useful for global configuration and long-running applications.

Capabilities

Enable Permanent Redirection

Start permanent forwarding of all C-level output to Python sys streams.

def sys_pipes_forever(encoding='utf-8', bufsize=None):
    """Redirect all C output to sys.stdout/err permanently.
    
    Args:
        encoding: Text encoding for output (default: 'utf-8')
        bufsize: Pipe buffer size in bytes (default: auto-detected)
        
    Note:
        This is not a context manager; it turns on C-forwarding permanently
        until stop_sys_pipes() is called.
    """

Example usage:

from wurlitzer import sys_pipes_forever

# Enable permanent redirection at application startup
sys_pipes_forever()

# All subsequent C-level output is forwarded
c_library_function_1()
other_c_operations()
c_library_function_2()

# Output forwarding continues until explicitly stopped

Disable Permanent Redirection

Stop permanent redirection and restore original C-level stream behavior.

def stop_sys_pipes():
    """Stop permanent redirection started by sys_pipes_forever"""

Example usage:

from wurlitzer import sys_pipes_forever, stop_sys_pipes

# Start permanent forwarding
sys_pipes_forever()

# ... application runs with C output forwarded ...

# Stop forwarding at application shutdown or when no longer needed
stop_sys_pipes()

# C output now goes back to original destinations

Thread-Safe Global State

The permanent redirection system uses thread-safe locks to manage global state.

from wurlitzer import sys_pipes_forever, stop_sys_pipes
import threading

def worker_function():
    # Multiple threads can safely call these functions
    sys_pipes_forever()  # Only activates once globally
    
    c_work_function()
    
    stop_sys_pipes()  # Only deactivates when last thread calls it

# Safe in multi-threaded environments
threads = [threading.Thread(target=worker_function) for _ in range(3)]
for t in threads:
    t.start()
for t in threads:
    t.join()

Usage Patterns

Application Initialization

Configure C-level output forwarding during application startup:

from wurlitzer import sys_pipes_forever
import logging

def initialize_app():
    # Setup logging
    logging.basicConfig(level=logging.INFO)
    
    # Enable C output forwarding for entire application
    sys_pipes_forever()
    
    print("Application initialized with C output forwarding")

def main():
    initialize_app()
    
    # All C library calls throughout the application
    # will have their output forwarded to sys.stdout/stderr
    run_application_logic()

Service/Daemon Applications

Long-running services that need consistent C output handling:

import signal
import sys
from wurlitzer import sys_pipes_forever, stop_sys_pipes

class ServiceApplication:
    def __init__(self):
        # Enable C output forwarding for service lifetime
        sys_pipes_forever()
        
    def start(self):
        # Setup signal handlers for clean shutdown
        signal.signal(signal.SIGTERM, self._shutdown)
        signal.signal(signal.SIGINT, self._shutdown)
        
        # Service main loop
        while self.running:
            self.process_requests()
            
    def _shutdown(self, signum, frame):
        print("Shutting down service...")
        stop_sys_pipes()
        self.running = False
        sys.exit(0)
        
    def process_requests(self):
        # C library calls have output forwarded automatically
        c_request_processor.handle_batch()

Testing Setup/Teardown

Configure test environments with global C output forwarding:

import pytest
from wurlitzer import sys_pipes_forever, stop_sys_pipes

@pytest.fixture(scope="session", autouse=True)
def setup_c_output_forwarding():
    """Enable C output forwarding for entire test session"""
    sys_pipes_forever()
    yield
    stop_sys_pipes()

def test_c_function_1():
    # C output automatically forwarded, captured by pytest
    c_function_under_test()

def test_c_function_2():
    # All tests benefit from automatic C output forwarding
    another_c_function()

Library Initialization

Enable forwarding when importing libraries that use C extensions:

# mylib/__init__.py
from wurlitzer import sys_pipes_forever

# Automatically enable C output forwarding when library is imported
sys_pipes_forever()

from .core import main_functions
from .extensions import c_extensions

__all__ = ['main_functions', 'c_extensions']

Conditional Activation

Enable permanent redirection based on environment or configuration:

import os
from wurlitzer import sys_pipes_forever

def configure_output_handling():
    # Enable based on environment variable
    if os.getenv('ENABLE_C_OUTPUT_FORWARDING', '').lower() == 'true':
        sys_pipes_forever()
        print("C output forwarding enabled")
    
    # Or based on configuration file
    if config.get('debug', {}).get('capture_c_output', False):
        sys_pipes_forever()
        print("Debug mode: C output forwarding enabled")

# Call during application setup
configure_output_handling()

State Management

Idempotent Operations

Multiple calls to sys_pipes_forever() are safe and idempotent:

from wurlitzer import sys_pipes_forever, stop_sys_pipes

# Multiple calls don't create multiple redirections
sys_pipes_forever()  # Enables forwarding
sys_pipes_forever()  # No additional effect
sys_pipes_forever()  # Still no additional effect

stop_sys_pipes()     # Disables forwarding
stop_sys_pipes()     # Safe to call multiple times

Status Checking

Check if permanent redirection is currently active:

from wurlitzer import sys_pipes_forever, stop_sys_pipes
import wurlitzer

# Check global state (internal variable)
def is_permanent_forwarding_active():
    return wurlitzer._mighty_wurlitzer is not None

# Example usage
if not is_permanent_forwarding_active():
    sys_pipes_forever()

# Later...
if is_permanent_forwarding_active():
    print("C output is being forwarded")
    stop_sys_pipes()

Context Integration

Combine permanent redirection with temporary context managers:

from wurlitzer import sys_pipes_forever, stop_sys_pipes, pipes

# Global forwarding for most operations
sys_pipes_forever()

# Temporary override for specific capture
with pipes() as (out, err):
    # This temporarily overrides the permanent forwarding
    special_c_function()
    
captured_output = out.read()

# Back to permanent forwarding after context manager exits
normal_c_operations()

Install with Tessl CLI

npx tessl i tessl/pypi-wurlitzer

docs

core-implementation.md

index.md

ipython-integration.md

output-capture.md

permanent-redirection.md

system-integration.md

tile.json