PEP 655: Clarify there are no grammar changes or runtime enforcement. (#2388)

Co-authored-by: CAM Gerlach <CAM.Gerlach@Gerlach.CAM>
This commit is contained in:
David Foster 2022-03-09 09:57:04 -08:00 committed by GitHub
parent 78e67c82b6
commit 20f7ce8aa7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 27 additions and 18 deletions

View File

@ -14,16 +14,21 @@ Post-History: 31-Jan-2021, 11-Feb-2021, 20-Feb-2021, 26-Feb-2021, 17-Jan-2022, 2
Abstract Abstract
======== ========
:pep:`589` defines syntax :pep:`589` defines notation
for declaring a TypedDict with all required keys and syntax for defining for declaring a TypedDict with all required keys and notation for defining
a TypedDict with :pep:`all potentially-missing keys <589#totality>` however it a TypedDict with :pep:`all potentially-missing keys <589#totality>`, however it
does not provide any syntax to declare some keys as required and others does not provide a mechanism to declare some keys as required and others
as potentially-missing. This PEP introduces two new syntaxes: as potentially-missing. This PEP introduces two new notations:
``Required[]`` which can be used on individual items of a ``Required[]``, which can be used on individual items of a
TypedDict to mark them as required, and TypedDict to mark them as required, and
``NotRequired[]`` which can be used on individual items ``NotRequired[]``, which can be used on individual items
to mark them as potentially-missing. to mark them as potentially-missing.
This PEP makes no Python grammar changes. Correct usage
of required and potentially-missing keys of TypedDicts is intended to be
enforced only by static type checkers and need not be enforced by
Python itself at runtime.
Motivation Motivation
========== ==========
@ -73,7 +78,7 @@ not support inheritance:
Rationale Rationale
========= =========
One might think it unusual to propose syntax that prioritizes marking One might think it unusual to propose notation that prioritizes marking
*required* keys rather than *potentially-missing* keys, as is *required* keys rather than *potentially-missing* keys, as is
customary in other languages like TypeScript: customary in other languages like TypeScript:
@ -133,6 +138,7 @@ potentially-missing key:
It is an error to use ``Required[]`` or ``NotRequired[]`` in any It is an error to use ``Required[]`` or ``NotRequired[]`` in any
location that is not an item of a TypedDict. location that is not an item of a TypedDict.
Type checkers must enforce this restriction.
It is valid to use ``Required[]`` and ``NotRequired[]`` even for It is valid to use ``Required[]`` and ``NotRequired[]`` even for
items where it is redundant, to enable additional explicitness if desired: items where it is redundant, to enable additional explicitness if desired:
@ -152,6 +158,9 @@ same time:
title: str title: str
year: NotRequired[Required[int]] # ERROR year: NotRequired[Required[int]] # ERROR
Type checkers must enforce this restriction.
The runtime implementations of ``Required[]`` and ``NotRequired[]``
may also enforce this restriction.
The :pep:`alternative functional syntax <589#alternative-syntax>` The :pep:`alternative functional syntax <589#alternative-syntax>`
for TypedDict also supports for TypedDict also supports
@ -291,7 +300,7 @@ required, define a ``total=False`` TypedDict
and mark those few keys that are required with ``Required[]``. and mark those few keys that are required with ``Required[]``.
If some items accept ``None`` in addition to a regular value, it is If some items accept ``None`` in addition to a regular value, it is
recommended that the ``TYPE|None`` syntax be preferred over recommended that the ``TYPE|None`` notation be preferred over
``Optional[TYPE]`` for marking such item values, to avoid using ``Optional[TYPE]`` for marking such item values, to avoid using
``Required[]`` or ``NotRequired[]`` alongside ``Optional[]`` ``Required[]`` or ``NotRequired[]`` alongside ``Optional[]``
within the same TypedDict definition: within the same TypedDict definition:
@ -397,7 +406,7 @@ Special syntax around the *key* of a TypedDict item
opt1?: str # may not exist, but if exists, value is string opt1?: str # may not exist, but if exists, value is string
opt2: Optional[str] # always exists, but may have None value opt2: Optional[str] # always exists, but may have None value
This syntax would require Python grammar changes and it is not This notation would require Python grammar changes and it is not
believed that marking TypedDict items as required or potentially-missing believed that marking TypedDict items as required or potentially-missing
would meet the high bar required to make such grammar changes. would meet the high bar required to make such grammar changes.
@ -407,7 +416,7 @@ would meet the high bar required to make such grammar changes.
Optional[opt1]: str # may not exist, but if exists, value is string Optional[opt1]: str # may not exist, but if exists, value is string
opt2: Optional[str] # always exists, but may have None value opt2: Optional[str] # always exists, but may have None value
This syntax causes ``Optional[]`` to take on different meanings depending This notation causes ``Optional[]`` to take on different meanings depending
on where it is positioned, which is inconsistent and confusing. on where it is positioned, which is inconsistent and confusing.
Also, “lets just not put funny syntax before the colon.” [1]_ Also, “lets just not put funny syntax before the colon.” [1]_
@ -441,12 +450,12 @@ Such operators could be implemented on ``type`` via the ``__pos__``,
``__neg__`` and ``__invert__`` special methods without modifying the ``__neg__`` and ``__invert__`` special methods without modifying the
grammar. grammar.
It was decided that it would be prudent to introduce longform syntax It was decided that it would be prudent to introduce long-form notation
(i.e. ``Required[]`` and ``NotRequired[]``) before introducing (i.e. ``Required[]`` and ``NotRequired[]``) before introducing
any shortform syntax. Future PEPs may reconsider introducing this any short-form notation. Future PEPs may reconsider introducing this
or other shortform syntax options. or other short-form notation options.
Note when reconsidering introducing this shortform syntax that Note when reconsidering introducing this short-form notation that
``+``, ``-``, and ``~`` already have existing meanings in the Python ``+``, ``-``, and ``~`` already have existing meanings in the Python
typing world: covariant, contravariant, and invariant: typing world: covariant, contravariant, and invariant:
@ -578,7 +587,7 @@ Difficult to implement
'''''''''''''''''''''' ''''''''''''''''''''''
Eric Traut from the Pyright type checker team has stated that Eric Traut from the Pyright type checker team has stated that
implementing a ``Union[..., Missing]``-style syntax would be implementing a ``Union[..., Missing]``-style notation would be
difficult. [2]_ difficult. [2]_
Introduces a second null-like value into Python Introduces a second null-like value into Python
@ -596,8 +605,8 @@ distinguishing between its analogous constants ``null`` and
Replace Optional with Nullable. Repurpose Optional to mean “optional item”. Replace Optional with Nullable. Repurpose Optional to mean “optional item”.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
``Optional[]`` is too ubiquitous to deprecate. Although use of it ``Optional[]`` is too ubiquitous to deprecate, although use of it
*may* fade over time in favor of the ``T|None`` syntax specified by :pep:`604`. *may* fade over time in favor of the ``T|None`` notation specified by :pep:`604`.
Change Optional to mean “optional item” in certain contexts instead of “nullable” Change Optional to mean “optional item” in certain contexts instead of “nullable”