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
========
:pep:`589` defines syntax
for declaring a TypedDict with all required keys and syntax for defining
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
as potentially-missing. This PEP introduces two new syntaxes:
``Required[]`` which can be used on individual items of a
:pep:`589` defines notation
for declaring a TypedDict with all required keys and notation for defining
a TypedDict with :pep:`all potentially-missing keys <589#totality>`, however it
does not provide a mechanism to declare some keys as required and others
as potentially-missing. This PEP introduces two new notations:
``Required[]``, which can be used on individual items of a
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.
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
==========
@ -73,7 +78,7 @@ not support inheritance:
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
customary in other languages like TypeScript:
@ -133,6 +138,7 @@ potentially-missing key:
It is an error to use ``Required[]`` or ``NotRequired[]`` in any
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
items where it is redundant, to enable additional explicitness if desired:
@ -152,6 +158,9 @@ same time:
title: str
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>`
for TypedDict also supports
@ -291,7 +300,7 @@ required, define a ``total=False`` TypedDict
and mark those few keys that are required with ``Required[]``.
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
``Required[]`` or ``NotRequired[]`` alongside ``Optional[]``
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
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
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
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.
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
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
any shortform syntax. Future PEPs may reconsider introducing this
or other shortform syntax options.
any short-form notation. Future PEPs may reconsider introducing this
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
typing world: covariant, contravariant, and invariant:
@ -578,7 +587,7 @@ Difficult to implement
''''''''''''''''''''''
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]_
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”.
---------------------------------------------------------------------------
``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`.
``Optional[]`` is too ubiquitous to deprecate, although use of it
*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”