Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions Doc/library/typing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2135,11 +2135,6 @@ without the dedicated syntax, as documented below.

.. versionadded:: 3.13

Type variable tuples created with ``covariant=True`` or
``contravariant=True`` can be used to declare covariant or contravariant
generic types. The ``bound`` argument is also accepted, similar to
:class:`TypeVar`, but its actual semantics are yet to be decided.

.. versionadded:: 3.11

.. versionchanged:: 3.12
Expand All @@ -2156,6 +2151,10 @@ without the dedicated syntax, as documented below.
Added support for the ``bound``, ``covariant``, ``contravariant``, and
``infer_variance`` parameters.

.. versionchanged:: 3.16

Syntax and semantics for bounds were added.

.. class:: ParamSpec(name, *, bound=None, covariant=False, contravariant=False, default=typing.NoDefault)

Parameter specification variable. A specialized version of
Expand Down Expand Up @@ -2282,6 +2281,10 @@ without the dedicated syntax, as documented below.

Support for default values was added.

.. versionchanged:: 3.16

Syntax and semantics for bounds were added.

.. note::
Only parameter specification variables defined in global scope can
be pickled.
Expand Down
5 changes: 3 additions & 2 deletions Grammar/python.gram
Original file line number Diff line number Diff line change
Expand Up @@ -695,10 +695,11 @@ type_param_seq[asdl_type_param_seq*]: a[asdl_type_param_seq*]=','.type_param+ ['
type_param[type_param_ty] (memo):
| a=NAME b=[type_param_bound] c=[type_param_default] { _PyAST_TypeVar(a->v.Name.id, b, c, EXTRA) }
| invalid_type_param
| '*' a=NAME b=[type_param_starred_default] { _PyAST_TypeVarTuple(a->v.Name.id, b, EXTRA) }
| '**' a=NAME b=[type_param_default] { _PyAST_ParamSpec(a->v.Name.id, b, EXTRA) }
| '*' a=NAME b=[type_param_stared_bound] c=[type_param_starred_default] { _PyAST_TypeVarTuple(a->v.Name.id, b, c, EXTRA) }
| '**' a=NAME b=[type_param_bound] c=[type_param_default] { _PyAST_ParamSpec(a->v.Name.id, b, c, EXTRA) }

type_param_bound[expr_ty]: ':' e=expression { e }
type_param_stared_bound[expr_ty]: ':' e=star_expression { e }
type_param_default[expr_ty]: '=' e=expression {
CHECK_VERSION(expr_ty, 13, "Type parameter defaults are", e) }
type_param_starred_default[expr_ty]: '=' e=star_expression {
Expand Down
4 changes: 2 additions & 2 deletions Include/internal/pycore_ast.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

81 changes: 38 additions & 43 deletions Lib/test/test_type_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -1075,52 +1075,43 @@

class TypeParamsTypeVarTupleTest(unittest.TestCase):
def test_typevartuple_01(self):
code = """def func1[*A: str](): pass"""
check_syntax_error(self, code, "cannot use bound with TypeVarTuple")
code = """def func1[*A: (int, str)](): pass"""
check_syntax_error(self, code, "cannot use constraints with TypeVarTuple")
code = """class X[*A: str]: pass"""
check_syntax_error(self, code, "cannot use bound with TypeVarTuple")
code = """class X[*A: (int, str)]: pass"""
check_syntax_error(self, code, "cannot use constraints with TypeVarTuple")
code = """type X[*A: str] = int"""
check_syntax_error(self, code, "cannot use bound with TypeVarTuple")
code = """type X[*A: (int, str)] = int"""
check_syntax_error(self, code, "cannot use constraints with TypeVarTuple")

def test_typevartuple_02(self):
def func1[*A]():
return A

a = func1()
def func1[*A: str, *B: str | int]():

Check failure on line 1078 in Lib/test/test_type_params.py

View workflow job for this annotation

GitHub Actions / lint

ruff (invalid-syntax)

Lib/test/test_type_params.py:1078:42: invalid-syntax: Expected `)`, found `(`

Check failure on line 1078 in Lib/test/test_type_params.py

View workflow job for this annotation

GitHub Actions / lint

ruff (invalid-syntax)

Lib/test/test_type_params.py:1078:41: invalid-syntax: Expected `,`, found `]`

Check failure on line 1078 in Lib/test/test_type_params.py

View workflow job for this annotation

GitHub Actions / lint

ruff (invalid-syntax)

Lib/test/test_type_params.py:1078:21: invalid-syntax: Expected `]`, found `:`
return A, B

Check failure on line 1079 in Lib/test/test_type_params.py

View workflow job for this annotation

GitHub Actions / lint

ruff (invalid-syntax)

Lib/test/test_type_params.py:1079:1: invalid-syntax: Unexpected indentation

Check failure on line 1079 in Lib/test/test_type_params.py

View workflow job for this annotation

GitHub Actions / lint

ruff (invalid-syntax)

Lib/test/test_type_params.py:1078:45: invalid-syntax: Expected an expression

a, b = func1()

self.assertIsInstance(a, TypeVarTuple)
self.assertEqual(a.__bound__, str)
self.assertTrue(a.__infer_variance__)
self.assertFalse(a.__covariant__)
self.assertFalse(a.__contravariant__)

self.assertIsInstance(b, TypeVarTuple)
self.assertEqual(b.__bound__, str | int)
self.assertTrue(b.__infer_variance__)
self.assertFalse(b.__covariant__)
self.assertFalse(b.__contravariant__)


class TypeParamsTypeVarParamSpecTest(unittest.TestCase):

Check failure on line 1096 in Lib/test/test_type_params.py

View workflow job for this annotation

GitHub Actions / lint

ruff (invalid-syntax)

Lib/test/test_type_params.py:1096:1: invalid-syntax: Expected a statement
def test_paramspec_01(self):
code = """def func1[**A: str](): pass"""
check_syntax_error(self, code, "cannot use bound with ParamSpec")
code = """def func1[**A: (int, str)](): pass"""
check_syntax_error(self, code, "cannot use constraints with ParamSpec")
code = """class X[**A: str]: pass"""
check_syntax_error(self, code, "cannot use bound with ParamSpec")
code = """class X[**A: (int, str)]: pass"""
check_syntax_error(self, code, "cannot use constraints with ParamSpec")
code = """type X[**A: str] = int"""
check_syntax_error(self, code, "cannot use bound with ParamSpec")
code = """type X[**A: (int, str)] = int"""
check_syntax_error(self, code, "cannot use constraints with ParamSpec")

def test_paramspec_02(self):
def func1[**A]():
return A

a = func1()
def func1[**A: [str], **B: [str | int]]():

Check failure on line 1098 in Lib/test/test_type_params.py

View workflow job for this annotation

GitHub Actions / lint

ruff (invalid-syntax)

Lib/test/test_type_params.py:1098:31: invalid-syntax: Expected an expression

Check failure on line 1098 in Lib/test/test_type_params.py

View workflow job for this annotation

GitHub Actions / lint

ruff (invalid-syntax)

Lib/test/test_type_params.py:1098:24: invalid-syntax: Only single target (not tuple) can be annotated

Check failure on line 1098 in Lib/test/test_type_params.py

View workflow job for this annotation

GitHub Actions / lint

ruff (invalid-syntax)

Lib/test/test_type_params.py:1098:24: invalid-syntax: Expected `)`, found `[`

Check failure on line 1098 in Lib/test/test_type_params.py

View workflow job for this annotation

GitHub Actions / lint

ruff (invalid-syntax)

Lib/test/test_type_params.py:1098:22: invalid-syntax: Expected `]`, found `:`
return A, B

a, b = func1()

self.assertIsInstance(a, ParamSpec)
self.assertEqual(a.__bound__, [str])
self.assertTrue(a.__infer_variance__)
self.assertFalse(a.__covariant__)
self.assertFalse(a.__contravariant__)

self.assertIsInstance(b, ParamSpec)
self.assertEqual(b.__bound__, [str | int])
self.assertTrue(b.__infer_variance__)
self.assertFalse(b.__covariant__)
self.assertFalse(b.__contravariant__)


class TypeParamsTypeParamsDunder(unittest.TestCase):
def test_typeparams_dunder_class_01(self):
Expand Down Expand Up @@ -1264,7 +1255,7 @@
P,
P.args,
P.kwargs,
TypeVarTuple('Ts'),
TypeVarTuple('Ts', bound=int),
OldStyle,
OldStyle[int],
OldStyle(),
Expand Down Expand Up @@ -1422,22 +1413,26 @@
def test_general(self):
type Alias = int
Alias2 = TypeAliasType("Alias2", int)
def f[T: int = int, **P = int, *Ts = int](): pass
T, P, Ts = f.__type_params__
def f[T: int = int, *Ts: int = int, **P: [int] = int](): pass
T, Ts, P = f.__type_params__
T2 = TypeVar("T2", bound=int, default=int)
P2 = ParamSpec("P2", default=int)
Ts2 = TypeVarTuple("Ts2", default=int)
Ts2 = TypeVarTuple("Ts2", bound=int, default=int)
P2 = ParamSpec("P2", bound=[int], default=int)
cases = [
Alias.evaluate_value,
Alias2.evaluate_value,
T.evaluate_bound,
T.evaluate_default,
P.evaluate_default,
Ts.evaluate_bound,
Ts.evaluate_default,
P.evaluate_bound,
P.evaluate_default,
T2.evaluate_bound,
T2.evaluate_default,
P2.evaluate_default,
Ts2.evaluate_bound,
Ts2.evaluate_default,
P2.evaluate_bound,
P2.evaluate_default,
]
for case in cases:
with self.subTest(case=case):
Expand Down
65 changes: 59 additions & 6 deletions Parser/parser.c

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading