Metadata-Version: 2.4
Name: paraboloski-result
Version: 0.1.0
Summary: Result monad for Python using Ok, Err and safe decorators
Author-email: Paraboloski <andreapetracca155@gmail.com>
License: MIT License
        
        Copyright (c) 2026 Andrea Petracca
        
        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.
License-File: LICENSE
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# paraboloski-result

Un decoratore per l'error handling per Python che sfrutta il design pattern monadico. Rappresenta operazioni che possono avere successo (`Ok`) o fallire (`Err`), senza sollevare eccezioni.

## Installazione

### PyPI
```bash
uv add paraboloski-result
pip install paraboloski-result
```

### GitHub
```bash
uv add git+https://github.com/paraboloski/snippet-toolbox/python#subdirectory=snippet/result
```

## Quando usarla

Ideale per operazioni che possono fallire in modo prevedibile: chiamate HTTP, parsing di dati, accesso al filesystem, query a database. Invece di disseminare `try/except` nel codice, il fallimento diventa parte esplicita del tipo di ritorno.

## Utilizzo

```python
from result import Ok, Err, Result, safe, safe_async

@safe
def parse_user(data: dict) -> User:
    return User(
        id=data["id"],
        name=data["name"],
        email=data["email"],
    )

@safe_async
async def fetch_user(user_id: int) -> dict:
    async with aiohttp.ClientSession() as session:
        async with session.get(f"/api/users/{user_id}") as response:
            return await response.json()
```

### Gestisci il risultato con match

```python
match parse_user(data):
    case Ok(user):
        print(f"Benvenuto, {user.name}")
    case Err(error):
        print(f"Dati utente non validi: {error}")
```

### Pipeline di operazioni

Il fallimento si propaga automaticamente senza blocchi `try/except` annidati:

```python
@safe
def read_file(path: str) -> str:
    with open(path) as f:
        return f.read()

@safe
def parse_json(content: str) -> dict:
    return json.loads(content)

@safe
def parse_user(data: dict) -> User:
    if "name" not in data:
        raise ValueError("campo 'name' mancante")
    return User(**data)

match read_file("user.json"):
    case Ok(content):
        match parse_json(content):
            case Ok(data):
                match parse_user(data):
                    case Ok(user): print(f"Ciao, {user.name}")
                    case Err(e): print(f"Utente non valido: {e}")
            case Err(e): print(f"JSON malformato: {e}")
    case Err(e): print(f"File non trovato: {e}")
```

### Oppure fornisci un valore di default con unwrap_or

Quando il fallimento è accettabile e hai un valore di fallback:

```python
user = parse_user(data).unwrap_or(User(id=0, name="anonimo", email=""))
users = (await fetch_user(user_id)).unwrap_or([])
```