Metadata-Version: 2.4
Name: nofuture
Version: 1.1.0
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.12
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Libraries
Classifier: Programming Language :: Rust
Classifier: Operating System :: OS Independent
Requires-Dist: click>=8.3.1 ; extra == 'dev'
Requires-Dist: maturin>=1.11.5 ; extra == 'dev'
Requires-Dist: twine>=6.2.0 ; extra == 'dev'
Requires-Dist: devpi-client>=7.2.0 ; extra == 'dev'
Provides-Extra: dev
License-File: LICENSE
Summary: NoFuture: explicit Maybe and Result types. No futures. No exceptions.
Author-email: Aristofor Kolomb <aristofor@gmail.com>
License-Expression: GPL-3.0-or-later
Requires-Python: >=3.12
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Changelog, https://framagit.org/aristofor/nofuture/-/blob/main/CHANGELOG.md
Project-URL: Homepage, https://framagit.org/aristofor/nofuture
Project-URL: Issues, https://framagit.org/aristofor/nofuture/-/issues
Project-URL: License, https://framagit.org/aristofor/nofuture/-/blob/main/LICENSE

# NoFuture

<img src="https://framagit.org/aristofor/nofuture/-/raw/main/NoFuture.svg" alt="NoFuture" width="160">

[![pipeline status](https://framagit.org/aristofor/nofuture/badges/v1.1.0/pipeline.svg)](https://framagit.org/aristofor/nofuture/-/commits/v1.1.0)

- [Changelog](https://framagit.org/aristofor/nofuture/-/blob/main/CHANGELOG.md)
- [License](https://framagit.org/aristofor/nofuture/-/blob/main/LICENSE)

No futures. No exceptions. Just explicit values.

`MayBe` et `Result` pour Python, built en Rust (PyO3 + maturin).

```python
from nofut import MayBe, Result
```

## Installation

```bash
pip install nofuture
```

Dev mode: `maturin develop`

## MayBe

Valeur optionnelle: `Just(value)` ou `Nothing`.

```python
MayBe.just(42)      # Just(42)
MayBe.nothing()     # Nothing

# API
.is_just() / .is_nothing()
.unwrap()           # raise si Nothing
.expect(msg)        # raise avec message custom si Nothing
.or_else(default)   # valeur ou default
.to_option()        # valeur ou None
.map(fn)            # Just(fn(x)) ou Nothing
.flat_map(fn)       # fn doit retourner MayBe
.match(just=fn, nothing=fn)  # pattern matching
>> fn               # flat_map
| default           # or_else
```

## Result

Succès ou erreur: `Ok(value)` ou `Err(message, code?, details?)`. La vie en binaire, avec du contexte.

```python
Result.ok(42)
Result.err("not found", code="NOT_FOUND")
Result.err("validation", code="INVALID", details={"field": "name"})
Result.from_dict({"ok": True, "value": 42})  # réciproque de to_dict

# API
.is_ok() / .is_err()
.unwrap()           # raise si Err
.expect(msg)        # raise avec message custom si Err
.unwrap_or(default) # valeur ou default
.unwrap_err()       # (msg, code, details) ou raise
.to_option()        # valeur ou None
.map(fn)            # Ok(fn(x)) ou Err passthrough
.map_err(fn)        # fn(msg, code, details) -> (msg, code, details)
.flat_map(fn)       # fn doit retourner Result
.and_then(fn)       # alias flat_map
.match(ok=fn, err=fn)  # pattern matching (err reçoit msg, code, details)
.to_dict()          # {"ok": True, "value": ...} ou {"ok": False, "error": ...}
>> fn               # flat_map
| default           # unwrap_or
```

## Typage générique

`MayBe` et `Result` supportent la syntaxe générique pour le typage statique :

```python
from nofut import MayBe, Result
from typing import Any

# MayBe[T] pour les valeurs optionnelles
def find_user(id: int) -> MayBe[User]:
    ...

# Result[T, E] pour les opérations faillibles
MyResult = Result[dict[str, Any], str]
```

## Itération

`MayBe` et `Result` se comportent comme des collections de 0 ou 1 élément :

```python
len(MayBe.just(42))      # 1
len(MayBe.nothing())     # 0

for x in Result.ok("hi"):
    print(x)

value, = MayBe.just("ok")    # unpacking
```

## Exemples

Exemples progressifs (basics -> objets -> pipeline Result).

```bash
python3 examples/base.py
python3 examples/objects.py
python3 examples/iteration.py
python3 examples/result.py
```

## Tests

```bash
python3 -m unittest discover -s tests -p 'test_*.py'
```

