PEP 728: Address Review Feedback (#3697)

This commit is contained in:
Zixuan Li 2024-03-14 11:06:14 -04:00 committed by GitHub
parent a8cc9106bc
commit 221d07cb9b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 56 additions and 6 deletions

View File

@ -252,7 +252,11 @@ be rejected by the type checker.
__extra_items__: str # A regular key
a: Movie = {"name": "Blade Runner", "__extra_items__": None} # Not OK. 'None' is incompatible with 'str'
b: Movie = {"name": "Blade Runner", "other_extra_key": None} # OK
b: Movie = {
"name": "Blade Runner",
"__extra_items__": "A required regular key",
"other_extra_key": None,
} # OK
Here, ``"__extra_items__"`` in ``a`` is a regular key defined on ``Movie`` where
its value type is narrowed from ``ReadOnly[str | None]`` to ``str``,
@ -530,6 +534,40 @@ between this type and a closed TypedDict type::
extra_int = not_closed # Not OK. 'ReadOnly[object]' implicitly on 'MovieNotClosed' is not consistent with 'int' for item '__extra_items__'
not_closed = extra_int # OK
Interaction with Constructors
-----------------------------
TypedDicts that allow extra items of type ``T`` also allow arbitrary keyword
arguments of this type when constructed by calling the class object::
class OpenMovie(TypedDict):
name: str
OpenMovie(name="No Country for Old Men") # OK
OpenMovie(name="No Country for Old Men", year=2007) # Not OK. Unrecognized key
class ExtraMovie(TypedDict, closed=True):
name: str
__extra_items__: int
ExtraMovie(name="No Country for Old Men") # OK
ExtraMovie(name="No Country for Old Men", year=2007) # OK
ExtraMovie(
name="No Country for Old Men",
language="English",
) # Not OK. Wrong type for extra key
# This implies '__extra_items__: Never',
# so extra keyword arguments produce an error
class ClosedMovie(TypedDict, closed=True):
name: str
ClosedMovie(name="No Country for Old Men") # OK
ClosedMovie(
name="No Country for Old Men",
year=2007,
) # Not OK. Extra items not allowed
Interaction with Mapping[KT, VT]
--------------------------------
@ -571,14 +609,17 @@ prohibits additional required keys in its structural subtypes, we can determine
if the TypedDict type and its structural subtypes will ever have any required
key during static analysis.
If there is no required key, the TypedDict type is consistent with ``dict[KT,
VT]`` and vice versa if all items on the TypedDict type satisfy the following
conditions:
The TypedDict type is consistent with ``dict[str, VT]`` if all items on the
TypedDict type satisfy the following conditions:
- ``VT`` is consistent with the value type of the item
- The value type of the item is consistent with ``VT``
- The item is not read-only.
- The item is not required.
For example::
class IntDict(TypedDict, closed=True):
@ -601,6 +642,15 @@ In this case, methods that are previously unavailable on a TypedDict are allowed
reveal_type(not_required_num.popitem()) # OK. Revealed type is tuple[str, int]
However, ``dict[str, VT]`` is not necessarily consistent with a TypedDict type,
because such dict can be a subtype of dict::
class CustomDict(dict[str, int]):
...
not_a_regular_dict: CustomDict = {"num": 1}
int_dict: IntDict = not_a_regular_dict # Not OK
How to Teach this
=================
@ -652,8 +702,8 @@ Supporting ``TypedDict(extra=type)``
------------------------------------
While this design is potentially viable, there are several partially addressable
concerns to consider. Adding everything up, it is slightly less favorable than
the current proposal.
concerns to consider. The author of this PEP thinks that it is slightly less
favorable than the current proposal.
- Usability of forward reference
As in the functional syntax, using a quoted type or a type alias will be