Skip to content

Commit ca269e5

Browse files
JelleZijlstraAlexWaygoodpicnixzhauntsaninja
authored
gh-116126: Implement PEP 696 (#116129)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com> Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com>
1 parent 852263e commit ca269e5

28 files changed

+1924
-623
lines changed

Doc/library/ast.rst

+38-14
Original file line numberDiff line numberDiff line change
@@ -1748,43 +1748,57 @@ Type parameters
17481748
:ref:`Type parameters <type-params>` can exist on classes, functions, and type
17491749
aliases.
17501750

1751-
.. class:: TypeVar(name, bound)
1751+
.. class:: TypeVar(name, bound, default_value)
17521752

1753-
A :class:`typing.TypeVar`. ``name`` is the name of the type variable.
1754-
``bound`` is the bound or constraints, if any. If ``bound`` is a :class:`Tuple`,
1755-
it represents constraints; otherwise it represents the bound.
1753+
A :class:`typing.TypeVar`. *name* is the name of the type variable.
1754+
*bound* is the bound or constraints, if any. If *bound* is a :class:`Tuple`,
1755+
it represents constraints; otherwise it represents the bound. *default_value*
1756+
is the default value; if the :class:`!TypeVar` has no default, this
1757+
attribute will be set to ``None``.
17561758

17571759
.. doctest::
17581760

1759-
>>> print(ast.dump(ast.parse("type Alias[T: int] = list[T]"), indent=4))
1761+
>>> print(ast.dump(ast.parse("type Alias[T: int = bool] = list[T]"), indent=4))
17601762
Module(
17611763
body=[
17621764
TypeAlias(
17631765
name=Name(id='Alias', ctx=Store()),
17641766
type_params=[
17651767
TypeVar(
17661768
name='T',
1767-
bound=Name(id='int', ctx=Load()))],
1769+
bound=Name(id='int', ctx=Load()),
1770+
default_value=Name(id='bool', ctx=Load()))],
17681771
value=Subscript(
17691772
value=Name(id='list', ctx=Load()),
17701773
slice=Name(id='T', ctx=Load()),
17711774
ctx=Load()))])
17721775

17731776
.. versionadded:: 3.12
17741777

1775-
.. class:: ParamSpec(name)
1778+
.. versionchanged:: 3.13
1779+
Added the *default_value* parameter.
1780+
1781+
.. class:: ParamSpec(name, default_value)
17761782

1777-
A :class:`typing.ParamSpec`. ``name`` is the name of the parameter specification.
1783+
A :class:`typing.ParamSpec`. *name* is the name of the parameter specification.
1784+
*default_value* is the default value; if the :class:`!ParamSpec` has no default,
1785+
this attribute will be set to ``None``.
17781786

17791787
.. doctest::
17801788

1781-
>>> print(ast.dump(ast.parse("type Alias[**P] = Callable[P, int]"), indent=4))
1789+
>>> print(ast.dump(ast.parse("type Alias[**P = (int, str)] = Callable[P, int]"), indent=4))
17821790
Module(
17831791
body=[
17841792
TypeAlias(
17851793
name=Name(id='Alias', ctx=Store()),
17861794
type_params=[
1787-
ParamSpec(name='P')],
1795+
ParamSpec(
1796+
name='P',
1797+
default_value=Tuple(
1798+
elts=[
1799+
Name(id='int', ctx=Load()),
1800+
Name(id='str', ctx=Load())],
1801+
ctx=Load()))],
17881802
value=Subscript(
17891803
value=Name(id='Callable', ctx=Load()),
17901804
slice=Tuple(
@@ -1796,19 +1810,26 @@ aliases.
17961810

17971811
.. versionadded:: 3.12
17981812

1799-
.. class:: TypeVarTuple(name)
1813+
.. versionchanged:: 3.13
1814+
Added the *default_value* parameter.
1815+
1816+
.. class:: TypeVarTuple(name, default_value)
18001817

1801-
A :class:`typing.TypeVarTuple`. ``name`` is the name of the type variable tuple.
1818+
A :class:`typing.TypeVarTuple`. *name* is the name of the type variable tuple.
1819+
*default_value* is the default value; if the :class:`!TypeVarTuple` has no
1820+
default, this attribute will be set to ``None``.
18021821

18031822
.. doctest::
18041823

1805-
>>> print(ast.dump(ast.parse("type Alias[*Ts] = tuple[*Ts]"), indent=4))
1824+
>>> print(ast.dump(ast.parse("type Alias[*Ts = ()] = tuple[*Ts]"), indent=4))
18061825
Module(
18071826
body=[
18081827
TypeAlias(
18091828
name=Name(id='Alias', ctx=Store()),
18101829
type_params=[
1811-
TypeVarTuple(name='Ts')],
1830+
TypeVarTuple(
1831+
name='Ts',
1832+
default_value=Tuple(ctx=Load()))],
18121833
value=Subscript(
18131834
value=Name(id='tuple', ctx=Load()),
18141835
slice=Tuple(
@@ -1821,6 +1842,9 @@ aliases.
18211842

18221843
.. versionadded:: 3.12
18231844

1845+
.. versionchanged:: 3.13
1846+
Added the *default_value* parameter.
1847+
18241848
Function and class definitions
18251849
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
18261850

Doc/library/typing.rst

+79-3
Original file line numberDiff line numberDiff line change
@@ -1614,7 +1614,7 @@ without the dedicated syntax, as documented below.
16141614

16151615
.. _typevar:
16161616

1617-
.. class:: TypeVar(name, *constraints, bound=None, covariant=False, contravariant=False, infer_variance=False)
1617+
.. class:: TypeVar(name, *constraints, bound=None, covariant=False, contravariant=False, infer_variance=False, default=typing.NoDefault)
16181618

16191619
Type variable.
16201620

@@ -1752,15 +1752,35 @@ without the dedicated syntax, as documented below.
17521752
the constraints are evaluated only when the attribute is accessed, not when
17531753
the type variable is created (see :ref:`lazy-evaluation`).
17541754

1755+
.. attribute:: __default__
1756+
1757+
The default value of the type variable, or :data:`typing.NoDefault` if it
1758+
has no default.
1759+
1760+
.. versionadded:: 3.13
1761+
1762+
.. method:: has_default()
1763+
1764+
Return whether or not the type variable has a default value. This is equivalent
1765+
to checking whether :attr:`__default__` is not the :data:`typing.NoDefault`
1766+
singleton, except that it does not force evaluation of the
1767+
:ref:`lazily evaluated <lazy-evaluation>` default value.
1768+
1769+
.. versionadded:: 3.13
1770+
17551771
.. versionchanged:: 3.12
17561772

17571773
Type variables can now be declared using the
17581774
:ref:`type parameter <type-params>` syntax introduced by :pep:`695`.
17591775
The ``infer_variance`` parameter was added.
17601776

1777+
.. versionchanged:: 3.13
1778+
1779+
Support for default values was added.
1780+
17611781
.. _typevartuple:
17621782

1763-
.. class:: TypeVarTuple(name)
1783+
.. class:: TypeVarTuple(name, default=typing.NoDefault)
17641784

17651785
Type variable tuple. A specialized form of :ref:`type variable <typevar>`
17661786
that enables *variadic* generics.
@@ -1870,14 +1890,34 @@ without the dedicated syntax, as documented below.
18701890

18711891
The name of the type variable tuple.
18721892

1893+
.. attribute:: __default__
1894+
1895+
The default value of the type variable tuple, or :data:`typing.NoDefault` if it
1896+
has no default.
1897+
1898+
.. versionadded:: 3.13
1899+
1900+
.. method:: has_default()
1901+
1902+
Return whether or not the type variable tuple has a default value. This is equivalent
1903+
to checking whether :attr:`__default__` is not the :data:`typing.NoDefault`
1904+
singleton, except that it does not force evaluation of the
1905+
:ref:`lazily evaluated <lazy-evaluation>` default value.
1906+
1907+
.. versionadded:: 3.13
1908+
18731909
.. versionadded:: 3.11
18741910

18751911
.. versionchanged:: 3.12
18761912

18771913
Type variable tuples can now be declared using the
18781914
:ref:`type parameter <type-params>` syntax introduced by :pep:`695`.
18791915

1880-
.. class:: ParamSpec(name, *, bound=None, covariant=False, contravariant=False)
1916+
.. versionchanged:: 3.13
1917+
1918+
Support for default values was added.
1919+
1920+
.. class:: ParamSpec(name, *, bound=None, covariant=False, contravariant=False, default=typing.NoDefault)
18811921

18821922
Parameter specification variable. A specialized version of
18831923
:ref:`type variables <typevar>`.
@@ -1946,6 +1986,22 @@ without the dedicated syntax, as documented below.
19461986

19471987
The name of the parameter specification.
19481988

1989+
.. attribute:: __default__
1990+
1991+
The default value of the parameter specification, or :data:`typing.NoDefault` if it
1992+
has no default.
1993+
1994+
.. versionadded:: 3.13
1995+
1996+
.. method:: has_default()
1997+
1998+
Return whether or not the parameter specification has a default value. This is equivalent
1999+
to checking whether :attr:`__default__` is not the :data:`typing.NoDefault`
2000+
singleton, except that it does not force evaluation of the
2001+
:ref:`lazily evaluated <lazy-evaluation>` default value.
2002+
2003+
.. versionadded:: 3.13
2004+
19492005
Parameter specification variables created with ``covariant=True`` or
19502006
``contravariant=True`` can be used to declare covariant or contravariant
19512007
generic types. The ``bound`` argument is also accepted, similar to
@@ -1959,6 +2015,10 @@ without the dedicated syntax, as documented below.
19592015
Parameter specifications can now be declared using the
19602016
:ref:`type parameter <type-params>` syntax introduced by :pep:`695`.
19612017

2018+
.. versionchanged:: 3.13
2019+
2020+
Support for default values was added.
2021+
19622022
.. note::
19632023
Only parameter specification variables defined in global scope can
19642024
be pickled.
@@ -3171,6 +3231,22 @@ Introspection helpers
31713231

31723232
.. versionadded:: 3.7.4
31733233

3234+
.. data:: NoDefault
3235+
3236+
A sentinel object used to indicate that a type parameter has no default
3237+
value. For example:
3238+
3239+
.. doctest::
3240+
3241+
>>> T = TypeVar("T")
3242+
>>> T.__default__ is typing.NoDefault
3243+
True
3244+
>>> S = TypeVar("S", default=None)
3245+
>>> S.__default__ is None
3246+
True
3247+
3248+
.. versionadded:: 3.13
3249+
31743250
Constant
31753251
--------
31763252

Doc/reference/compound_stmts.rst

+23-8
Original file line numberDiff line numberDiff line change
@@ -1620,15 +1620,18 @@ Type parameter lists
16201620

16211621
.. versionadded:: 3.12
16221622

1623+
.. versionchanged:: 3.13
1624+
Support for default values was added (see :pep:`696`).
1625+
16231626
.. index::
16241627
single: type parameters
16251628

16261629
.. productionlist:: python-grammar
16271630
type_params: "[" `type_param` ("," `type_param`)* "]"
16281631
type_param: `typevar` | `typevartuple` | `paramspec`
1629-
typevar: `identifier` (":" `expression`)?
1630-
typevartuple: "*" `identifier`
1631-
paramspec: "**" `identifier`
1632+
typevar: `identifier` (":" `expression`)? ("=" `expression`)?
1633+
typevartuple: "*" `identifier` ("=" `expression`)?
1634+
paramspec: "**" `identifier` ("=" `expression`)?
16321635

16331636
:ref:`Functions <def>` (including :ref:`coroutines <async def>`),
16341637
:ref:`classes <class>` and :ref:`type aliases <type>` may
@@ -1694,19 +1697,31 @@ evaluated in a separate :ref:`annotation scope <annotation-scopes>`.
16941697
:data:`typing.TypeVarTuple`\ s and :data:`typing.ParamSpec`\ s cannot have bounds
16951698
or constraints.
16961699

1700+
All three flavors of type parameters can also have a *default value*, which is used
1701+
when the type parameter is not explicitly provided. This is added by appending
1702+
a single equals sign (``=``) followed by an expression. Like the bounds and
1703+
constraints of type variables, the default value is not evaluated when the
1704+
object is created, but only when the type parameter's ``__default__`` attribute
1705+
is accessed. To this end, the default value is evaluated in a separate
1706+
:ref:`annotation scope <annotation-scopes>`. If no default value is specified
1707+
for a type parameter, the ``__default__`` attribute is set to the special
1708+
sentinel object :data:`typing.NoDefault`.
1709+
16971710
The following example indicates the full set of allowed type parameter declarations::
16981711

16991712
def overly_generic[
17001713
SimpleTypeVar,
1714+
TypeVarWithDefault = int,
17011715
TypeVarWithBound: int,
17021716
TypeVarWithConstraints: (str, bytes),
1703-
*SimpleTypeVarTuple,
1704-
**SimpleParamSpec,
1717+
*SimpleTypeVarTuple = (int, float),
1718+
**SimpleParamSpec = (str, bytearray),
17051719
](
17061720
a: SimpleTypeVar,
1707-
b: TypeVarWithBound,
1708-
c: Callable[SimpleParamSpec, TypeVarWithConstraints],
1709-
*d: SimpleTypeVarTuple,
1721+
b: TypeVarWithDefault,
1722+
c: TypeVarWithBound,
1723+
d: Callable[SimpleParamSpec, TypeVarWithConstraints],
1724+
*e: SimpleTypeVarTuple,
17101725
): ...
17111726

17121727
.. _generic-functions:

Doc/reference/executionmodel.rst

+6-2
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ Annotation scopes are used in the following contexts:
205205
* Type parameter lists for :ref:`generic classes <generic-classes>`.
206206
A generic class's base classes and
207207
keyword arguments are executed within the annotation scope, but its decorators are not.
208-
* The bounds and constraints for type variables
208+
* The bounds, constraints, and default values for type parameters
209209
(:ref:`lazily evaluated <lazy-evaluation>`).
210210
* The value of type aliases (:ref:`lazily evaluated <lazy-evaluation>`).
211211

@@ -232,13 +232,17 @@ Annotation scopes differ from function scopes in the following ways:
232232
.. versionadded:: 3.12
233233
Annotation scopes were introduced in Python 3.12 as part of :pep:`695`.
234234

235+
.. versionchanged:: 3.13
236+
Annotation scopes are also used for type parameter defaults, as
237+
introduced by :pep:`696`.
238+
235239
.. _lazy-evaluation:
236240

237241
Lazy evaluation
238242
---------------
239243

240244
The values of type aliases created through the :keyword:`type` statement are
241-
*lazily evaluated*. The same applies to the bounds and constraints of type
245+
*lazily evaluated*. The same applies to the bounds, constraints, and default values of type
242246
variables created through the :ref:`type parameter syntax <type-params>`.
243247
This means that they are not evaluated when the type alias or type variable is
244248
created. Instead, they are only evaluated when doing so is necessary to resolve

Doc/whatsnew/3.13.rst

+6
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ Interpreter improvements:
8989

9090
New typing features:
9191

92+
* :pep:`696`: Type parameters (:data:`typing.TypeVar`, :data:`typing.ParamSpec`,
93+
and :data:`typing.TypeVarTuple`) now support defaults.
9294
* :pep:`742`: :data:`typing.TypeIs` was added, providing more intuitive
9395
type narrowing behavior.
9496

@@ -850,6 +852,10 @@ typing
850852
an item of a :class:`typing.TypedDict` as read-only for type checkers.
851853
See :pep:`705` for more details.
852854

855+
* Add :data:`typing.NoDefault`, a sentinel object used to represent the defaults
856+
of some parameters in the :mod:`typing` module. (Contributed by Jelle Zijlstra in
857+
:gh:`116126`.)
858+
853859
unicodedata
854860
-----------
855861

Grammar/python.gram

+7-3
Original file line numberDiff line numberDiff line change
@@ -647,21 +647,25 @@ type_params[asdl_type_param_seq*]: '[' t=type_param_seq ']' {
647647
type_param_seq[asdl_type_param_seq*]: a[asdl_type_param_seq*]=','.type_param+ [','] { a }
648648

649649
type_param[type_param_ty] (memo):
650-
| a=NAME b=[type_param_bound] { _PyAST_TypeVar(a->v.Name.id, b, EXTRA) }
650+
| a=NAME b=[type_param_bound] c=[type_param_default] { _PyAST_TypeVar(a->v.Name.id, b, c, EXTRA) }
651651
| '*' a=NAME colon=':' e=expression {
652652
RAISE_SYNTAX_ERROR_STARTING_FROM(colon, e->kind == Tuple_kind
653653
? "cannot use constraints with TypeVarTuple"
654654
: "cannot use bound with TypeVarTuple")
655655
}
656-
| '*' a=NAME { _PyAST_TypeVarTuple(a->v.Name.id, EXTRA) }
656+
| '*' a=NAME b=[type_param_starred_default] { _PyAST_TypeVarTuple(a->v.Name.id, b, EXTRA) }
657657
| '**' a=NAME colon=':' e=expression {
658658
RAISE_SYNTAX_ERROR_STARTING_FROM(colon, e->kind == Tuple_kind
659659
? "cannot use constraints with ParamSpec"
660660
: "cannot use bound with ParamSpec")
661661
}
662-
| '**' a=NAME { _PyAST_ParamSpec(a->v.Name.id, EXTRA) }
662+
| '**' a=NAME b=[type_param_default] { _PyAST_ParamSpec(a->v.Name.id, b, EXTRA) }
663663

664664
type_param_bound[expr_ty]: ':' e=expression { e }
665+
type_param_default[expr_ty]: '=' e=expression {
666+
CHECK_VERSION(expr_ty, 13, "Type parameter defaults are", e) }
667+
type_param_starred_default[expr_ty]: '=' e=star_expression {
668+
CHECK_VERSION(expr_ty, 13, "Type parameter defaults are", e) }
665669

666670
# EXPRESSIONS
667671
# -----------

0 commit comments

Comments
 (0)