We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Structural Typing and the Hard Parts step 16 of 24
Annotated: metadata the type checker deliberately ignores
Annotated[int, Gt(0)] constrains nothing. It is an int to every type
checker in existence. The metadata is inert unless some runtime library goes
looking for it.
That is not a defect — it is the design. Annotated[T, ...] is by
definition assignable exactly where T is, which is what lets FastAPI put
Depends(...), pydantic put Field(...) and typer put Option(...) into
annotations without any of them needing checker support. The mistake is
believing the checker is enforcing them.
Verified, so you do not have to wonder: with Port = Annotated[int, "1-65535"], passing 70000 produces no error; passing "80" produces
arg-type. The int is enforced; the range is not.
The mechanics that actually bite
-
get_type_hints(fn)stripsAnnotatedmetadata. You must passinclude_extras=Trueor you will get back a bareintand wonder where yourBoundswent. This problem asserts both results. -
Metadata is read off
__metadata__on the annotation object. -
Order matters for equality (
Annotated[int, A, B] != Annotated[int, B, A]) and duplicates are not de-duplicated. -
Nested
Annotatedflattens innermost-first — but not through a PEP 695typealias. Use a plain assignment alias (Port = Annotated[...]) when you intend the metadata to be visible; atype Port = Annotated[...]statement hides it behind aTypeAliasType.
Your task
Implement a decorator that makes the metadata mean something at runtime:
def check_bounds[**P, R](fn: Callable[P, R]) -> Callable[P, R]
At decoration time, read get_type_hints(fn, include_extras=True) and
inspect.signature(fn). At call time, signature.bind(*args, **kwargs),
apply_defaults(), and for each bound argument check every Bounds object
in that parameter’s __metadata__. Out of range raises
ValueError(f"{name}={value} outside [{lo}, {hi}]")
Also implement:
def metadata_visible(param: str) -> tuple[bool, bool]
returning (does plain get_type_hints keep __metadata__, does include_extras) for the named parameter of bind.
def solve(ports: list[int], backlogs: list[int]) -> dict[str, object]
zips the two lists, calls bind(port, backlog) in a try, and appends
either the result or f"rejected:{exc}". Returns
{"results", "plain_has_metadata", "extras_has_metadata"}.
Parameters are validated in signature order, so an out-of-range port
is reported even when backlog is also bad.
Two PEPs not to teach as available
PEP 746 (type-checking Annotated metadata against the annotated type) and
PEP 835 are both Draft. Today, if you want the metadata validated, a
runtime library — or the decorator you just wrote — has to do it.
Loading visualization…
Stuck?
Python reference solution
Sign in to attempt this problem and reveal the reference solution.