Skip to main content

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 selected 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}")

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

Pass exception types to catch only expected failures. Exceptions that are not selected continue to propagate.

from sovic import to_result


@to_result(ValueError, TypeError)
def parse_number(value: str) -> int:
    return int(value)

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 factory that converts a callable from Callable[P, T] into Callable[P, Result[T, Exception]]. Use to_result() to catch every Exception, or pass one or more exception types to catch selected failures.

Development

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

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.2.0.tar.gz (5.6 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.2.0-py3-none-any.whl (5.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: sovic-0.2.0.tar.gz
  • Upload date:
  • Size: 5.6 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.2.0.tar.gz
Algorithm Hash digest
SHA256 a5f0567dec1a30ecf81e67e75b1bca02c0a8acb525651ffed69814bf1d8bc653
MD5 07deabe4fa27278aa2b025b83d8788fb
BLAKE2b-256 420af1afd3c58563f62a1fc7a2f5338e4bcff5ff319360617e67cdb584294105

See more details on using hashes here.

File details

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

File metadata

  • Download URL: sovic-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 5.9 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.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1948badc85ac91589c38ae6e914fbc44aa90638b9f63b721c227660097bcc774
MD5 5774affcff021ea4ad57a595ffc8ec0e
BLAKE2b-256 5394d7ea70be27b6d25d1b8fefa014bd8a3cc46cca14614b96eb02e69a754660

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page