CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-jsonschema

An implementation of JSON Schema validation for Python

Pending
Overview
Eval results
Files

type-checking.mddocs/

Type Checking

Customizable type checking system for JSON Schema types with built-in type checkers for each draft version and extensibility for custom type definitions. The type system maps JSON Schema types to Python types and validation logic.

Capabilities

TypeChecker

The main class for JSON Schema type validation, supporting both built-in and custom type definitions.

class TypeChecker:
    """
    A type property checker for JSON Schema type keyword validation.
    
    Converts between JSON Schema types and Python types/objects.
    Supports customization and extension of type checking behavior.
    """
    
    def __init__(self, type_checkers=()):
        """
        Initialize type checker.
        
        Parameters:
        - type_checkers: Mapping of type names to checker functions
        """
    
    def is_type(self, instance, type):
        """
        Check if instance is of the specified JSON Schema type.
        
        Parameters:
        - instance: Value to check
        - type: JSON Schema type name
        
        Returns:
        - bool: True if instance is of the specified type
        
        Raises:
        - UndefinedTypeCheck: If type is not defined
        """
    
    def redefine(self, type, fn):
        """
        Create new TypeChecker with redefined type.
        
        Parameters:
        - type: Type name to redefine
        - fn: Type checking function
        
        Returns:
        - TypeChecker: New TypeChecker instance
        """
    
    def redefine_many(self, definitions=()):
        """
        Create new TypeChecker with multiple redefined types.
        
        Parameters:
        - definitions: Dictionary mapping type names to checker functions
        
        Returns:
        - TypeChecker: New TypeChecker instance
        """
    
    def remove(self, *types):
        """
        Create new TypeChecker without specified types.
        
        Parameters:
        - types: Type names to remove
        
        Returns:
        - TypeChecker: New TypeChecker instance
        
        Raises:
        - UndefinedTypeCheck: If any type is not defined
        """

Built-in Type Checkers

Pre-configured type checkers for each JSON Schema draft version.

# Type checkers for each draft
draft202012_type_checker: TypeChecker
draft201909_type_checker: TypeChecker
draft7_type_checker: TypeChecker
draft6_type_checker: TypeChecker
draft4_type_checker: TypeChecker
draft3_type_checker: TypeChecker

Built-in Type Checking Functions

Individual type checking functions for standard JSON Schema types.

def is_array(checker, instance):
    """
    Check if instance is an array (Python list).
    
    Parameters:
    - checker: TypeChecker instance
    - instance: Value to check
    
    Returns:
    - bool: True if instance is a list
    """

def is_bool(checker, instance):
    """
    Check if instance is a boolean.
    
    Parameters:
    - checker: TypeChecker instance  
    - instance: Value to check
    
    Returns:
    - bool: True if instance is a boolean
    """

def is_integer(checker, instance):
    """
    Check if instance is an integer.
    
    Parameters:
    - checker: TypeChecker instance
    - instance: Value to check
    
    Returns:
    - bool: True if instance is an integer (excludes booleans)
    """

def is_null(checker, instance):
    """
    Check if instance is null (Python None).
    
    Parameters:
    - checker: TypeChecker instance
    - instance: Value to check
    
    Returns:
    - bool: True if instance is None
    """

def is_number(checker, instance):
    """
    Check if instance is a number.
    
    Parameters:
    - checker: TypeChecker instance
    - instance: Value to check
    
    Returns:
    - bool: True if instance is numeric (excludes booleans)
    """

def is_object(checker, instance):
    """
    Check if instance is an object (Python dict).
    
    Parameters:
    - checker: TypeChecker instance
    - instance: Value to check
    
    Returns:
    - bool: True if instance is a dictionary
    """

def is_string(checker, instance):
    """
    Check if instance is a string.
    
    Parameters:
    - checker: TypeChecker instance
    - instance: Value to check
    
    Returns:
    - bool: True if instance is a string
    """

def is_any(checker, instance):
    """
    Check if instance is any type (always returns True).
    
    Used for Draft 3 "any" type.
    
    Parameters:
    - checker: TypeChecker instance
    - instance: Value to check
    
    Returns:
    - bool: Always True
    """

Usage Examples

Basic Type Checking

from jsonschema import Draft202012Validator
from jsonschema._types import draft202012_type_checker

# Direct type checking
checker = draft202012_type_checker

print(checker.is_type("hello", "string"))    # True
print(checker.is_type(123, "integer"))       # True
print(checker.is_type(123.5, "number"))      # True
print(checker.is_type([1, 2, 3], "array"))   # True
print(checker.is_type({"a": 1}, "object"))   # True
print(checker.is_type(None, "null"))         # True
print(checker.is_type(True, "boolean"))      # True

# Type checking in validation
schema = {"type": "integer"}
validator = Draft202012Validator(schema)

validator.validate(42)      # Valid
validator.validate(42.0)    # Valid (Draft 6+ allows integers as floats)
validator.validate("42")    # Invalid - string, not integer

Custom Type Definitions

from jsonschema import Draft202012Validator, create
from jsonschema._types import TypeChecker, draft202012_type_checker
import decimal

# Define custom type checker function
def is_decimal(checker, instance):
    """Check if instance is a decimal number."""
    return isinstance(instance, decimal.Decimal)

def is_positive_number(checker, instance):
    """Check if instance is a positive number."""
    return (isinstance(instance, (int, float)) and 
            not isinstance(instance, bool) and 
            instance > 0)

# Create custom type checker
custom_type_checker = draft202012_type_checker.redefine_many({
    "decimal": is_decimal,
    "positive-number": is_positive_number
})

# Create validator with custom types
validator_class = create(
    meta_schema=Draft202012Validator.META_SCHEMA,
    validators=Draft202012Validator.VALIDATORS,
    type_checker=custom_type_checker
)

# Use custom types in schema
schema = {
    "type": "object",
    "properties": {
        "price": {"type": "decimal"},
        "quantity": {"type": "positive-number"}
    }
}

validator = validator_class(schema)

# Test custom types
import decimal
test_data = {
    "price": decimal.Decimal("19.99"),
    "quantity": 5
}

validator.validate(test_data)  # Should pass

# Invalid data
invalid_data = {
    "price": 19.99,  # float, not Decimal
    "quantity": -1   # not positive
}

errors = list(validator.iter_errors(invalid_data))
for error in errors:
    print(f"Type error: {error.message}")

Extending Existing Type Checkers

from jsonschema._types import draft202012_type_checker
from collections import namedtuple

# Define custom object type that includes namedtuples
def is_object_or_namedtuple(checker, instance):
    """Check if instance is dict or namedtuple."""
    return (isinstance(instance, dict) or 
            (hasattr(instance, '_fields') and 
             hasattr(instance, '_asdict')))

# Extend type checker
extended_checker = draft202012_type_checker.redefine(
    "object", is_object_or_namedtuple
)

# Test with namedtuple
Person = namedtuple('Person', ['name', 'age'])
person = Person('Alice', 30)

print(extended_checker.is_type(person, "object"))  # True
print(draft202012_type_checker.is_type(person, "object"))  # False

Removing Type Support

from jsonschema._types import draft202012_type_checker

# Create type checker without null support
no_null_checker = draft202012_type_checker.remove("null")

try:
    no_null_checker.is_type(None, "null")
except UndefinedTypeCheck as e:
    print(f"Type undefined: {e}")

# Available types
print("Available types:", list(no_null_checker._type_checkers.keys()))

Draft-Specific Type Differences

from jsonschema._types import (
    draft3_type_checker, 
    draft4_type_checker, 
    draft6_type_checker
)

# Draft 3 supports "any" type
print("Draft 3 types:", list(draft3_type_checker._type_checkers.keys()))
# Includes: 'any', 'array', 'boolean', 'integer', 'null', 'number', 'object', 'string'

# Draft 4+ removes "any" type  
print("Draft 4 types:", list(draft4_type_checker._type_checkers.keys()))
# Excludes 'any'

# Draft 6+ changes integer handling
print(draft4_type_checker.is_type(42.0, "integer"))  # False
print(draft6_type_checker.is_type(42.0, "integer"))  # True (if 42.0.is_integer())

Type Checking in Custom Validators

from jsonschema import Draft202012Validator
from jsonschema._types import TypeChecker

# Create validator with custom type checking
def is_non_empty_string(checker, instance):
    """Check if instance is a non-empty string."""
    return isinstance(instance, str) and len(instance) > 0

custom_checker = TypeChecker().redefine_many({
    "string": is_string,
    "non-empty-string": is_non_empty_string,
    "array": is_array,
    "object": is_object,
    "number": is_number,
    "integer": is_integer,
    "boolean": is_bool,
    "null": is_null
})

# Import required items
from jsonschema._types import is_string, is_array, is_object, is_number, is_integer, is_bool, is_null

# Use in validator
validator = Draft202012Validator(
    {"type": "non-empty-string"},
    type_checker=custom_checker
)

validator.validate("hello")  # Valid
try:
    validator.validate("")   # Invalid - empty string
except ValidationError as e:
    print(f"Type error: {e.message}")

Type Checking Function Signature

All type checking functions must follow this signature:

def my_type_checker(checker, instance):
    """
    Custom type checking function.
    
    Parameters:
    - checker: The TypeChecker instance calling this function
    - instance: The value to type-check
    
    Returns:
    - bool: True if instance is of this type, False otherwise
    """
    # Custom type checking logic here
    return isinstance(instance, MyCustomType)

Install with Tessl CLI

npx tessl i tessl/pypi-jsonschema

docs

core-validation.md

error-handling.md

format-validation.md

index.md

type-checking.md

validator-creation.md

validators.md

tile.json