A robust, fully-typed, and async-ready Result pattern implementation for Python.
fates brings expressive, functional error handling to Python, completely removing the need for defensive try/except blocks. It helps you build predictable pipelines with absolute type safety for both synchronous and asynchronous operations.
- 🛡️ 100% Type Safe: Full
mypy/pyrightcompliance using generic protocols andTypeVarcovariance. - ⚡ Async Native: First-class support for asynchronous mapping and monadic binding.
- 🧩 Zero Dependencies: Lightweight and clean, relying only on standard library primitives (and
typing_extensionsfor older Python versions).
pip install fatesfrom fates import Result, Ok, Err
def divide(a: int, b: int) -> Result[float, str]:
if b == 0:
return Err("Cannot divide by zero")
return Ok(a / b)
# Monadic binding and mapping
result = (
divide(10, 2)
.map(lambda x: x * 2)
.unwrap_or(0.0)
)
print(result) # Output: 10.0fates shines when working with async databases or HTTP clients. Use amap and abind to pipe async operations seamlessly.
import asyncio
from fates import Ok, Err, Result
async def fetch_user_id(username: str) -> Result[int, str]:
# Simulating async DB call
await asyncio.sleep(0.1)
return Ok(42) if username == "admin" else Err("User not found")
async def get_user_role_async(user_id: int) -> Result[str, str]:
await asyncio.sleep(0.1)
return Ok("superuser")
async def main():
# Chain async functions using abind
pipeline = await fetch_user_id("admin").abind(get_user_role_async)
print(pipeline) # Output: Ok('superuser')
print(pipeline.unwrap()) # Output: superuser
asyncio.run(main()).unwrap()— Returns the success value or raises anUnwrapError..unwrap_or(default)— Returns the success value or a fallback value..unwrap_err()— Returns the error value or raises anUnwrapError..expect(note)— Returns the success value or crashes with a custom message.
.map(mapper)— Transforms the success value insideOk..map_err(mapper)— Transforms the error value insideErr..bind(binder)— Monadic bind. Chains another operation that returns aResult..catch(binder)— Recovers from an error by returning an alternativeResult..resolve(mapper)— Merges both paths into a single success-type value.
.amap(async_mapper)— Asynchronously transforms the success value..amap_err(async_mapper)— Asynchronously transforms the error value..abind(async_binder)— Asynchronously chains another operation returning aResult.
This project is licensed under the MIT License.