diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 1957cadcbb1592..02550b1c067b87 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2786,6 +2786,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:: @@ -2819,8 +2850,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__ @@ -2890,8 +2921,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 @@ -2906,6 +2935,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 `_ section in the typing documentation for more examples and detailed rules. .. versionadded:: 3.8 @@ -2925,7 +2962,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:: 3.15 + Support for the *closed* and *extra_items* class arguments was added. See :pep:`728`. Protocols @@ -3673,6 +3713,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 a687ee5115be05..ced32f2f287720 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -79,7 +79,7 @@ Summary -- Release highlights ` * :pep:`686`: :ref:`Python now uses UTF-8 as the default encoding ` -* :pep:`728`: ``TypedDict`` with typed extra items +* :pep:`728`: :ref:`TypedDict with typed extra items ` * :pep:`747`: :ref:`Annotating type forms with TypeForm ` * :pep:`800`: Disjoint bases in the type system @@ -1399,6 +1399,15 @@ typing (Contributed by Jelle Zijlstra in :gh:`145033`.) +.. _whatsnew315-pep728: + +* :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`.)