A tiny validator built on get_type_hints
The checker walks the hints with get_origin and get_args. Missing fields without defaults are reported; fields with defaults may be left out.
Hints are ordinary data that Python keeps, so a program can read them: __annotations__, typing.get_type_hints, get_origin and get_args. Dataclasses and Pydantic do exactly this, and so you can write a tiny validator yourself.
Change the code and press Run (Ctrl+Enter). Predict what will happen first, then break it on purpose and read what changes. Your edits are saved and match the lesson page.
Ready for more? This phase has 5 hands-on exercises with automatic checks.
Practice questions
Write the code in the editor, run it, then open the model answer to compare.
Print the resolved type hints (use get_type_hints) of a function def f(a: int, b: list[str] = []) -> bool.
Write field_names(cls) that returns the list of annotated field names of a class, and call it for a small class.
Create a Pydantic model User with name: str and age: int, build one from age="42", and print user.age + 1.
Explain it without notes
Where does Python store type hints, and how should you read them?
What is the difference between how a dataclass and Pydantic use the same hints?
What is a forward reference and what changed in Python 3.14?
How do type hints help with LLM tool calling?
Why can reading __annotations__ fail or mislead, and what do you use instead? What changes on 3.14?
Expected output
raw: {'id': <class 'int'>, 'customer': <class 'str'>, 'tags': list[str], 'note': str | None}
resolved: {'id': <class 'int'>, 'customer': <class 'str'>, 'tags': list[str], 'note': str | None}
[]
["id: expected <class 'int'>, got '1'", 'customer: missing', "tags: expected list[str], got ['a', 2]", 'note: expected str | None, got 5']