{"id":3323,"library":"wurlitzer","title":"Wurlitzer","description":"Wurlitzer is a Python library that captures C-level `stdout` and `stderr` streams, making it possible to integrate output from underlying C code into Python's I/O system. This is particularly useful in environments like Jupyter notebooks or when calling native libraries that print directly to the console. As of April 2026, the current stable version is 3.1.1, and it maintains a steady release cadence, with recent updates focusing on stability and feature enhancements.","status":"active","version":"3.1.1","language":"en","source_language":"en","source_url":"https://github.com/minrk/wurlitzer","tags":["c-level output","stdout","stderr","capture","context-manager","jupyter","ipython","native code"],"install":[{"cmd":"pip install wurlitzer","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Runtime environment","package":"python","optional":false}],"imports":[{"symbol":"pipes","correct":"from wurlitzer import pipes"},{"symbol":"sys_pipes","correct":"from wurlitzer import sys_pipes"},{"note":"Class-based context manager, less commonly used directly than `pipes` or `sys_pipes`.","symbol":"Wurlitzer","correct":"from wurlitzer import Wurlitzer"},{"note":"Used with `pipes` to redirect stderr to stdout.","symbol":"STDOUT","correct":"from wurlitzer import STDOUT"},{"note":"Placeholder for pipe output in `pipes`.","symbol":"PIPE","correct":"from wurlitzer import PIPE"}],"quickstart":{"code":"import ctypes\nimport io\nfrom wurlitzer import pipes, STDOUT\n\n# Simulate a C function that prints to stdout/stderr\nlibc = ctypes.CDLL(None) # Load standard C library\ndef c_printf(msg):\n    libc.printf(b'%s\\n', msg.encode('utf8'))\ndef c_fprintf_stderr(msg):\n    # Find stderr pointer, differs slightly by OS\n    try:\n        c_stderr_p = ctypes.c_void_p.in_dll(libc, 'stderr')\n    except ValueError:\n        c_stderr_p = ctypes.c_void_p.in_dll(libc, '__stderrp')\n    libc.fprintf(c_stderr_p, b'%s\\n', msg.encode('utf8'))\n\n# Example 1: Capture stdout and stderr separately\nout_buf = io.StringIO()\nerr_buf = io.StringIO()\nwith pipes(stdout=out_buf, stderr=err_buf):\n    c_printf('Hello from C stdout!')\n    c_fprintf_stderr('Hello from C stderr!')\n\nprint(f\"Captured STDOUT: '{out_buf.getvalue().strip()}'\")\nprint(f\"Captured STDERR: '{err_buf.getvalue().strip()}'\")\n\n# Example 2: Forward C-level stdout/stderr to Python's sys.stdout/stderr\n# which might already be redirected (e.g., in a Jupyter notebook)\nfrom wurlitzer import sys_pipes\nprint(\"\\n--- Using sys_pipes (output below is from Python's streams) ---\")\nwith sys_pipes():\n    c_printf('C stdout via sys_pipes!')\n    c_fprintf_stderr('C stderr via sys_pipes!')\nprint(\"--- End sys_pipes example ---\")\n","lang":"python","description":"This quickstart demonstrates how to use `wurlitzer.pipes` to capture C-level `stdout` and `stderr` into Python `StringIO` objects, and `wurlitzer.sys_pipes` to forward C-level output directly to Python's `sys.stdout` and `sys.stderr` streams. It uses `ctypes` to simulate C functions printing to the console."},"warnings":[{"fix":"Upgrade to `wurlitzer` version 3.1.0 or newer. If upgrading is not possible, ensure `sys.stdout` and `sys.stderr` are not redirected to each other before entering the `sys_pipes` context, or use `pipes(stdout=None, stderr=sys.stdout)` for specific redirection needs.","message":"When using `sys_pipes` in complex environments (e.g., deeply nested context managers or with prior redirections of `sys.stdout`/`sys.stderr`), older versions of `wurlitzer` (prior to 3.1.0) on macOS could sometimes hang. This was due to specific interactions with file descriptor handling.","severity":"gotcha","affected_versions":"<3.1.0"},{"fix":"For C code that might hold the GIL for extended periods, consider using `pipes` with a file-like object that has a `fileno()` method (e.g., `open('log.txt', 'ab')`) as the `stdout` or `stderr` target, as `wurlitzer` version 3.1 and newer optimizes this for GIL-less capture. This allows the C code to write directly to the file without needing Python's I/O, minimizing GIL contention.","message":"`wurlitzer` operates by redirecting C-level file descriptors. While it uses a background thread to forward output, long-running C code that extensively holds the Python GIL (Global Interpreter Lock) might still cause perceived blocking or delays in output processing, especially if not configured to write to a file-backed pipe.","severity":"gotcha","affected_versions":"All versions"},{"fix":"It is recommended to use `wurlitzer` with Python 3.8 or newer to ensure compatibility with future releases and benefit from ongoing maintenance.","message":"While `wurlitzer` 3.1.1 officially supports Python >=3.5, there has been a GitHub Pull Request to drop support for Python versions older than 3.8. Future major or minor releases may officially drop support for Python 3.5, 3.6, and 3.7.","severity":"deprecated","affected_versions":"Future versions (post 3.1.1)"}],"env_vars":null,"last_verified":"2026-04-11T00:00:00.000Z","next_check":"2026-07-10T00:00:00.000Z"}