Skip to main content

Result monad for Python using Ok, Err and safe decorators

Project description

paraboloski-monad

An error handling decorator for Python that leverages the monadic design pattern. It represents operations that run on two parallel tracks: they can either succeed (Ok) or fail (Err), without raising exceptions.


Installation

PyPI

uv add paraboloski-monad
pip install paraboloski-monad

GitHub

uv add git+https://github.com/paraboloski/snippet-toolbox/python#subdirectory=snippet/monad

When to use it

Ideal for operations that can fail predictably: HTTP calls, data parsing, filesystem access, database queries. Instead of scattering try/except blocks throughout your code, failure becomes an explicit part of the return type.

Usage

from monad import Ok, Err, monad, 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()

Handle results with match

match parse_user(data):
    case Ok(user):
        print(f"Welcome, {user.name}")
    case Err(error):
        print(f"Invalid user data: {error}")

Operation pipelines

Failures propagate automatically without nested try/except blocks:

@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("missing 'name' field")
    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"Hello, {user.name}")
                    case Err(e):
                        print(f"Invalid user: {e}")
            case Err(e):
                print(f"Malformed JSON: {e}")
    case Err(e):
        print(f"File not found: {e}")

Or provide a default value with unwrap_or

When failure is acceptable and you want a fallback value:

user = parse_user(data).unwrap_or(
    User(id=0, name="anonymous", email="")
)

users = (await fetch_user(user_id)).unwrap_or([])

Italiano

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

Installazione

PyPI

uv add paraboloski-monad
pip install paraboloski-monad

GitHub

uv add git+https://github.com/paraboloski/snippet-toolbox/python#subdirectory=snippet/monad

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

from monad import Ok, Err, monad, 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

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:

@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:

user = parse_user(data).unwrap_or(
    User(id=0, name="anonimo", email="")
)

users = (await fetch_user(user_id)).unwrap_or([])

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

paraboloski_monad-1.0.0.tar.gz (4.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

paraboloski_monad-1.0.0-py3-none-any.whl (3.9 kB view details)

Uploaded Python 3

File details

Details for the file paraboloski_monad-1.0.0.tar.gz.

File metadata

  • Download URL: paraboloski_monad-1.0.0.tar.gz
  • Upload date:
  • Size: 4.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for paraboloski_monad-1.0.0.tar.gz
Algorithm Hash digest
SHA256 8bd322a3d9d8d60229d5e698c5e1af021e997779f3c1b002b5fb7dcb6b483c90
MD5 64d6075b2ea4925b6ece70eb3df6bd84
BLAKE2b-256 2d58731391d3613709591f8c47d91916c1b9a1d1bc3d997b6844cde2c20514f9

See more details on using hashes here.

File details

Details for the file paraboloski_monad-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for paraboloski_monad-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e27c1317ce12430a9e1df30434f1573d2cf3ff905ea142f7755156c4a3afb84a
MD5 4da3b66ececf82edcfca65d2b0baae6e
BLAKE2b-256 ff8e0f1f703c2fb8702eb5effc18e52bc18e65b10247a7dbf5d6d9fe327a4d52

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page