Metadata-Version: 2.4
Name: divine-type-enforcer
Version: 0.1.2
Summary: A runtime type validation utility with detailed error reporting.
Author-email: DIVINE <admin@divine.sh>
License: MIT License
        
        Copyright (c) 2025 DIVINE
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Homepage, https://github.com/codebydivine/type-enforcer
Project-URL: Issues, https://github.com/codebydivine/type-enforcer/issues
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.13
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.13
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
Requires-Dist: python-dotenv>=1.0.0; extra == "dev"
Requires-Dist: pre-commit>=3.5.0; extra == "dev"
Requires-Dist: ruff>=0.8.0; extra == "dev"
Requires-Dist: mypy>=1.14.0; extra == "dev"
Dynamic: license-file

# 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

```bash
pip install divine-type-enforcer
```

## Usage

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

```python
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`](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](LICENSE) file for details.
