Skip to main content

Safe, non-error-raising, alternative to Pydantic validate_call decorator

Project description

validate-call-safe

validate_call_safe is a safe, non-error-raising alternative to Pydantic's validate_call decorator. It allows you to validate function arguments while gracefully handling validation errors through an error model, inspired by effects handlers, returning them as structured data models instead of raising exceptions.

This therefore means that side effects ('erroring') are transformed into return types. The return type annotation of a decorated function is modified accordingly as the Union of the existing return type with the provided error model type.

Features

  • Validates function arguments using Pydantic's existing validate_call decorator
  • Returns a custom error model instead of raising exceptions when validation fails
  • Configurable error information, including tracebacks
  • Compatible with Pydantic v2, tested back to version 2.0.1
  • Optional model config and return value validation, as in the original Pydantic @validate_call decorator
  • Option to validate function body execution (validate_body)
  • Option to specify additional exceptions to capture when validating body execution (extra_exceptions)

Installation

pip install validate-call-safe

Usage

Basic Usage

Here's a basic example using a custom error model:

from pydantic import BaseModel
from validate_call_safe import validate_call_safe, ErrorDetails

class CustomErrorModel(BaseModel):
    error_type: str
    error_details: list[ErrorDetails]
    error_repr: str
    error_tb: str

@validate_call_safe(CustomErrorModel)
def int_noop(a: int) -> int:
    return a

success = int_noop(a=1)  # 1
failure = int_noop(a="A")  # CustomErrorModel(error_type='ValidationError', ...)

Return Value Validation

You can enable return value validation using the validate_return parameter, which is passed along to the original Pydantic @validate_call decorator flag of the same name:

@validate_call_safe(validate_return=True)
def int_noop(a: int) -> int:
    return "foo"  # This will cause a validation error

result = int_noop(a=1)  # ErrorModel(error_type='ValidationError', ...)

Function Body Validation

To capture exceptions that occur within the function body, use the validate_body parameter:

@validate_call_safe(validate_body=True)
def failing_function(name: str):
    raise ValueError(f"Invalid name: {name}")

result = failing_function("John")  # ErrorModel(error_type='ValueError', ...)

Capturing Additional Exceptions

You can specify additional exceptions to capture using the extra_exceptions parameter:

@validate_call_safe(validate_body=True, extra_exceptions=(NameError, TypeError))
def risky_function(a: int):
    if a == 1:
        raise NameError("Name not found")
    elif a == 2:
        raise TypeError("Type mismatch")
    return a

result1 = risky_function(1)  # ErrorModel(error_type='NameError', ...)
result2 = risky_function(2)  # ErrorModel(error_type='TypeError', ...)
result3 = risky_function(3)  # 3

The extra_exception default is Exception (enough for most user-level exceptions, but will not stop sys.exit calls for which you'd need to capture BaseException).

Specifying it is useful to narrow the handled exception types, as is good practice with regular try/except exception handling.

Error Model Configuration

validate_call_safe offers flexibility in specifying the error model:

  1. No brackets:

    @validate_call_safe
    def int_noop(a: int) -> int:
        return a
    
  2. Empty brackets:

    @validate_call_safe()
    def int_noop(a: int) -> int:
        return a
    
  3. Custom error model:

    @validate_call_safe(CustomErrorModel)
    def int_noop(a: int) -> int:
        return a
    
  4. With validation parameters:

    @validate_call_safe(validate_return=True)
    def int_noop(a: int) -> int:
        return a
    

Comparison with validate_call

With validate_call_safe you don't have to catch the expected ValidationError from Pydantic's validate_call:

# Using validate_call
from pydantic import validate_call

@validate_call
def unsafe_int_noop(a: int) -> int:
    return a

try:
    unsafe_int_noop(a="A")
except ValidationError as e:
    print(f"Error: {e}")

# Using validate_call_safe
from validate_call_safe import validate_call_safe

@validate_call_safe(CustomErrorModel)
def safe_int_noop(a: int) -> int:
    return a

result = safe_int_noop(a="A")
match result:
    case CustomErrorModel():
        print(f"Error: {result.error_type}")
    case int():
        ...  # Regular business logic here

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

validate_call_safe-0.3.1.tar.gz (4.5 kB view details)

Uploaded Source

Built Distribution

validate_call_safe-0.3.1-py3-none-any.whl (5.5 kB view details)

Uploaded Python 3

File details

Details for the file validate_call_safe-0.3.1.tar.gz.

File metadata

  • Download URL: validate_call_safe-0.3.1.tar.gz
  • Upload date:
  • Size: 4.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: pdm/2.18.1 CPython/3.10.14 Linux/5.15.0-117-generic

File hashes

Hashes for validate_call_safe-0.3.1.tar.gz
Algorithm Hash digest
SHA256 6e8f032dc72aeb5d75f19fcac4c9b06a8682bbc7b256ba8b59f84c13c8250646
MD5 162b81d1714e22c8e8fbc65a7c1de23a
BLAKE2b-256 842935df4b263b92ec09cab8b09208245d94ec31bfddffec96a6e832669d7374

See more details on using hashes here.

File details

Details for the file validate_call_safe-0.3.1-py3-none-any.whl.

File metadata

  • Download URL: validate_call_safe-0.3.1-py3-none-any.whl
  • Upload date:
  • Size: 5.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: pdm/2.18.1 CPython/3.10.14 Linux/5.15.0-117-generic

File hashes

Hashes for validate_call_safe-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 d4e4c6e41d95001eb13fca4c9bc68d1b94c89953a3cbe54dda65c7f6fcfca71e
MD5 604744d77bb93aec667924a303ecbcdc
BLAKE2b-256 4c1f5caa265dfe9ed8e5bfa989f073ca77c737fc2510ae6556bdfb5d5cb03ab9

See more details on using hashes here.

Supported by

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