https://github.com/python/cpython/commit/5dd21617164cf69e848a70e3d7e32faf0bc3f279
commit: 5dd21617164cf69e848a70e3d7e32faf0bc3f279
branch: main
author: Jelle Zijlstra <[email protected]>
committer: JelleZijlstra <[email protected]>
date: 2026-05-04T20:30:03-07:00
summary:
gh-137840: Document PEP 728 (#149207)
files:
M Doc/library/typing.rst
M Doc/whatsnew/3.15.rst
diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst
index f45a22addbb56a..1e544de74a040f 100644
--- a/Doc/library/typing.rst
+++ b/Doc/library/typing.rst
@@ -2792,6 +2792,37 @@ types.
y: int
z: int
+ By default, a ``TypedDict`` is open, meaning that it may contain additional
keys
+ at runtime beyond those defined in the class body. The *closed* class
argument can
+ be used to control this; if ``closed=True``, the ``TypedDict`` cannot
contain additional keys.
+
+ ::
+
+ class ClosedPoint(TypedDict, closed=True):
+ x: int
+ y: int
+
+ class ClosedPoint3D(ClosedPoint): # type checker error: cannot add keys
to a closed TypedDict
+ z: int
+
+ Setting ``closed=False`` explicitly requests the default open behavior. If
the argument is not
+ passed, this state is inherited from the parent class.
+
+ In addition to being open or closed, a ``TypedDict`` can also be configured
to have extra items.
+ If the *extra_items* class argument is set to a type, the ``TypedDict`` can
contain arbitrary
+ additional keys, but the values of those keys must be of the specified type.
+
+ ::
+
+ class ExtraItemsPoint(TypedDict, extra_items=int):
+ x: int
+ y: int
+
+ point: ExtraItemsPoint = {'x': 1, 'y': 2, 'anything': 3} # OK
+
+ The *extra_items* argument is also inherited through subclassing. It is
unset
+ by default, and it may not be used together with the *closed* argument.
+
A ``TypedDict`` cannot inherit from a non-\ ``TypedDict`` class,
except for :class:`Generic`. For example::
@@ -2825,8 +2856,8 @@ types.
group: list[T]
A ``TypedDict`` can be introspected via annotations dicts
- (see :ref:`annotations-howto` for more information on annotations best
practices),
- :attr:`__total__`, :attr:`__required_keys__`, and :attr:`__optional_keys__`.
+ (see :ref:`annotations-howto` for more information on annotations best
practices)
+ and the following attributes:
.. attribute:: __total__
@@ -2896,8 +2927,6 @@ types.
``__required_keys__`` and ``__optional_keys__`` rely on may not work
properly, and the values of the attributes may be incorrect.
- Support for :data:`ReadOnly` is reflected in the following attributes:
-
.. attribute:: __readonly_keys__
A :class:`frozenset` containing the names of all read-only keys. Keys
@@ -2912,6 +2941,14 @@ types.
.. versionadded:: 3.13
+ .. attribute:: __closed__
+
+ The value of the *closed* class argument. It can be ``True``, ``False``,
or :data:`None`.
+
+ .. attribute:: __extra_items__
+
+ The value of the *extra_items* class argument. It can be a valid type or
:data:`NoExtraItems`.
+
See the `TypedDict
<https://typing.python.org/en/latest/spec/typeddict.html#typeddict>`_ section
in the typing documentation for more examples and detailed rules.
.. versionadded:: 3.8
@@ -2931,7 +2968,10 @@ types.
Removed support for the keyword-argument method of creating
``TypedDict``\ s.
.. versionchanged:: 3.13
- Support for the :data:`ReadOnly` qualifier was added.
+ Support for the :data:`ReadOnly` qualifier was added. See :pep:`705`.
+
+ .. versionchanged:: next
+ Support for the *closed* and *extra_items* class arguments was added.
See :pep:`728`.
Protocols
@@ -3679,6 +3719,21 @@ Introspection helpers
.. versionadded:: 3.13
+.. data:: NoExtraItems
+
+ A :class:`sentinel` object used to indicate that a :class:`TypedDict`
+ does not have the *extra_items* class argument.
+
+ .. doctest::
+
+ >>> from typing import TypedDict, NoExtraItems
+ >>> class Point(TypedDict):
+ ... x: int
+ ... y: int
+ ...
+ >>> Point.__extra_items__ is NoExtraItems
+ True
+
Constant
--------
diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst
index e98c483baec823..7c4ff0d8775168 100644
--- a/Doc/whatsnew/3.15.rst
+++ b/Doc/whatsnew/3.15.rst
@@ -81,7 +81,7 @@ Summary -- Release highlights
<whatsnew315-unpacking-in-comprehensions>`
* :pep:`686`: :ref:`Python now uses UTF-8 as the default encoding
<whatsnew315-utf8-default>`
-* :pep:`728`: ``TypedDict`` with typed extra items
+* :pep:`728`: :ref:`TypedDict with typed extra items <whatsnew315-typeddict>`
* :pep:`747`: :ref:`Annotating type forms with TypeForm
<whatsnew315-typeform>`
* :pep:`800`: Disjoint bases in the type system
@@ -1521,6 +1521,15 @@ typing
(Contributed by Jelle Zijlstra in :gh:`145033`.)
+.. _whatsnew315-typeddict:
+
+* :pep:`728`: Add support in :class:`~typing.TypedDict` for the *closed*
+ and *extra_items* class arguments. A closed :class:`~typing.TypedDict`
+ does not allow extra keys beyond those specified in the class body, while
+ a :class:`~typing.TypedDict` with ``extra_items`` allows arbitrary extra
+ items where the values are of the specified type. (Contributed by Angela
+ Liss in :gh:`137840`.)
+
* Code like ``class ExtraTypeVars(P1[S], Protocol[T, T2]): ...`` now raises
a :exc:`TypeError`, because ``S`` is not listed in ``Protocol`` parameters.
(Contributed by Nikita Sobolev in :gh:`137191`.)
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]