Skip to content

Commit 5dd2161

Browse files
gh-137840: Document PEP 728 (#149207)
1 parent ed99680 commit 5dd2161

2 files changed

Lines changed: 70 additions & 6 deletions

File tree

Doc/library/typing.rst

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2792,6 +2792,37 @@ types.
27922792
y: int
27932793
z: int
27942794

2795+
By default, a ``TypedDict`` is open, meaning that it may contain additional keys
2796+
at runtime beyond those defined in the class body. The *closed* class argument can
2797+
be used to control this; if ``closed=True``, the ``TypedDict`` cannot contain additional keys.
2798+
2799+
::
2800+
2801+
class ClosedPoint(TypedDict, closed=True):
2802+
x: int
2803+
y: int
2804+
2805+
class ClosedPoint3D(ClosedPoint): # type checker error: cannot add keys to a closed TypedDict
2806+
z: int
2807+
2808+
Setting ``closed=False`` explicitly requests the default open behavior. If the argument is not
2809+
passed, this state is inherited from the parent class.
2810+
2811+
In addition to being open or closed, a ``TypedDict`` can also be configured to have extra items.
2812+
If the *extra_items* class argument is set to a type, the ``TypedDict`` can contain arbitrary
2813+
additional keys, but the values of those keys must be of the specified type.
2814+
2815+
::
2816+
2817+
class ExtraItemsPoint(TypedDict, extra_items=int):
2818+
x: int
2819+
y: int
2820+
2821+
point: ExtraItemsPoint = {'x': 1, 'y': 2, 'anything': 3} # OK
2822+
2823+
The *extra_items* argument is also inherited through subclassing. It is unset
2824+
by default, and it may not be used together with the *closed* argument.
2825+
27952826
A ``TypedDict`` cannot inherit from a non-\ ``TypedDict`` class,
27962827
except for :class:`Generic`. For example::
27972828

@@ -2825,8 +2856,8 @@ types.
28252856
group: list[T]
28262857

28272858
A ``TypedDict`` can be introspected via annotations dicts
2828-
(see :ref:`annotations-howto` for more information on annotations best practices),
2829-
:attr:`__total__`, :attr:`__required_keys__`, and :attr:`__optional_keys__`.
2859+
(see :ref:`annotations-howto` for more information on annotations best practices)
2860+
and the following attributes:
28302861

28312862
.. attribute:: __total__
28322863

@@ -2896,8 +2927,6 @@ types.
28962927
``__required_keys__`` and ``__optional_keys__`` rely on may not work
28972928
properly, and the values of the attributes may be incorrect.
28982929

2899-
Support for :data:`ReadOnly` is reflected in the following attributes:
2900-
29012930
.. attribute:: __readonly_keys__
29022931

29032932
A :class:`frozenset` containing the names of all read-only keys. Keys
@@ -2912,6 +2941,14 @@ types.
29122941

29132942
.. versionadded:: 3.13
29142943

2944+
.. attribute:: __closed__
2945+
2946+
The value of the *closed* class argument. It can be ``True``, ``False``, or :data:`None`.
2947+
2948+
.. attribute:: __extra_items__
2949+
2950+
The value of the *extra_items* class argument. It can be a valid type or :data:`NoExtraItems`.
2951+
29152952
See the `TypedDict <https://typing.python.org/en/latest/spec/typeddict.html#typeddict>`_ section in the typing documentation for more examples and detailed rules.
29162953

29172954
.. versionadded:: 3.8
@@ -2931,7 +2968,10 @@ types.
29312968
Removed support for the keyword-argument method of creating ``TypedDict``\ s.
29322969

29332970
.. versionchanged:: 3.13
2934-
Support for the :data:`ReadOnly` qualifier was added.
2971+
Support for the :data:`ReadOnly` qualifier was added. See :pep:`705`.
2972+
2973+
.. versionchanged:: next
2974+
Support for the *closed* and *extra_items* class arguments was added. See :pep:`728`.
29352975

29362976

29372977
Protocols
@@ -3679,6 +3719,21 @@ Introspection helpers
36793719

36803720
.. versionadded:: 3.13
36813721

3722+
.. data:: NoExtraItems
3723+
3724+
A :class:`sentinel` object used to indicate that a :class:`TypedDict`
3725+
does not have the *extra_items* class argument.
3726+
3727+
.. doctest::
3728+
3729+
>>> from typing import TypedDict, NoExtraItems
3730+
>>> class Point(TypedDict):
3731+
... x: int
3732+
... y: int
3733+
...
3734+
>>> Point.__extra_items__ is NoExtraItems
3735+
True
3736+
36823737
Constant
36833738
--------
36843739

Doc/whatsnew/3.15.rst

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ Summary -- Release highlights
8181
<whatsnew315-unpacking-in-comprehensions>`
8282
* :pep:`686`: :ref:`Python now uses UTF-8 as the default encoding
8383
<whatsnew315-utf8-default>`
84-
* :pep:`728`: ``TypedDict`` with typed extra items
84+
* :pep:`728`: :ref:`TypedDict with typed extra items <whatsnew315-typeddict>`
8585
* :pep:`747`: :ref:`Annotating type forms with TypeForm
8686
<whatsnew315-typeform>`
8787
* :pep:`800`: Disjoint bases in the type system
@@ -1521,6 +1521,15 @@ typing
15211521
15221522
(Contributed by Jelle Zijlstra in :gh:`145033`.)
15231523

1524+
.. _whatsnew315-typeddict:
1525+
1526+
* :pep:`728`: Add support in :class:`~typing.TypedDict` for the *closed*
1527+
and *extra_items* class arguments. A closed :class:`~typing.TypedDict`
1528+
does not allow extra keys beyond those specified in the class body, while
1529+
a :class:`~typing.TypedDict` with ``extra_items`` allows arbitrary extra
1530+
items where the values are of the specified type. (Contributed by Angela
1531+
Liss in :gh:`137840`.)
1532+
15241533
* Code like ``class ExtraTypeVars(P1[S], Protocol[T, T2]): ...`` now raises
15251534
a :exc:`TypeError`, because ``S`` is not listed in ``Protocol`` parameters.
15261535
(Contributed by Nikita Sobolev in :gh:`137191`.)

0 commit comments

Comments
 (0)