Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

Outwrite

Standard Python logging and one live status line, across threads and processes.

Outwrite connects Python's logging module to Rich and relays worker output to one renderer in the parent process. Use your existing processes and ordinary loggers. No queue management in application code.

This is an early alpha. APIs may change; it is not production-certified. Python 3.11+ is required. Rich is the only runtime dependency.

Installation

The first release is a prerelease:

python -m pip install outwrite==0.1.0a1

Or use python -m pip install --pre outwrite to allow the latest prerelease. These commands become available once the release is published to PyPI.

To install from a local checkout:

python -m pip install .

One process

import logging
from outwrite import setup_output, status

logger = logging.getLogger("my_app")

with setup_output(logger=logger) as output:
    logger.info("Starting")
    status.update("Processing files")
    # Do some work.
    status.clear()
    logger.info("Done")

Worker processes

Pass the connection returned by the parent to each worker. Call the same setup function inside each worker:

import logging
import multiprocessing as mp
import signal
from outwrite import setup_output, status

logger = logging.getLogger("my_app")

def work(output, stop):
    signal.signal(signal.SIGINT, signal.SIG_IGN)
    setup_output(output)
    logger.info("Worker started")
    for index in range(10):
        if stop.is_set():
            break
        status.update(f"Processing file {index + 1}")
        stop.wait(0.1)

if __name__ == "__main__":
    ctx = mp.get_context("spawn")
    stop = ctx.Event()
    with setup_output(logger=logger, mp_context=ctx) as output:
        process = ctx.Process(target=work, args=(output, stop))
        process.start()
        try:
            process.join()
        finally:
            stop.set()
            process.join()

Always join workers and logging threads inside the parent context. On exit, Outwrite drains queued messages, clears the status, and releases its resources. Exit cleanup is also registered as a fallback; it does not stop or join workers for you. Forced process termination can lose messages or damage multiprocessing queues, so prefer a cooperative worker stop in real applications.

See the runnable example.

API

  • setup_output(logger=logger, level=logging.INFO, show_status=True, mp_context=ctx) starts parent output and returns an OutputConnection context handle.
  • setup_output(output) connects a worker. The parent's logger name and status setting are carried by the connection; keyword options are for parent setup.
  • status.update(text) replaces the status line. None or "" clears it.
  • status.clear() clears the line without ending the session.

Status calls are safe from threads. Only one session and one status line are active per process; concurrent writers replace the same line. Status calls before setup or after parent cleanup raise RuntimeError.

The console uses stderr. Status is automatically disabled outside terminals; logs still appear. show_status=False disables only status, and level controls only the Rich console handler. Use integer logging levels, such as logging.DEBUG.

Logging behavior

Only the selected named logger and its propagating descendants are routed. The root logger and unrelated loggers are not configured. Child loggers with their own handlers or propagate=False retain their normal logging behavior.

Existing handlers on the selected logger also receive records in the parent. For example, attach a standard logging.FileHandler before setup to retain file logging. Outwrite does not close your handlers. It adds a Rich console handler, so remove an existing console handler yourself if you do not want duplicate console output. The logger's original handlers, level, and propagation are restored when the parent context exits.

Records pass through standard QueueHandler preparation: exception tracebacks become message text. Extra record attributes must be picklable. Cross-process delivery is asynchronous; use a cooperative worker shutdown and join workers to flush their messages. Ordering between different producers is not guaranteed.

The default queue context is spawn. If using forkserver, pass that same context to setup and use it to create processes. fork is deliberately unsupported because the parent has an active rendering thread. Do not send a connection to an already-running pool; pass it when creating workers or through a pool initializer.

Rendering failures are reported to stderr and raised when the parent context exits. Standard logging handlers retain their usual error-reporting behavior. No arbitrary stdout/stderr capture is performed.

Why not just Rich?

Rich already supplies the columns, colors, links, and live display. Outwrite adds the connection between existing worker processes, standard logging, and one live status line. It is not a new renderer, process pool, or progress-bar framework.

Development

python -m pip install -e .
python examples/multiprocessing_demo.py
python -m pip install build
python -m build

No persisted test suite is included in this initial iteration. Add regression tests before a production release, particularly for process shutdown and terminal cleanup.

The initial wheel was verified on macOS ARM64 with Python 3.13.7 and 3.14.0, including spawn/forkserver workers and real-terminal Ctrl+C cleanup. Python 3.11/3.12 and other operating systems have not yet been runtime-tested.

License

MIT. The initial implementation adapts output coordination developed in Firefly, with its author's permission.

Publishing

Maintainers use PyPI Trusted Publishing; no permanent upload token is stored in GitHub. The GitHub environment pypi requires approval before publication.

  1. Update the version in pyproject.toml, and commit and push the change.
  2. Create a GitHub release with a matching tag, such as v0.1.0a1. Mark alpha/beta/RC versions as prereleases.
  3. Review the build job and approve the pypi environment deployment.
  4. Verify the uploaded version on PyPI and install it in a fresh environment.

The workflow builds and validates the distributions before publishing. Release files cannot be replaced on PyPI; use a new version to correct a release. The initial pending publisher must be configured on PyPI for repository ariel-m-s/outwrite, workflow publish.yml, and environment pypi.

Metadata

Release files for outwrite 0.1.0a1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for outwrite 0.1.0a1
File Size Uploaded Provenance Actions
outwrite-0.1.0a1.tar.gz 10.2 kB With provenance Details for outwrite-0.1.0a1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for outwrite 0.1.0a1
File Interpreter ABI Platform Actions
outwrite-0.1.0a1-py3-none-any.whl Python 3 none any Details for outwrite-0.1.0a1-py3-none-any.whl

Total release size: 18.0 kB

Release files / outwrite-0.1.0a1.tar.gz

Download URL outwrite-0.1.0a1.tar.gz
Size 10.2 kB
Tags Source
SHA-256 checksum
How to use checksums
b407e42795be2657465bd99f28065893c82b11837d31346ad32cdfe9c643ba00
BLAKE2b-256 checksum
How to use checksums
0da4cfc9df09f4446a62975e20bdb6b7689bebc4e79e764833f125a3ee9123a1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.

Transparency log

Release files / outwrite-0.1.0a1-py3-none-any.whl

Download URL outwrite-0.1.0a1-py3-none-any.whl
Size 7.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0c8e7cef02cc97a9341127285a5cc2cedbfe041cd73e111a3a23f3d1359a0a96
BLAKE2b-256 checksum
How to use checksums
bc1b87321c41e5199b8d3cdc5ef269f5dbbc3d044d974293655f8cf20cc4a6cc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.

Transparency log

Security for outwrite 0.1.0a1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for outwrite-0.1.0a1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page