From 93b9a386f54474234df2b33430b7079e816d2ea8 Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Sun, 17 May 2026 12:37:19 +0100 Subject: [PATCH 1/3] Mark TypeVar/ParamSpec/TypeVarTuple 'name' as positional-only These special-form constructors require `name` to be a positional string literal (PEP 484 / 612 / 646); type checkers reject the keyword form, e.g. mypy: error: TypeVar() expects a string literal as first argument [misc] The stubs advertised `name` as positional-or-keyword, which misleads tools that consume typeshed as ground truth. No type-checker behaviour changes (these are special-cased); the runtime objects are C-level with no introspectable signature on 3.12+, so stubtest is unaffected there. Refs python/typeshed#15804 Co-Authored-By: Claude Opus 4.7 (1M context) --- stdlib/typing.pyi | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/stdlib/typing.pyi b/stdlib/typing.pyi index 2018a835c632..6f73c92a433f 100644 --- a/stdlib/typing.pyi +++ b/stdlib/typing.pyi @@ -178,6 +178,7 @@ class TypeVar: def __new__( cls, name: str, + /, *constraints: Any, # AnnotationForm bound: Any | None = None, # AnnotationForm contravariant: bool = False, @@ -189,6 +190,7 @@ class TypeVar: def __new__( cls, name: str, + /, *constraints: Any, # AnnotationForm bound: Any | None = None, # AnnotationForm covariant: bool = False, @@ -199,6 +201,7 @@ class TypeVar: def __new__( cls, name: str, + /, *constraints: Any, # AnnotationForm bound: Any | None = None, # AnnotationForm covariant: bool = False, @@ -208,6 +211,7 @@ class TypeVar: def __init__( self, name: str, + /, *constraints: Any, # AnnotationForm bound: Any | None = None, # AnnotationForm covariant: bool = False, @@ -280,6 +284,7 @@ if sys.version_info >= (3, 11): def __new__( cls, name: str, + /, *, bound: Any | None = None, # AnnotationForm covariant: bool = False, @@ -288,11 +293,11 @@ if sys.version_info >= (3, 11): infer_variance: bool = False, ) -> Self: ... elif sys.version_info >= (3, 13): - def __new__(cls, name: str, *, default: Any = ...) -> Self: ... # AnnotationForm + def __new__(cls, name: str, /, *, default: Any = ...) -> Self: ... # AnnotationForm elif sys.version_info >= (3, 12): - def __new__(cls, name: str) -> Self: ... + def __new__(cls, name: str, /) -> Self: ... else: - def __init__(self, name: str) -> None: ... + def __init__(self, name: str, /) -> None: ... def __iter__(self) -> Any: ... def __typing_subst__(self, arg: Never, /) -> Never: ... @@ -345,6 +350,7 @@ class ParamSpec: def __new__( cls, name: str, + /, *, bound: Any | None = None, # AnnotationForm contravariant: bool = False, @@ -356,6 +362,7 @@ class ParamSpec: def __new__( cls, name: str, + /, *, bound: Any | None = None, # AnnotationForm contravariant: bool = False, @@ -364,11 +371,11 @@ class ParamSpec: ) -> Self: ... elif sys.version_info >= (3, 11): def __new__( - cls, name: str, *, bound: Any | None = None, contravariant: bool = False, covariant: bool = False # AnnotationForm + cls, name: str, /, *, bound: Any | None = None, contravariant: bool = False, covariant: bool = False # AnnotationForm ) -> Self: ... else: def __init__( - self, name: str, *, bound: Any | None = None, contravariant: bool = False, covariant: bool = False # AnnotationForm + self, name: str, /, *, bound: Any | None = None, contravariant: bool = False, covariant: bool = False # AnnotationForm ) -> None: ... @property From 387d2926f37d80cb6a3b2cba5173a68fd1140c84 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 17 May 2026 11:39:42 +0000 Subject: [PATCH 2/3] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/typing.pyi | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/stdlib/typing.pyi b/stdlib/typing.pyi index 6f73c92a433f..d4580ed84daa 100644 --- a/stdlib/typing.pyi +++ b/stdlib/typing.pyi @@ -375,7 +375,13 @@ class ParamSpec: ) -> Self: ... else: def __init__( - self, name: str, /, *, bound: Any | None = None, contravariant: bool = False, covariant: bool = False # AnnotationForm + self, + name: str, + /, + *, + bound: Any | None = None, + contravariant: bool = False, + covariant: bool = False, # AnnotationForm ) -> None: ... @property From 06da95b52203d8d29b3184477099342e6a430433 Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Sun, 17 May 2026 12:42:27 +0100 Subject: [PATCH 3/3] Allowlist stubtest positional-only mismatch on 3.10/3.11 On 3.10/3.11 these special forms are pure-Python with introspectable signatures whose `name` is positional-or-keyword at runtime; the stub now marks it positional-only (the type-system contract). stubtest only checks positional-only accuracy on 3.10 (+ TypeVarTuple.__init__ on 3.11), so allowlist exactly those entries on those versions. Co-Authored-By: Claude Opus 4.7 (1M context) --- stdlib/@tests/stubtest_allowlists/py310.txt | 6 ++++++ stdlib/@tests/stubtest_allowlists/py311.txt | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/stdlib/@tests/stubtest_allowlists/py310.txt b/stdlib/@tests/stubtest_allowlists/py310.txt index 58e826f7081b..21eb7537ca51 100644 --- a/stdlib/@tests/stubtest_allowlists/py310.txt +++ b/stdlib/@tests/stubtest_allowlists/py310.txt @@ -284,3 +284,9 @@ typing\.Annotated # Super-special typing primitive # These methods have no default implementation for Python < 3.13. _pickle.Pickler.persistent_id _pickle.Unpickler.persistent_load + +# `name` is a positional string literal for these special forms (PEP 484 / 612); +# the stub marks it positional-only, but the pure-Python 3.10 runtime objects +# accept it as a keyword argument. +typing.ParamSpec.__init__ +typing.TypeVar.__init__ diff --git a/stdlib/@tests/stubtest_allowlists/py311.txt b/stdlib/@tests/stubtest_allowlists/py311.txt index 11af276eb139..7a7b4006985b 100644 --- a/stdlib/@tests/stubtest_allowlists/py311.txt +++ b/stdlib/@tests/stubtest_allowlists/py311.txt @@ -261,3 +261,8 @@ typing\.Annotated # Super-special typing primitive # These methods have no default implementation for Python < 3.13. _pickle.Pickler.persistent_id _pickle.Unpickler.persistent_load + +# `name` is a positional string literal for TypeVarTuple (PEP 646); the stub +# marks it positional-only, but the pure-Python 3.11 runtime __init__ accepts +# it as a keyword argument. +typing.TypeVarTuple.__init__