Skip to main content

Typed Python utilities for explicit error handling and composable helpers

Project description

Sovic

sovic is a typed Python utility package for explicit error handling, collection helpers, and small composable tools. It starts with a Result-style API for code that should return either a successful value or an error value without raising at the call site.

The package is inspired by Result types commonly found in languages such as Rust:

  • Ok(value) represents a successful operation.
  • Err(error) represents a failed operation.
  • Result[T, E] is the union of Ok[T] | Err[E].
  • ResultProtocol[T, E] describes the shared Result interface.
  • to_result converts exceptions raised by a function into Err(Exception).
  • map, map_err, and and_then help transform and chain Result values.

Why Sovic?

Python exceptions are useful, but they can make expected failures implicit. sovic is for functions where failure is part of the normal return path, such as validation, parsing, request handling, or adapters around exception-raising code.

Use sovic when you want:

  • explicit success and error branches in function signatures;
  • simple pattern matching with Ok(value) and Err(error);
  • typed error handling without adding runtime dependencies;
  • small composable helpers for transforming and chaining results.

Installation

This project is managed with uv and requires Python 3.12 or newer.

uv sync --all-groups

Basic Usage

from sovic import Err, Ok, Result


def parse_user_id(raw: str) -> Result[int, str]:
    if raw.isdigit():
        return Ok(int(raw))

    return Err("user id must be numeric")


result = parse_user_id("42")

if result.is_ok():
    user_id = result.ok()
else:
    message = result.err()

Transforming Results

Use map() to transform a successful value, map_err() to transform an error, and and_then() to chain another operation that returns a Result.

from sovic import Err, Ok, Result


def parse_user_id(raw: str) -> Result[int, str]:
    if raw.isdigit():
        return Ok(int(raw))

    return Err("user id must be numeric")


def require_positive(user_id: int) -> Result[int, str]:
    if user_id > 0:
        return Ok(user_id)

    return Err("user id must be positive")


result = (
    parse_user_id("42")
    .map(lambda user_id: user_id + 1)
    .and_then(require_positive)
    .map_err(lambda error: f"invalid user id: {error}")
)

Pattern Matching

Ok and Err can be used with Python pattern matching.

from sovic import Err, Ok


match parse_user_id("abc"):
    case Ok(value):
        print(f"parsed id: {value}")
    case Err(error):
        print(f"invalid input: {error}")

Converting Exceptions

Use to_result when you want a function that may raise an exception to return a Result instead.

from sovic import Err, Ok, to_result


@to_result
def divide(a: float, b: float) -> float:
    return a / b


match divide(8, 0):
    case Ok(value):
        print(value)
    case Err(error):
        print(f"failed: {error}")

to_result catches Exception and returns Err(Exception). It does not catch BaseException, so interrupts such as KeyboardInterrupt and SystemExit are not swallowed.

API Reference

Ok[T]

Successful result container.

  • ok() -> T: returns the contained value.
  • err() -> Never: raises ResultValueError.
  • unwrap() -> T: returns the contained value.
  • unwrap_err() -> Never: raises ResultValueError.
  • is_ok() -> bool: returns True.
  • is_err() -> bool: returns False.
  • map(func) -> Ok[U]: returns Ok(func(value)).
  • map_err(func) -> Ok[T]: returns the original Ok.
  • and_then(func) -> Result[U, E]: returns func(value).

Err[E]

Failed result container.

  • ok() -> Never: raises ResultValueError.
  • err() -> E: returns the contained error.
  • unwrap() -> Never: raises ResultValueError.
  • unwrap_err() -> E: returns the contained error.
  • is_ok() -> bool: returns False.
  • is_err() -> bool: returns True.
  • map(func) -> Err[E]: returns the original Err.
  • map_err(func) -> Err[F]: returns Err(func(error)).
  • and_then(func) -> Err[E]: returns the original Err.

Result[T, E]

Type alias for Ok[T] | Err[E].

ResultProtocol[T, E]

Structural protocol for objects that expose the same Result-style methods as Ok and Err.

to_result

Decorator that converts a callable from Callable[P, T] into Callable[P, Result[T, Exception]].

Development

uv run pytest
uv run ruff check .
uv run ruff format .
uv run pyrefly check

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

sovic-0.1.0.tar.gz (5.0 kB view details)

Uploaded Source

Built Distribution

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

sovic-0.1.0-py3-none-any.whl (5.3 kB view details)

Uploaded Python 3

File details

Details for the file sovic-0.1.0.tar.gz.

File metadata

  • Download URL: sovic-0.1.0.tar.gz
  • Upload date:
  • Size: 5.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for sovic-0.1.0.tar.gz
Algorithm Hash digest
SHA256 55915e31a1820af41f253fd6b1619e51b9eb58d55800e3e61621206ff00074f4
MD5 01d230d20a41fa91c5061c9523696ae9
BLAKE2b-256 8d0f79bc2c23db30a28168e6fcddfcc465209d7a9f1f3dea82e6a8f92cf1f746

See more details on using hashes here.

File details

Details for the file sovic-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: sovic-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 5.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for sovic-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 689c9921a9a4f92cb84fd592f9dd70316f85d9d6bfbb20c8c7f67b643d27ac4f
MD5 b79d396fee0202f53428bf37d5c9cd4e
BLAKE2b-256 d64970d43946d9584dfc25f360e59f2c3b99992737e628a40af940c7eaf5bc7f

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