Skip to main content

Rust Result/Option types exposed to Python with @do generator short-circuiting

Project description

pyropust

Python versions

Rust-powered, type-safe pipelines for Python.

pyropust bridges the messy, exception-heavy reality of Python with the explicit, composable world of Rust’s Result / Option.

This is not just another Result library.

pyropust is built around three core ideas:

  • Blueprints — typed, declarative data-processing pipelines
  • Rust operators — hot-path operations (e.g. JSON decoding) executed safely and efficiently in Rust
  • Exception boundaries — explicit normalization of Python exceptions into Result

If you have ever thought:

“I want Rust-like error flow, but I live in Python and can’t avoid exceptions”

pyropust is designed for you.

Why pyropust exists

Python already has multiple Result / Option libraries. The problem is not representation — it is integration.

In real Python systems:

  • Most libraries raise exceptions (requests, boto3, sqlalchemy, ...)
  • Data transformation is written as long chains of try/except
  • Type checkers lose track of what can fail and where

pyropust treats exceptions as an external reality and provides a structured boundary where they are captured, typed, and composed.

Why not exceptions?

Exceptions are great for failures that should abort the current operation. They are less suitable for orchestration and pipelines:

  • They hide control flow in call stacks
  • They complicate typed composition across steps
  • They are hard to make explicit at module boundaries

pyropust makes failures values so they can be composed, transformed, and tested like data.

Adoption path

You do not need to switch everything at once. A realistic path is:

  1. Wrap exceptions with @catch
  2. Use Result / Option explicitly in Python code
  3. Use @do for structured propagation
  4. Introduce Blueprint for typed pipelines

Key concepts

1) Result and Option

Rust-style Result[T, E] and Option[T] as first-class values.

from pyropust import Ok, Err, Some, None_

value = Ok(10)
error = Err("boom")

maybe = Some(42)
empty = None_()

Result is explicit about failures. You can return it from functions and branch on is_ok / is_err without exceptions.

from pyropust import Ok, Err, Result

def divide(a: int, b: int) -> Result[float, str]:
    if b == 0:
        return Err("division by zero")
    return Ok(a / b)

res = divide(10, 2)
if res.is_ok():
    value = res.unwrap()
else:
    error = res.unwrap_err()

Keep Option short and explicit: you must unwrap or provide defaults.

from pyropust import Some, None_, Option

def find_user(user_id: int) -> Option[str]:
    return Some("alice") if user_id == 1 else None_()

user = find_user(1)
name = user.unwrap_or("guest")

missing = find_user(2)
name2 = missing.unwrap_or("guest")

Unlike Optional[T] (which is only a type hint), Option[T] is a runtime value that forces explicit handling.

Functional Chaining (map, and_then)

Avoid if checks by chaining operations.

from pyropust import Ok

res = (
    Ok("123")
    .map(int)                # Result[int, E]
    .map(lambda x: x * 2)    # Result[int, E]
    .and_then(lambda x: Ok(f"Value is {x}"))
)
print(res.unwrap())  # "Value is 246"

When to use: map/and_then is best for small, expression-style transforms where each step is a function.

[!TIP] Type Hint for and_then: When using and_then with a callback that may return Err, define the initial Result with an explicit return type annotation. This ensures the error type is correctly inferred.

from pyropust import Ok, Err, Result

def fetch_data() -> Result[int, str]:  # Declare error type here
    return Ok(42)

def validate(x: int) -> Result[int, str]:
    return Err("invalid") if x < 0 else Ok(x)

# Error type flows correctly through the chain
result = fetch_data().and_then(validate)

2) Blueprint: typed pipelines

A Blueprint is a declarative pipeline that describes what happens to data, not how it is wired together.

from pyropust import Blueprint, Op

bp = (
    Blueprint.for_type(str)
    .pipe(Op.json_decode())
    .pipe(Op.get("user"))
    .pipe(Op.get("id"))
)

Characteristics:

  • Typed: Blueprint.for_type(T) gives static analyzers a concrete starting point
  • Composable: pipelines are values, not control flow
  • No runtime type checks: types are for humans and tools, not runtime checks

Blueprints are the primary abstraction of pyropust.

Blueprints are inert definitions. Use run(bp, value) to execute them, typically inside an exception boundary.

Only a core set of basic operators is supported today; see the full list in docs/operations.md.

3) Rust operators (hot paths)

Some operations are performance-critical and error-prone. pyropust implements these as Rust-backed operators:

  • Op.json_decode()
  • (future) Op.base64_decode(), Op.url_parse(), ...

Benefits:

  • Faster execution for hot paths
  • Consistent error semantics
  • No Python-level exceptions leaking through the pipeline

You can always fall back to Python:

bp = bp.pipe(Op.map_py(lambda x: x + 1))

Rust where it matters, Python where it’s convenient.

4) Exception boundaries (@catch)

Python exceptions are unavoidable. pyropust makes them explicit.

from pyropust import Blueprint, Op, catch, run

bp = (
    Blueprint.for_type(str)
    .pipe(Op.json_decode())
    .pipe(Op.get("value"))
)

@catch
def load_value(payload: str):
    return run(bp, payload)

Inside the boundary:

  • Exceptions are captured
  • Normalized into Err
  • Enriched with traceback metadata (py_traceback)

Outside the boundary:

  • No hidden control flow
  • Failures are values

This makes error flow visible, testable, and composable.

5) @do: Rust-like ? for Python

The @do decorator enables linear, Rust-style propagation of Result.

from pyropust import Ok, Result, do

@do
def process(data: str) -> Result[str, object]:
    text = yield Ok(data)
    return Ok(text.upper())

When to use: @do reads like imperative code and is better when you need intermediate variables, early returns, or mixed steps.

This is not syntax sugar over exceptions — it is structured propagation of Result values.

Framework boundaries

You can safely use pyropust in frameworks that expect exceptions by converting Result back into exceptions at the boundary.

from fastapi import FastAPI, HTTPException
from pyropust import Result, catch

app = FastAPI()

@catch(ValueError, KeyError)
def parse_user_input(data: dict) -> dict:
    return {
        "age": int(data["age"]),
        "name": data["name"],
    }

@app.post("/users")
def create_user(data: dict):
    result = parse_user_input(data)

    # Convert Result to exception at the framework boundary
    parsed = result.unwrap_or_raise(
        HTTPException(status_code=400, detail="Invalid input")
    )

    return {"user": parsed}

Installation

pyropust is currently experimental.

pip install pyropust

Supported:

  • Python 3.10+
  • CPython (wheels provided)

Note: Some platforms may require a Rust toolchain to build from source.

Minimal example (30 seconds)

from pyropust import Blueprint, Op, catch, run

bp = (
    Blueprint.for_type(str)
    .pipe(Op.json_decode())
    .pipe(Op.get("value"))
)

@catch
def run_value(payload: str):
    return run(bp, payload)

result = run_value('{"value": 123}')
  • No try/except
  • Failures are explicit
  • The pipeline is reusable and testable

Documentation

Non-goals

pyropust intentionally does not aim to:

  • Replace Python exceptions everywhere
  • Be a general-purpose FP toolkit
  • Hide Python’s dynamic nature

It is a boundary and pipeline tool, not a new language.

Roadmap

  • More Rust-backed operators
  • Benchmark suite and published numbers
  • Better IDE / type-checker ergonomics
  • Stabilization of public APIs

Stability

  • APIs may change before 1.0
  • Semantic versioning will start at 1.0
  • Breaking changes will be documented

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyropust-0.1.0.tar.gz (67.9 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

pyropust-0.1.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (494.5 kB view details)

Uploaded CPython 3.14manylinux: glibc 2.17+ x86-64

pyropust-0.1.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (479.8 kB view details)

Uploaded CPython 3.14manylinux: glibc 2.17+ ARM64

pyropust-0.1.0-cp314-cp314-macosx_11_0_arm64.whl (441.5 kB view details)

Uploaded CPython 3.14macOS 11.0+ ARM64

pyropust-0.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (494.5 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

pyropust-0.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (482.4 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ ARM64

pyropust-0.1.0-cp313-cp313-macosx_11_0_arm64.whl (441.4 kB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

pyropust-0.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (495.6 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

pyropust-0.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (481.6 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ ARM64

pyropust-0.1.0-cp312-cp312-macosx_11_0_arm64.whl (443.4 kB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

File details

Details for the file pyropust-0.1.0.tar.gz.

File metadata

  • Download URL: pyropust-0.1.0.tar.gz
  • Upload date:
  • Size: 67.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyropust-0.1.0.tar.gz
Algorithm Hash digest
SHA256 ef0395c3beb8690819183a8328cd92cf929edd1d2a4b6e57b42ef49ff3bb592f
MD5 2cb3b99cb24677914075765d2ae6f10f
BLAKE2b-256 801a26d03758db6e28e0b2aeabe242acf6cfa783490f6edf085f20dc5fcfc60f

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyropust-0.1.0.tar.gz:

Publisher: publish.yml on K-dash/pyropust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyropust-0.1.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyropust-0.1.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 7f283efd240a815aa75b157f9483e1f8b727c9dd658a13d99b1c08911f6c5852
MD5 c7d501b368cb47de75f4e48eba9ceac2
BLAKE2b-256 a943ca21cf45a7e41d1088281c26bb3f0530adc2ed66c5ea4c18cc80e911f2fc

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyropust-0.1.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: publish.yml on K-dash/pyropust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyropust-0.1.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for pyropust-0.1.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 c13e73ec5328a6f9851bc307ef5309ad9cec9567cb2b9f056e9ff4b4b50e8cb7
MD5 9651e947290bbad488acc0ff2b1d8ceb
BLAKE2b-256 06cf1d65210346b505442cd322cc53ef9bc0fa3f3009bf543503b8a00b42f9ef

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyropust-0.1.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: publish.yml on K-dash/pyropust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyropust-0.1.0-cp314-cp314-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pyropust-0.1.0-cp314-cp314-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 ff0bf6fa6214fcb4c4748e497e555fb0e7b9a5071a8af16e4bbab0de295ab8ec
MD5 1a412efa1145820f75317ad61ad44509
BLAKE2b-256 b2ad999ce19adb94366e00e6ac6f84638fcd838665b583d0506a9ab935897736

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyropust-0.1.0-cp314-cp314-macosx_11_0_arm64.whl:

Publisher: publish.yml on K-dash/pyropust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyropust-0.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyropust-0.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 dcac769e1767aee534b865d461af6521dfc498b599289c626464430ff3d6ee20
MD5 bcbeae7fafe6b1428d2592e6bd117719
BLAKE2b-256 77fee9dc79eee21812ba217a2a0634ff924148cf40861bd0d542c66f4011168b

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyropust-0.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: publish.yml on K-dash/pyropust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyropust-0.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for pyropust-0.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 26311a7ee8a97307dcea70f8ca883eff72bcf55ede7b886c215ff04b987ebaab
MD5 2db9f707e7e0aaa845cad59e3581df8f
BLAKE2b-256 7c11cace55a0d7b18f03d5c63b0fbca81d30ba036d11e0685c6c526cae5f5b5c

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyropust-0.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: publish.yml on K-dash/pyropust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyropust-0.1.0-cp313-cp313-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pyropust-0.1.0-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 26cc175c64c8c1241d589bdf4ed8872640dff9fdbe9fe52122f3d81c1c32f245
MD5 4c5157ecb685a4798910b8aaaa294204
BLAKE2b-256 dd518496d106aaf53230f41438dbabef386a31d946e4a25c3b7de6e5fb8e45cf

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyropust-0.1.0-cp313-cp313-macosx_11_0_arm64.whl:

Publisher: publish.yml on K-dash/pyropust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyropust-0.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyropust-0.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 a3465bd33b275fab6d92a031b5a4f1f0948c491708a3cf0cd13497103c2549f6
MD5 46e5d6d77752e913433f4e6f1f9984ac
BLAKE2b-256 8b41b5ca57db5b8cc7216f18ed7f9e089f9d04036bb639fb5b2fa6d17540f79e

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyropust-0.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: publish.yml on K-dash/pyropust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyropust-0.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for pyropust-0.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 9167d48ab8a0d20bace122bc3f6fc424a23c6a2f2c2b4447a2679aa5151c7b67
MD5 2e6b44dae4604151d2f3a9b86778e89d
BLAKE2b-256 2f7263a295da18dd91ae2eaddddca0bdf0dca58db71f2057f6f9e386bb0903c2

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyropust-0.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: publish.yml on K-dash/pyropust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyropust-0.1.0-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pyropust-0.1.0-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 67fc595aff1bcfa5f10504fa72427e21ab32100cfc34bef804d1cdafc86145d8
MD5 f391c041bca0bbd05e2f4bae4a1ca1c3
BLAKE2b-256 1e29740b407232eb5349a160c6058bd503a69f50e008d13d8a996cce2de435b5

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyropust-0.1.0-cp312-cp312-macosx_11_0_arm64.whl:

Publisher: publish.yml on K-dash/pyropust

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page