Skip to main content

A Python library providing a Result type for elegant error handling, inspired by Rust's Result type.

Project description

safe-result

A Python package for elegant error handling, inspired by Rust's Result type.

Installation

uv pip install "git+https://github.com/overflowy/safe-result"

Overview

safe-result provides type-safe objects that represent either success (Ok) or failure (Err). This approach enables more explicit error handling without relying on try/catch blocks, making your code more predictable and easier to reason about.

Key features:

  • Type-safe result handling with generics support
  • Type guards to safely access result values
  • Decorators to automatically wrap function returns in Result objects
  • Pattern matching support for elegant error handling
  • Built-in traceback capture for comprehensive error information

Usage

Basic Usage

from safe_result import Err, Ok, Result, ok


def divide(a: int, b: int) -> Result[float, ZeroDivisionError]:
    if b == 0:
        return Err(ZeroDivisionError("Cannot divide by zero"))  # Failure case
    return Ok(a / b)  # Success case


# Function signature clearly communicates potential failure modes
foo = divide(10, 0)  # -> Result[float, ZeroDivisionError]

# Type checking will prevent unsafe access to the value
bar = 1 + foo.value
#         ^^^^^^^^^ Pylance/mypy indicates error:
# "Operator '+' not supported for types 'Literal[1]' and 'float | None'"

# Safe access pattern using the type guard function
if ok(foo):  # Verifies foo is an Ok result and enables type narrowing
    bar = 1 + foo.value  # Safe! - type system knows the value is a float here
else:
    # Handle error case with full type information about the error
    print(f"Error: {foo.error}")

Using the Decorators

The safe decorator automatically wraps function returns in an Ok or Err object. Any exception is caught and wrapped in an Err result.

from safe_result import Err, Ok, ok, safe


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


# Return type is inferred as Result[float, Exception]
foo = divide(10, 0)

if ok(foo):
    print(f"Result: {foo.value}")
else:
    print(f"Error: {foo}")  # -> Err(division by zero)
    print(f"Error type: {type(foo.error)}")  # -> <class 'ZeroDivisionError'>

# Python's pattern matching provides elegant error handling
match foo:
    case Ok(value):
        bar = 1 + value
    case Err(ZeroDivisionError):
        print("Cannot divide by zero")
    case Err(TypeError):
        print("Type mismatch in operation")
    case Err(ValueError):
        print("Invalid value provided")
    case _ as e:
        print(f"Unexpected error: {e}")

The safe_with decorator provides more precise control by specifying which exception types to catch, improving type hints and safety.

from safe_result import ok, safe_with


@safe_with(ZeroDivisionError)
def divide(a: int, b: int) -> float:
    return a / b


foo = divide(10, 0)  # -> Result[float, ZeroDivisionError]

if not ok(foo):
    print(f"Error: {foo}")  # -> Err(division by zero)
    print(f"Error type: {type(foo.error)}")  # -> <class 'ZeroDivisionError'>


# Other exceptions are not caught, maintaining expected behavior
# foo = divide(10, "2")  # Will raise a TypeError since it's not handled by the decorator

License

MIT

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

safe_result-2.1.0.tar.gz (13.0 kB view details)

Uploaded Source

Built Distribution

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

safe_result-2.1.0-py3-none-any.whl (4.9 kB view details)

Uploaded Python 3

File details

Details for the file safe_result-2.1.0.tar.gz.

File metadata

  • Download URL: safe_result-2.1.0.tar.gz
  • Upload date:
  • Size: 13.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.5.13

File hashes

Hashes for safe_result-2.1.0.tar.gz
Algorithm Hash digest
SHA256 d3ba3e7b3ff3a98fb2a65c4ad1ea58a72a0dd27160d39d3c2a82b2c4688f16c5
MD5 e6f7bb66ec237b93041c0cbbfa12520b
BLAKE2b-256 331aaf1db2a661876459a800335f7f01713583683372f95a223961a9b7a9f65c

See more details on using hashes here.

File details

Details for the file safe_result-2.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for safe_result-2.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 bbd1a07e8082830e63749a4c3ff1450f25139cb9eea78a30fa1e82398850dbef
MD5 5cefb3c9a52ea247baf17f4fa1d97298
BLAKE2b-256 550a996f383de742ffd261d5a8c306bfc5d8340b6a3528f7cd5fae59d8e9a8fc

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