From 795214108bdca3342c7c6849729fc29d8e684fcb Mon Sep 17 00:00:00 2001 From: David Foster Date: Fri, 28 Jan 2022 12:11:29 -0500 Subject: [PATCH] PEP 655: Integrate feedback circa Jan 2022 (#2287) --- pep-0655.rst | 61 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/pep-0655.rst b/pep-0655.rst index d39995f98..62528d14a 100644 --- a/pep-0655.rst +++ b/pep-0655.rst @@ -8,7 +8,7 @@ Type: Standards Track Content-Type: text/x-rst Created: 30-Jan-2021 Python-Version: 3.11 -Post-History: 31-Jan-2021, 11-Feb-2021, 20-Feb-2021, 26-Feb-2021, 17-Jan-2022 +Post-History: 31-Jan-2021, 11-Feb-2021, 20-Feb-2021, 26-Feb-2021, 17-Jan-2022, 28-Jan-2022 Abstract @@ -156,6 +156,11 @@ in any nesting order: title: str year: Annotated[NotRequired[int], ValueRange(-9999, 9999)] # ok +In particular allowing ``Annotated[]`` to be the outermost annotation +for an item allows better interoperability with non-typing uses of +annotations, which may always want ``Annotated[]`` as the outermost annotation. +[3]_ + Interaction with ``get_type_hints()`` ------------------------------------- @@ -260,14 +265,61 @@ No: # ick; avoid using both Optional and NotRequired owner: NotRequired[Optional[str]] +Usage in Python <3.11 +--------------------- + +If your code supports Python <3.11 and wishes to use ``Required[]`` or +``NotRequired[]`` then it should use ``typing_extensions.TypedDict`` rather +than ``typing.TypedDict`` because the latter will not understand +``(Not)Required[]``. In particular ``__required_keys__`` and +``__optional_keys__`` on the resulting TypedDict type will not be correct: + +Yes (Python 3.11+ only): + +:: + + from typing import NotRequired, TypedDict + + class Dog(TypedDict): + name: str + owner: NotRequired[str|None] + +Yes (Python <3.11 and 3.11+): + +:: + + from __future__ import annotations # for Python 3.7-3.9 + + from typing_extensions import NotRequired, TypedDict # for Python <3.11 with (Not)Required + + class Dog(TypedDict): + name: str + owner: NotRequired[str|None] + +No (Python <3.11 and 3.11+): + +:: + + from typing import TypedDict # oops: should import from typing_extensions instead + from typing_extensions import NotRequired + + class Movie(TypedDict): + title: str + year: NotRequired[int] + + assert Movie.__required_keys__ == frozenset({'title', 'year'}) # yikes + assert Movie.__optional_keys__ == frozenset() # yikes + Reference Implementation ======================== The `mypy `__ -`0.930 `__ -and `pyright `__ -`1.1.117 `__ +`0.930 `__, +`pyright `__ +`1.1.117 `__, +and `pyanalyze `__ +`0.4.0 `__ type checkers support ``Required`` and ``NotRequired``. A reference implementation of the runtime component is provided in the @@ -539,6 +591,7 @@ References .. [2] https://mail.python.org/archives/list/typing-sig@python.org/message/S2VJSVG6WCIWPBZ54BOJPG56KXVSLZK6/ +.. [3] https://bugs.python.org/issue46491 Copyright =========