Skip to main content

philiprehberger-result

Tests PyPI version Last updated

Rust-inspired Result type for Python with pattern matching and type-safe error handling.

Installation

pip install philiprehberger-result

Usage

Basic Result

from philiprehberger_result import Ok, Err, Result

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

result = divide(10, 2)
print(result.unwrap())  # 5.0

result = divide(10, 0)
print(result.unwrap_or(0.0))  # 0.0

Pattern Matching (Python 3.10+)

match divide(10, 3):
    case Ok(value):
        print(f"Result: {value}")
    case Err(error):
        print(f"Error: {error}")

Chaining

result = (
    Ok(10)
    .map(lambda x: x * 2)
    .flat_map(lambda x: Ok(x + 1) if x < 100 else Err("too large"))
)

Fallback with or_else

result = Err("not found").or_else(lambda e: Ok("default"))
# Ok("default")

Serialization

Ok(42).to_dict()    # {"ok": 42}
Err("x").to_dict()  # {"err": "x"}

Try/Catch Wrapping

from philiprehberger_result import try_catch

result = try_catch(lambda: int("not a number"))
# Err(ValueError("invalid literal..."))

Async Support

from philiprehberger_result import try_catch_async

result = await try_catch_async(fetch_data)

Collecting Results

from philiprehberger_result import all_ok

results = [Ok(1), Ok(2), Ok(3)]
combined = all_ok(results)  # Ok([1, 2, 3])

results = [Ok(1), Err("fail"), Ok(3)]
combined = all_ok(results)  # Err("fail")

Batch Mapping

from philiprehberger_result import map_batch

results = [Ok(1), Ok(2), Ok(3)]
mapped = map_batch(results, lambda x: x * 10)  # Ok([10, 20, 30])

results = [Ok(1), Err("fail"), Ok(3)]
mapped = map_batch(results, lambda x: x * 10)  # Err("fail")

Flattening Nested Results

nested = Ok(Ok(42))
flat = nested.flatten()  # Ok(42)

nested = Ok(Err("inner error"))
flat = nested.flatten()  # Err("inner error")

outer_err = Err("outer")
flat = outer_err.flatten()  # Err("outer")

Transpose nested results

from philiprehberger_result import transpose

transpose(Ok(Ok(5)))       # Ok(5)
transpose(Ok(Err("bad")))  # Err("bad")
transpose(Err("outer"))    # Err("outer")

# Method form:
Ok(Ok(5)).transpose()      # Ok(5)
Ok(Err("bad")).transpose() # Err("bad")

Unlike flatten(), transpose() collapses both inner branches and raises TypeError if the inner value is not itself a Result.

Combining Multiple Results

from philiprehberger_result import combine

result = combine(Ok(1), Ok("hello"), Ok(True))
# Ok((1, "hello", True))

result = combine(Ok(1), Err("fail"), Ok(3))
# Err("fail")

Collecting Results from Iterables

from philiprehberger_result import collect

results = [Ok(1), Ok(2), Ok(3)]
collected = collect(results)  # Ok([1, 2, 3])

results = [Ok(1), Err("fail"), Ok(3)]
collected = collect(results)  # Err("fail")

Adding Error Context

result = Err("not found").with_context("loading config")
# Err("loading config: not found")

ok_result = Ok(42).with_context("ignored for Ok")
# Ok(42)

Partitioning

from philiprehberger_result import Ok, Err, partition

oks, errs = partition([Ok(1), Err("a"), Ok(2), Err("b"), Ok(3)])
# oks == [1, 2, 3]
# errs == ["a", "b"]

Unlike collect(), partition() does not short-circuit on the first Err — it walks the entire iterable and returns both lists.

Side-effect taps

from philiprehberger_result import Ok, Err

Ok(5).tap(lambda v: print(f"got {v}"))
# prints "got 5", returns Ok(5)

Err("boom").tap_err(lambda e: print(f"error: {e}"))
# prints "error: boom", returns Err("boom")

# Mismatched variants are no-ops:
Err("boom").tap(lambda v: print(v))      # does nothing, returns Err("boom")
Ok(5).tap_err(lambda e: print(e))        # does nothing, returns Ok(5)

API

Function / Class Description
Ok(value) Success variant — wraps a value
Err(error) Error variant — wraps an error
.is_ok() / .is_err() Type check
.unwrap() Get value or raise
.unwrap_or(default) Get value or return default
.unwrap_err() Get error or raise
.map(fn) Transform Ok value
.map_err(fn) Transform Err value
.flat_map(fn) Chain Result-returning functions
.or_else(fn) Fallback on Err, pass-through on Ok
.flatten() Flatten nested Results: Ok(Ok(v)) -> Ok(v)
.transpose() / transpose(result) Collapse nested Result: Ok(Ok(v)) -> Ok(v), Ok(Err(e)) -> Err(e), Err(e) -> Err(e)
.match(ok=fn, err=fn) Pattern dispatch
.to_dict() Serialize to {"ok": v} or {"err": e}
ok(value) / err(error) Shorthand constructors
try_catch(fn) Wrap callable in Result
try_catch_async(fn) Async version
from_awaitable(aw) Wrap awaitable in Result
all_ok(results) Collect list of Results into Result of list
map_batch(results, fn) Apply fn to all Ok values; short-circuit on first Err
combine(*results) Merge multiple Results into Ok(tuple) or first Err
collect(iterable) Convert iterable of Results into Result of list or first Err
partition(results) Split iterable of Results into (oks, errs) lists without short-circuiting
.with_context(msg) Wrap Err with context string; pass-through on Ok
Ok.tap(fn) / Err.tap(fn) Call fn(value) on Ok for side effects; no-op on Err; returns self
Ok.tap_err(fn) / Err.tap_err(fn) Call fn(error) on Err for side effects; no-op on Ok; returns self

Development

pip install -e .
python -m pytest tests/ -v

Support

If you find this project useful:

⭐ Star the repo

🐛 Report issues

💡 Suggest features

❤️ Sponsor development

🌐 All Open Source Projects

💻 GitHub Profile

🔗 LinkedIn Profile

License

MIT

Release files for philiprehberger-result 0.6.0

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

Source distribution (sdist)

Source distribution for philiprehberger-result 0.6.0
File Size Uploaded
philiprehberger_result-0.6.0.tar.gz 196.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for philiprehberger-result 0.6.0
File Interpreter ABI Platform
philiprehberger_result-0.6.0-py3-none-any.whl Python 3 none any Details

Total release size: 203.7 kB

Release files / philiprehberger_result-0.6.0.tar.gz

Download URL philiprehberger_result-0.6.0.tar.gz
Size 196.9 kB
Tags Source
SHA-256 checksum
How to use checksums
8253a6f157a0c8ede583df727e4d09e7c03dfea11b221a91cbfdb882e85855c5
BLAKE2b-256 checksum
How to use checksums
fc5d0ff0641bf89b2b402f6a4361927a2a663c92e035186af32895a30edd0df4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.13

Release files / philiprehberger_result-0.6.0-py3-none-any.whl

Download URL philiprehberger_result-0.6.0-py3-none-any.whl
Size 6.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8f3fdd0af50a87c4f7f10cd95f27eb234797cb12e0066e90cb84ae0118d17a75
BLAKE2b-256 checksum
How to use checksums
fdc2406cdbed92eb0e55026f1b8133ed6d88f328e1addb35ecef4216dd45cffe
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.13

Release history Release notifications | RSS feed

This release

0.6.0 This release

2 release files

0.5.0

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.1

2 release files

0.1.0

2 release files

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