better-result-py
Inspired by better-result
Yet another implementation of Rust's Result type: minimal, dependency-free, and fully-typed. Wraps synchronous and asynchronous functions so exceptions become values rather than control flow.
Installation
# with uv
uv add better-result-py
# with pip
pip install better-result-py
Usage
Synchronous
Wrap any callable with Result. If the function raises, ok is Unset and err holds the exception. If it succeeds, ok holds the value and err is None.
from better_result import Result
def divide(a: int, b: int) -> float:
return a / b
result = Result(divide, 10, 2)
result.is_ok() # True
result.ok # 5.0
result.err # None
result = Result(divide, 10, 0)
result.is_ok() # False
result.err # ZeroDivisionError(...)
Asynchronous
AsyncResult works the same way for async functions.
import asyncio
from better_result import AsyncResult
async def fetch_data(url: str) -> str:
... # may raise
result = await AsyncResult(fetch_data, "https://example.com")
if result.is_ok():
print(result.ok)
else:
print(result.err)
Explicit Ok / Err construction
For control-flow patterns where you want to return a typed result directly (without wrapping a callable) use Ok and Err.
from better_result import Ok, Err, BaseResult
def divide(a: int, b: int) -> BaseResult[float]:
if b == 0:
return Err("division by zero")
return Ok(a / b)
result = divide(10, 2)
result.is_ok() # True
result.ok # 5.0
result = divide(10, 0)
result.is_err() # True
result.err # ResultError("division by zero")
Err accepts either a plain string message (wrapped in ResultError) or an existing exception via the err keyword argument:
Err("something went wrong") # error_message form
Err(err=ValueError("bad value")) # exception form
Extracting values
unwrap()
Returns the value or raises the original exception (or UnsetError if the result is unset).
value = Result(divide, 10, 2).unwrap() # 5.0
Result(divide, 10, 0).unwrap() # raises ZeroDivisionError
unwrap_or(default)
Returns the value or falls back to a default on error.
value = Result(divide, 10, 0).unwrap_or(0.0) # 0.0
expect(message)
Like unwrap(), but always raises ExpectError with a custom message (preserving the original exception as __cause__).
result = Result(divide, 10, 0)
result.expect("division must succeed") # raises ExpectError("division must succeed")
API reference
| Method | Description |
|---|---|
is_ok() -> bool |
True if no error and value is set |
is_err() -> bool |
True if an error occurred or value is unset |
unwrap() -> T |
Return value or raise |
unwrap_or(default: T) -> T |
Return value or default |
expect(message: str) -> T |
Return value or raise ExpectError |
Requirements
Python 3.10 or higher. No runtime dependencies.
Roadmap
Find the full roadmap here
Metadata
Release files for better-result-py 1.1.0
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 |
|---|---|---|---|---|
| better_result_py-1.1.0.tar.gz | 3.6 kB | Without provenance | Details for better_result_py-1.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| better_result_py-1.1.0-py3-none-any.whl | Python 3 | none | any | Details for better_result_py-1.1.0-py3-none-any.whl |
Total release size: 8.1 kB
Release files / better_result_py-1.1.0.tar.gz
| Download URL | better_result_py-1.1.0.tar.gz |
|---|---|
| Size | 3.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b73494e0692efda9d6fd3ea1304093a35c18b94633bfcfaec37aab80e951f2e4
|
|
BLAKE2b-256 checksum How to use checksums |
f9d2c02f5be83ac4e52b95fbe9673715c1d3901863ec5ee98db94f09f3f2abe0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","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 / better_result_py-1.1.0-py3-none-any.whl
| Download URL | better_result_py-1.1.0-py3-none-any.whl |
|---|---|
| Size | 4.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
585df8a5ceca37a5891f1e4989147b7cbc7657ddfaba8f6f44a0d766b2a2b392
|
|
BLAKE2b-256 checksum How to use checksums |
4d2c58bb760c184da697e1e4f6d1c4ee21e875fb133955d6c9ad4e8aabd5be13
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","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 better-result-py 1.1.0
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.