pythonpydantictypeddict

Runtime checking for extra keys in TypedDict


This answer tells how to validated a TypedDict at runtime, but it won't catch the case of an extra key being present.

For example, this doesn't throw. How can I make it throw?

from typing import Any, TypeVar

from pydantic import TypeAdapter
from typing_extensions import TypedDict

T = TypeVar('T')

def runtime_check_typed_dict(TypedDictClass: type[T], object_: Any) -> T:
    TypedDictValidator = TypeAdapter(TypedDictClass)
    return TypedDictValidator.validate_python(object_, strict=True)


class MyThing(TypedDict):
    key: str

obj_: Any = {'key': 'stuff', 'extra': 'this should throw!'}

runtime_check_typed_dict(MyThing, obj_)

Solution

  • My Answer

    My Example

    from pprint import pprint
    from typing import Any, TypeVar
    
    from pydantic import BaseModel, ConfigDict, TypeAdapter, ValidationError
    from typing_extensions import TypedDict
    
    T = TypeVar('T')
    
    
    def runtime_check_typed_dict(TypedDictClass: type[T], object_: Any) -> T:
        TypedDictValidator = TypeAdapter(TypedDictClass)
        return TypedDictValidator.validate_python(object_, strict=True)
    
    
    class MyThing(TypedDict):
        key: str
    
    
    obj_ = {'key': 'stuff', 'extra': 'this should throw!'}
    
    
    ### 1: TypedDict
    
    
    # https://docs.pydantic.dev/2.4/usage/strict_mode/#dataclasses-and-typeddict
    MyThing.__pydantic_config__ = ConfigDict(extra='forbid')
    try:
        runtime_check_typed_dict(MyThing, obj_)
    except ValidationError as exc:
        pprint(exc.errors())
        # > [{'input': 'this should throw!',
        # >   'loc': ('extra',),
        # >   'msg': 'Extra inputs are not permitted',
        # >   'type': 'extra_forbidden',
        # >   'url': 'https://errors.pydantic.dev/2.4/v/extra_forbidden'}]
    
    
    ### 2: BaseModel
    
    
    class MyThing2(BaseModel):
        model_config = ConfigDict(extra='forbid')
        key: str
    
    
    try:
        runtime_check_typed_dict(MyThing2, obj_)
    except ValidationError as exc:
        pprint(exc.errors())
        # >[{'input': 'this should throw!',
        # >  'loc': ('extra',),
        # >  'msg': 'Extra inputs are not permitted',
        # >  'type': 'extra_forbidden',
        # >  'url': 'https://errors.pydantic.dev/2.4/v/extra_forbidden'}]