Compose SafeCmd instances into a Pipeline via the | operator. Pipelines
stream data from each stage's stdout into the next stage's stdin and apply
backpressure using asyncio's pipe drain() semantics.
Running a pipeline returns a PipelineResult that exposes:
- The captured output of the final stage (via
result.stdout). - Per-stage exit metadata (via
result.stages).
import sys
from pathlib import Path
from cuprum import ECHO, Program, ProgramCatalogue, ProjectSettings, scoped, sh
PYTHON = Program(str(Path(sys.executable)))
project = ProjectSettings(
name="pipeline-example",
programs=(ECHO, PYTHON),
documentation_locations=(),
noise_rules=(),
)
catalogue = ProgramCatalogue(projects=(project,))
echo = sh.make(ECHO, catalogue=catalogue)
python = sh.make(PYTHON, catalogue=catalogue)
pipeline = echo("-n", "hello") | python(
"-c",
"import sys; sys.stdout.write(sys.stdin.read().upper())",
)
with scoped(allowlist=catalogue.allowlist):
result = pipeline.run_sync()
print(result.stdout) # "HELLO"
print([stage.exit_code for stage in result.stages]) # per-stage exit codes
Notes:
- Only the final stage's stdout is captured; intermediate stage stdout is
streamed and represented as
Noneinresult.stages. echo=Trueechoes the final stage stdout and all stage stderr streams to their configured sinks.- Pipelines fail fast: when a stage exits non-zero, Cuprum terminates the
remaining stages. The failing stage is available via
result.failure/result.failure_index.