]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-137840: Document PEP 728 (#149207)
authorJelle Zijlstra <jelle.zijlstra@gmail.com>
Tue, 5 May 2026 03:30:03 +0000 (20:30 -0700)
committerGitHub <noreply@github.com>
Tue, 5 May 2026 03:30:03 +0000 (20:30 -0700)
Doc/library/typing.rst
Doc/whatsnew/3.15.rst

index f45a22addbb56a37c07c137584535bae18d8c67f..1e544de74a040f17de7b908265ad3d8527f79035 100644 (file)
@@ -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
 --------
 
index e98c483baec823008da892983f4db53ec457cc03..7c4ff0d8775168c8a934263ea6cb180fcf09dba6 100644 (file)
@@ -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`.)