You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Guidance needed: how to narrow unions of TypedDicts? #18543
However, a common use case (for me) of a TypedDict is to allow external code (e.g. REST API input) to be deserialized into a dict and refined at runtime into a TypedDict -- which implies the the design requirement to have a branded field (e.g. tag) must now exist in our public facing API.
This could work in some cases, but consider something like this:
from __future__ importannotationsfromtypingimportList, TypedDictclassPolicy(TypedDict):
name: strclassCombinedORPolicy(TypedDict):
OR: List[Policy]
classCombinedANDPolicy(TypedDict):
AND: List[Policy]
defprint_policy(policy: CombinedANDPolicy|CombinedORPolicy|Policy) ->None:
if'OR'inpolicy:
allowed_policy_names=' '.join([p['name'] forpinpolicy['OR']])
print(f"Can match _any_ of the following: {allowed_policy_names}")
elif'AND'inpolicy:
allowed_policy_names=' '.join([p['name'] forpinpolicy['AND']])
print(f"Must match _all_ the following: {allowed_policy_names}")
else:
print(f"Must be exactly {policy['name']}")
# pretend this is an API endpoint or somethingprint_policy({'name': 'role:is_admin'})
#13838 being closed seems to imply this is possible but i'm still having trouble.
Here's the current mypy (1.14.1) output:
test.py: note: In function "print_policy":
test.py:16:68: error: TypedDict "CombinedANDPolicy" has no key "OR" [typeddict-item]
test.py:16:68: error: TypedDict "Policy" has no key "OR" [typeddict-item]
test.py:19:68: error: TypedDict "Policy" has no key "AND" [typeddict-item]
Found 3 errors in 1 file (checked 1 source file)
The solution as I understand is either:
force an API change (e.g. print_policy({'name': 'role:is_admin', 'tag': 'root-policy'}))
use cast (e.g. policy = cast(CombinedANDPolicy, policy)
Is there anything more idiomatic i'm missing?
(I searched the tracker but wasn't able to find discission of this specifically, but I think this is related: #7981#12098#11080)
Is there a stance on this yet? Is this is a goal or non-goal of mypy? Thanks!
from __future__ importannotationsfromtypingimportList, TypedDict, final@finalclassPolicy(TypedDict):
name: str@finalclassCombinedORPolicy(TypedDict):
OR: List[Policy]
@finalclassCombinedANDPolicy(TypedDict):
AND: List[Policy]
defprint_policy(policy: CombinedANDPolicy|CombinedORPolicy|Policy) ->None:
if'OR'inpolicy:
allowed_policy_names=' '.join([p['name'] forpinpolicy['OR']])
print(f"Can match _any_ of the following: {allowed_policy_names}")
elif'AND'inpolicy:
allowed_policy_names=' '.join([p['name'] forpinpolicy['AND']])
print(f"Must match _all_ the following: {allowed_policy_names}")
else:
print(f"Must be exactly {policy['name']}")
# pretend this is an API endpoint or somethingprint_policy({'name': 'role:is_admin'})
Activity
A5rocks commentedon Jan 27, 2025
Adding
@finalto all TypedDicts makes this work. See also #15697.A5rocks commentedon Jan 27, 2025
For reference, I checked:
and it passes without mypy complaining.
magicmark commentedon Jan 27, 2025
Brilliant, thanks! I might send a PR to add this to the docs here https://mypy.readthedocs.io/en/stable/typed_dict.html#unions-of-typeddicts
[docs] Add example of using `@final` with TypedDict