Skip to main content

A runtime type validation utility with detailed error reporting.

Project description

Type Enforcer

A runtime type validation utility for Python 3.13+ with detailed error reporting.

This module provides a clean, efficient way to enforce type constraints on data, ensuring that your function inputs, API responses, or configuration files match the expected structure and types.

Features

  • Runtime Validation: Checks types when your code runs, catching errors early.
  • Detailed Errors: Pinpoints exactly where validation failed in nested structures.
  • Complex Types: Supports List, Dict, Tuple, Optional, Union, Literal, Enum, TypedDict, and dataclass.
  • Clean API: Simple enforce(data, expected_type) function for easy use.
  • Introspection Caching: Uses caching for type analysis to improve performance.
  • Python 3.13+: Leverages modern Python features.
  • 100% Test Coverage: Every line of code is thoroughly tested, ensuring reliability and stability.

Why Type Enforcer Is Useful

Safer Data Handling

Python's dynamic typing is flexible but can lead to runtime errors when data doesn't match expectations. Type Enforcer adds a safety layer that validates data structures at critical boundaries in your application.

API Integration

When working with external APIs, responses may not always conform to documentation. Type Enforcer helps validate responses before your code processes them, preventing cascading errors from malformed data.

Better Error Messages

Instead of cryptic AttributeError or TypeError deep in your processing logic, Type Enforcer provides clear, path-based error messages like data.users[0].settings.notifications: Expected bool, got str.

Schema Documentation

TypedDict and dataclass definitions serve as living documentation of your data structures, making code more maintainable and self-documenting.

Gradual Typing

While type annotations help at development time, Type Enforcer extends their value to runtime, offering a bridge between static and dynamic typing that's especially valuable at system boundaries.

Data Transformation

Beyond validation, Type Enforcer can convert compatible types (like dictionaries to dataclasses), simplifying your data pipeline.

Installation

# For end users
pip install divine-type-enforcer

# For development
poetry install

Usage

Import the enforce function and use it to validate data against a type annotation:

from type_enforcer import enforce, ValidationError
from typing import List, Dict, Optional, Union, Literal, TypedDict, Tuple
from enum import Enum
from dataclasses import dataclass

# Basic types
enforce(42, int)
# >> 42
enforce("hello", str)
# >> 'hello'
enforce(True, bool)
# >> True
enforce(3.14, float)
# >> 3.14
enforce(None, type(None))
# >> None

try:
    enforce("not an int", int)
except ValidationError as e:
    print(e)
# >> : Expected int, got str

# Lists
enforce([1, 2, 3], List[int])
# >> [1, 2, 3]

try:
    enforce([1, "not an int", 3], List[int])
except ValidationError as e:
    print(e)
# >> [1]: Expected int, got str

# Dictionaries
enforce({"a": 1, "b": 2}, Dict[str, int])
# >> {'a': 1, 'b': 2}

try:
    enforce({"a": 1, "b": "not an int"}, Dict[str, int])
except ValidationError as e:
    print(e)
# >> [b]: Expected int, got str

# TypedDict
class User(TypedDict):
    name: str
    age: int

enforce({"name": "Alice", "age": 30}, User)
# >> {'name': 'Alice', 'age': 30}

try:
    enforce({"name": "Alice"}, User)
except ValidationError as e:
    print(e)
# >> : Missing required keys: age

# Optional fields
enforce(None, Optional[int])
# >> None
enforce(42, Optional[int])
# >> 42

# Union types
enforce("hello", Union[int, str])
# >> 'hello'
enforce(42, Union[int, str])
# >> 42

try:
    enforce(True, Union[int, str])
except ValidationError as e:
    print(e)
# >> : Value doesn't match any type in Union. Got bool, expected one of: <class 'int'> | <class 'str'>

# Literal types
enforce("small", Literal["small", "medium", "large"])
# >> 'small'
enforce(None, Literal[None, "small", "large"])
# >> None

try:
    enforce("extra-large", Literal["small", "medium", "large"])
except ValidationError as e:
    print(e)
# >> : Expected one of: 'small', 'medium', 'large', got: 'extra-large'

# Tuples
enforce((1, 2, 3), Tuple[int, ...])
# >> (1, 2, 3)
enforce((1, "hello"), Tuple[int, str])
# >> (1, 'hello')

# Enums
class Size(Enum):
    SMALL = "small"
    MEDIUM = "medium"
    LARGE = "large"

enforce(Size.SMALL, Size)
# >> <Size.SMALL: 'small'>
enforce("SMALL", Size)  # Converts string to enum
# >> <Size.SMALL: 'small'>

try:
    enforce("EXTRA_LARGE", Size)
except ValidationError as e:
    print(e)
# >> : Invalid enum value. Valid values: SMALL, MEDIUM, LARGE

# Dataclasses
@dataclass
class Point:
    x: int
    y: int

enforce(Point(1, 2), Point)
# >> Point(x=1, y=2)
enforce({"x": 1, "y": 2}, Point)  # Converts dict to dataclass
# >> Point(x=1, y=2)

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

The project maintains 100% test coverage, which helps ensure stability and correctness as new features are added. Any contributions should include appropriate tests to maintain this coverage level.

Real-World Examples

Check out the examples/ directory for real-world use cases of type-enforcer:

API Response Validation

See examples/api_response_validation.py for a comprehensive example of validating complex API responses. This example shows how to:

  • Define nested TypedDict structures for complex JSON responses
  • Validate responses against these structures
  • Handle validation errors gracefully
  • Work with deeply nested optional fields

This pattern is especially useful when working with third-party APIs where you need to ensure the response matches your expected structure before processing it further.

License

This project is licensed under the MIT License - see the LICENSE file for details.

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

divine_type_enforcer-0.1.11.tar.gz (11.4 kB view details)

Uploaded Source

Built Distribution

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

divine_type_enforcer-0.1.11-py3-none-any.whl (9.2 kB view details)

Uploaded Python 3

File details

Details for the file divine_type_enforcer-0.1.11.tar.gz.

File metadata

  • Download URL: divine_type_enforcer-0.1.11.tar.gz
  • Upload date:
  • Size: 11.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for divine_type_enforcer-0.1.11.tar.gz
Algorithm Hash digest
SHA256 879d46cf7d184e77b83651d29dda0c02ac248c1dd5b6953ed3cbc6073c0ee119
MD5 d289b72141538ca1cea2e44fe1ba2061
BLAKE2b-256 bd20b788a252e3ea834dcba233d770e997d42fbf6a35a030619b33a24e7bd0cf

See more details on using hashes here.

Provenance

The following attestation bundles were made for divine_type_enforcer-0.1.11.tar.gz:

Publisher: pypi-publish.yml on divinescreener/type-enforcer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file divine_type_enforcer-0.1.11-py3-none-any.whl.

File metadata

File hashes

Hashes for divine_type_enforcer-0.1.11-py3-none-any.whl
Algorithm Hash digest
SHA256 0aa4c03cbbd41fb3fb645ec3479d82dde9956b7ba64bef1927e28fe6d5d23018
MD5 5dd38e000a193f50f2cfa6c06181f2b6
BLAKE2b-256 7f556e00657e94f4745aac856894f2dc3ad02d75d3aafa5ad544eb220c5f2007

See more details on using hashes here.

Provenance

The following attestation bundles were made for divine_type_enforcer-0.1.11-py3-none-any.whl:

Publisher: pypi-publish.yml on divinescreener/type-enforcer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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