Metadata-Version: 2.3
Name: fates
Version: 0.0.2
Summary: A generic Result[T, E] type for explicit error propagation.
Author: Evgeny Goryachev
Author-email: Evgeny Goryachev <saladware46@gmail.com>
License: # MIT License
         
         Copyright (c) 2026 Evgeny Goryachev
         
         Permission is hereby granted, free of charge, to any person obtaining a copy
         of this software and associated documentation files (the "Software"), to deal
         in the Software without restriction, including without limitation the rights
         to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
         copies of the Software, and to permit persons to whom the Software is
         furnished to do so, subject to the following conditions:
         
         The above copyright notice and this permission notice shall be included in all
         copies or substantial portions of the Software.
         
         THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
         AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
         OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
         SOFTWARE.
Classifier: Typing :: Typed
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Dist: typing-extensions>=4.0.0 ; python_full_version < '3.12'
Requires-Python: >=3.7
Project-URL: Documentation, https://saladware.github.io/fates/
Project-URL: Repository, https://github.com/saladware/fates
Description-Content-Type: text/markdown

# fates 🔮

[![PyPI Version](https://img.shields.io/pypi/v/fates?style=flat-square&color=green&label=latest)](https://pypi.org/project/fates/)
[![Code Quality Check](https://github.com/saladware/fates/actions/workflows/check.yml/badge.svg)](https://github.com/saladware/fates/actions/workflows/check.yml)

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.

---

## ✨ Features

- **🛡️ 100% Type Safe:** Full `mypy` / `pyright` compliance using generic protocols and `TypeVar` covariance.
- **⚡ Async Native:** First-class support for asynchronous mapping and monadic binding.
- **🧩 Zero Dependencies:** Lightweight and clean, relying only on standard library primitives (and `typing_extensions` for older Python versions).

---

## 🚀 Installation

```bash
pip install fates
```

---

## 📖 Quick Start

### Synchronous Usage

```python
from 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.0
```

### Asynchronous Pipelines

`fates` shines when working with async databases or HTTP clients. Use `amap` and `abind` to pipe async operations seamlessly.

```python
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())
```

---

## 🛠️ API Reference

### Extracting Values

- `.unwrap()` — Returns the success value or raises an `UnwrapError`.
- `.unwrap_or(default)` — Returns the success value or a fallback value.
- `.unwrap_err()` — Returns the error value or raises an `UnwrapError`.
- `.expect(note)` — Returns the success value or crashes with a custom message.

### Transforming Results

- `.map(mapper)` — Transforms the success value inside `Ok`.
- `.map_err(mapper)` — Transforms the error value inside `Err`.
- `.bind(binder)` — Monadic bind. Chains another operation that returns a `Result`.
- `.catch(binder)` — Recovers from an error by returning an alternative `Result`.
- `.resolve(mapper)` — Merges both paths into a single success-type value.

### Async Operations

- `.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 a `Result`.

---

## ⚖️ License

This project is licensed under the [MIT License](LICENSE).
