classification
Title: TypedDict: no way to tell which (if any) keys are optional at runtime
Type: Stage: resolved
Components: Library (Lib) Versions: Python 3.8
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: Zac Hatfield-Dodds, levkivskyi
Priority: normal Keywords: patch

Created on 2019-11-18 00:53 by Zac Hatfield-Dodds, last changed 2019-11-24 13:06 by levkivskyi. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 17214 merged Zac Hatfield-Dodds, 2019-11-18 06:21
Messages (1)
msg356836 - (view) Author: Zac Hatfield-Dodds (Zac Hatfield-Dodds) * Date: 2019-11-18 00:53
Consider the following cases:

```python
class A(typing.TypedDict):
    a: int  # a is required

class B(A, total=False):
    b: bool  # a is required, b is optional

class C(B):
    c: str  # a is required, b is optional, c is required again
```

PEP-589 is clear about the semantics, and this is obvious enough when reading the code.  At runtime the __annotations__ attribute of each class gives us the set of allowed keys and the type of each corresponding value, but we have a problem:

- C has __total__==True, but b is not actually required.
- B has __total__==False, but a *is* required.
- I can't see any way to get the parent classes of a TypedDict class!

The _TypedDictMeta metaclass updates the attributes, but leaves no record of the parent type - at runtime A, B, and C all appear to inherit directly from dict.

After discussion on the typing-sig mailing list, I propose to add __required_keys__ and __optional_keys__ attributes to TypedDict subclasses, as frozensets of strings.

This will be very useful for Hypothesis' `from_type()` strategy, as well as for type-based validation frameworks like pydantic or typeguard.
History
Date User Action Args
2019-11-24 13:06:26levkivskyisetstatus: open -> closed
resolution: fixed
stage: patch review -> resolved
2019-11-18 06:21:21Zac Hatfield-Doddssetkeywords: + patch
stage: patch review
pull_requests: + pull_request16717
2019-11-18 00:53:54Zac Hatfield-Doddscreate