CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-beartype

Unbearably fast near-real-time hybrid runtime-static type-checking in pure Python

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

validators.mddocs/

Custom Validators

Data validation beyond basic type checking using composable validator factories. The beartype.vale module provides a hierarchy of subscriptable classes for creating custom validation logic that integrates seamlessly with beartype's type checking system.

Capabilities

Generic Validator Factory

Create validators from arbitrary callable predicates.

class Is:
    """
    Generic validator factory for callable predicates.
    
    Creates validators from functions that return boolean values.
    Used with typing.Annotated to add validation logic to type hints.
    """
    
    def __class_getitem__(cls, predicate):
        """
        Create validator from predicate function.
        
        Parameters:
        - predicate: callable - Function that takes object and returns bool
        
        Returns:
        BeartypeValidator - Validator object for use with Annotated
        """

Usage examples:

from beartype import beartype
from beartype.vale import Is
from typing import Annotated

# Positive integer validator
PositiveInt = Annotated[int, Is[lambda x: x > 0]]

@beartype
def deposit(amount: PositiveInt) -> str:
    return f"Deposited ${amount}"

deposit(100)   # ✓ Valid
# deposit(-50)  # ✗ Raises validation error

# String length validator
NonEmptyStr = Annotated[str, Is[lambda s: len(s) > 0]]

@beartype
def greet(name: NonEmptyStr) -> str:
    return f"Hello, {name}!"

greet("Alice")  # ✓ Valid
# greet("")     # ✗ Raises validation error

# Complex validation logic
def is_valid_email(email: str) -> bool:
    return "@" in email and "." in email.split("@")[-1]

Email = Annotated[str, Is[is_valid_email]]

@beartype
def send_email(address: Email, message: str) -> bool:
    print(f"Sending to {address}: {message}")
    return True

Attribute-Based Validator Factory

Create validators based on object attributes.

class IsAttr:
    """
    Attribute-based validator factory.
    
    Creates validators that check object attributes against predicates.
    """
    
    def __class_getitem__(cls, params):
        """
        Create attribute validator.
        
        Parameters:
        - params: str or tuple - Attribute name or (attr_name, predicate)
        
        Returns:
        BeartypeValidator - Validator for object attributes
        """

Usage examples:

from beartype.vale import IsAttr
from typing import Annotated
from dataclasses import dataclass

# Check for attribute existence
HasName = Annotated[object, IsAttr["name"]]

# Check attribute value
HasPositiveLength = Annotated[object, IsAttr[("__len__", lambda x: x > 0)]]

@dataclass
class Person:
    name: str
    age: int

@beartype
def process_person(person: HasName) -> str:
    return f"Processing {person.name}"

person = Person("Alice", 30)
process_person(person)  # ✓ Valid

# List length validation  
@beartype
def process_items(items: HasPositiveLength) -> int:
    return len(items)

process_items([1, 2, 3])  # ✓ Valid
# process_items([])       # ✗ Raises validation error

Equality-Based Validator Factory

Create validators based on equality comparisons.

class IsEqual:
    """
    Equality-based validator factory.
    
    Creates validators that check equality against specific values.
    """
    
    def __class_getitem__(cls, value):
        """
        Create equality validator.
        
        Parameters:
        - value: Any - Value to compare against
        
        Returns:
        BeartypeValidator - Validator for equality checking
        """

Usage examples:

from beartype.vale import IsEqual
from typing import Annotated, Literal

# Exact value validation
StatusOK = Annotated[int, IsEqual[200]]
StatusError = Annotated[int, IsEqual[404]]
ConfigMode = Annotated[str, IsEqual["production"]]

@beartype
def handle_response(status: StatusOK) -> str:
    return "Request successful"

@beartype  
def set_config(mode: ConfigMode) -> None:
    print(f"Setting config to {mode}")

handle_response(200)  # ✓ Valid
# handle_response(404)  # ✗ Raises validation error

set_config("production")  # ✓ Valid
# set_config("development")  # ✗ Raises validation error

Instance Type Validator Factory

Create validators based on isinstance() checks.

class IsInstance:
    """
    Instance type validator factory.
    
    Creates validators using isinstance() checks against type or tuple of types.
    """
    
    def __class_getitem__(cls, types):
        """
        Create isinstance validator.
        
        Parameters:
        - types: type or tuple - Type(s) for isinstance check
        
        Returns:
        BeartypeValidator - Validator using isinstance()
        """

Usage examples:

from beartype.vale import IsInstance
from typing import Annotated, Union
import datetime

# Single type validation
NumericValue = Annotated[Union[int, float], IsInstance[int, float]]

# Multiple type validation
DateTimeValue = Annotated[object, IsInstance[(datetime.date, datetime.datetime)]]

@beartype
def calculate(value: NumericValue) -> float:
    return float(value) * 2.0

@beartype
def format_date(dt: DateTimeValue) -> str:
    return dt.strftime("%Y-%m-%d")

calculate(42)      # ✓ Valid (int)
calculate(3.14)    # ✓ Valid (float)  
# calculate("42")  # ✗ Raises validation error

format_date(datetime.date.today())     # ✓ Valid
format_date(datetime.datetime.now())   # ✓ Valid
# format_date("2023-01-01")            # ✗ Raises validation error

Subclass Validator Factory

Create validators based on issubclass() checks.

class IsSubclass:
    """
    Subclass validator factory.
    
    Creates validators using issubclass() checks against type or tuple of types.
    """
    
    def __class_getitem__(cls, types):
        """
        Create issubclass validator.
        
        Parameters:
        - types: type or tuple - Type(s) for issubclass check
        
        Returns:
        BeartypeValidator - Validator using issubclass()
        """

Usage examples:

from beartype.vale import IsSubclass
from typing import Annotated
from abc import ABC, abstractmethod

# Abstract base class
class Drawable(ABC):
    @abstractmethod
    def draw(self): pass

class Shape(Drawable):
    def draw(self): return "Drawing shape"

class Circle(Shape):
    def draw(self): return "Drawing circle"

# Validator for subclasses
DrawableClass = Annotated[type, IsSubclass[Drawable]]
ShapeClass = Annotated[type, IsSubclass[Shape]]

@beartype
def create_drawable(cls: DrawableClass) -> Drawable:
    return cls()

@beartype  
def create_shape(cls: ShapeClass) -> Shape:
    return cls()

create_drawable(Circle)  # ✓ Valid
create_shape(Circle)     # ✓ Valid
# create_drawable(str)   # ✗ Raises validation error

Combining Validators

Multiple validators can be combined using multiple annotations:

from beartype.vale import Is, IsAttr
from typing import Annotated

# Multiple validation constraints
ValidUser = Annotated[
    object,
    IsAttr["name"],                          # Must have name attribute
    IsAttr[("age", lambda x: x >= 18)],      # Age must be >= 18
    Is[lambda obj: len(obj.name) > 0]        # Name must be non-empty
]

@dataclass
class User:
    name: str
    age: int

@beartype
def register_user(user: ValidUser) -> str:
    return f"Registered {user.name}, age {user.age}"

valid_user = User("Alice", 25)
register_user(valid_user)  # ✓ Valid

invalid_user = User("", 16)  
# register_user(invalid_user)  # ✗ Raises validation error

Advanced Patterns

Conditional Validation

from beartype.vale import Is
from typing import Annotated, Union

def validate_id(obj) -> bool:
    if isinstance(obj, str):
        return obj.isalnum() and len(obj) >= 3
    elif isinstance(obj, int):
        return obj > 0
    return False

FlexibleID = Annotated[Union[str, int], Is[validate_id]]

@beartype
def lookup_item(item_id: FlexibleID) -> str:
    return f"Item {item_id}"

lookup_item("abc123")  # ✓ Valid string ID
lookup_item(42)        # ✓ Valid numeric ID
# lookup_item("ab")    # ✗ Too short
# lookup_item(-1)      # ✗ Negative number

Custom Exception Messages

from beartype.vale import Is
from typing import Annotated

def positive_with_message(x: int) -> bool:
    if x <= 0:
        raise ValueError(f"Expected positive integer, got {x}")
    return True

PositiveInt = Annotated[int, Is[positive_with_message]]

@beartype
def process_positive(value: PositiveInt) -> int:
    return value * 2

try:
    process_positive(-5)
except Exception as e:
    print(f"Validation failed: {e}")

Install with Tessl CLI

npx tessl i tessl/pypi-beartype

docs

core-type-checking.md

door-api.md

exceptions.md

import-hooks.md

index.md

typing-compatibility.md

validators.md

tile.json