subprocess-multitee
Multiplex subprocess stdout/stderr to multiple destinations simultaneously.
from subprocess_multitee import Popen, tee, PIPE
import sys
# Capture output AND print to terminal in real-time
proc = Popen(['make'], stdout=tee(PIPE, sys.stdout))
output = proc.stdout.read()
proc.wait()
Installation
pip install subprocess-multitee
Why?
Standard subprocess forces a choice: either capture output (stdout=PIPE) or display it (stdout=sys.stdout). This library lets you do both—plus log to files, discard with DEVNULL, or any combination.
The tee() function creates a pipe that spawns a background thread reading one byte at a time and writing to all destinations, ensuring real-time output even for line-buffered programs.
Usage
Basic: Capture + Display
from subprocess_multitee import Popen, tee, PIPE
import sys
proc = Popen(['python', 'train.py'], stdout=tee(PIPE, sys.stdout))
output = proc.stdout.read() # Full output captured
proc.wait() # Terminal saw it in real-time
Log to File + Display + Capture
with open('build.log', 'wb') as log:
proc = Popen(['make', '-j4'],
stdout=tee(PIPE, sys.stdout, log),
stderr=tee(PIPE, sys.stderr, log))
stdout, stderr = proc.communicate()
With run() Helper
from subprocess_multitee import run, tee, PIPE
import sys
result = run(['pytest', '-v'], stdout=tee(PIPE, sys.stdout), check=True)
print(f"Captured {len(result.stdout)} bytes")
Discard + Capture (silent but recorded)
from subprocess_multitee import Popen, tee, PIPE, DEVNULL
proc = Popen(['noisy-command'], stdout=tee(DEVNULL, PIPE))
output = proc.stdout.read() # Captured, but nothing printed
With stdlib Popen (manual cleanup)
import subprocess
from subprocess_multitee import tee, PIPE
t = tee(PIPE, open('log.txt', 'wb'))
proc = subprocess.Popen(['cmd'], stdout=t)
proc.wait()
t.close() # Required with stdlib Popen
output = t.pipes[0].read()
API
tee(*destinations) -> _Tee
Creates a tee object for use as stdout or stderr in Popen.
Destinations can be any combination of:
PIPE— creates a readable pipe (accessible via.pipeslist orPopen.stdout)DEVNULL— discard output (no-op, skipped efficiently)- File objects — anything with
.write()(binary mode recommended) - File descriptors — raw
intfds - Text-mode files — automatically uses
.bufferif available
Not supported: STDOUT (use stderr=tee(...) separately)
Popen
Drop-in subclass of subprocess.Popen with tee integration:
- Automatically closes parent's write fd after fork
- Exposes first
PIPEdestination as.stdout/.stderr - Joins tee threads on context manager exit
run(), call(), check_call(), check_output()
Drop-in replacements using the enhanced Popen.
How It Works
tee()creates anos.pipe()- Returns a object with
fileno()pointing to the write end - Spawns a daemon thread that reads 1 byte at a time and writes to all destinations
Popenpasses the fd to the subprocess, then closes the parent's copy- When subprocess exits, the pipe closes, thread sees EOF and exits
Alternatives
-
subprocess-tee — Drop-in replacement for
subprocess.runthat prints output in real-time while capturing. Simple API (tee=Falseto disable), but impliesuniversal_newlines=True(text mode only) and doesn't support multiple arbitrary destinations. -
tee-subprocess — Also replaces
subprocess.runwith tee support, but adds async/await support viaasyncio. Automatically detects async context. Supports redirecting tee output to file objects. Better static typing. More complex internals.
subprocess-multitee takes a different approach: a composable tee(*destinations) primitive that works with any number of destinations (multiple files, PIPE, DEVNULL, etc.) and a minimal Popen subclass. This gives more flexibility at the cost of slightly more verbose usage.
License
MIT
Metadata
Release files for subprocess-multitee 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| subprocess_multitee-0.2.1.tar.gz | 31.1 kB | Without provenance | Details for subprocess_multitee-0.2.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| subprocess_multitee-0.2.1-py3-none-any.whl | Python 3 | none | any | Details for subprocess_multitee-0.2.1-py3-none-any.whl |
Total release size: 39.3 kB
Release files / subprocess_multitee-0.2.1.tar.gz
| Download URL | subprocess_multitee-0.2.1.tar.gz |
|---|---|
| Size | 31.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
69343c2f3db64b207db590eec0f7184048f8ebc342ab9b385f84fcd396e906e1
|
|
BLAKE2b-256 checksum How to use checksums |
692bf12e452b78931eaa6e1595bacf84836d7731689c18e0bec8fd7bd10834b3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.9.17 {"installer":{"name":"uv","version":"0.9.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / subprocess_multitee-0.2.1-py3-none-any.whl
| Download URL | subprocess_multitee-0.2.1-py3-none-any.whl |
|---|---|
| Size | 8.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2e4b309a24dcc507d52a91cffc16205c046cb62849ee7bf939aa13af82647f6f
|
|
BLAKE2b-256 checksum How to use checksums |
077d15540139bc4c9bc78883412a1fd175dcd3c6517f9ecdd5ac9d4db01896b4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.9.17 {"installer":{"name":"uv","version":"0.9.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for subprocess-multitee 0.2.1
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
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.