From fcff32fbd4003af3b01afccd5f03cf57e0502dd6 Mon Sep 17 00:00:00 2001 From: PyCharm Automation Bot Date: Mon, 17 Aug 2026 11:04:17 +0000 Subject: [PATCH] PY-91657 Update conformance test suite version to dcffbae91ed8b7e26fdf35803133eaf85d836160 Closes PY-91657 (cherry picked from commit 06ebb646b55a51dceb3d34f89315287fc7223679) IJ-MR-218984 GitOrigin-RevId: 0dbf2c3d5f206813c5a594ad4661f68dd0aad7a5 --- .../conformance/tests/callables_annotation.py | 2 +- .../conformance/tests/callables_protocol.py | 2 +- .../conformance/tests/callables_subtyping.py | 2 +- .../conformance/tests/classes_classvar.py | 16 ++ .../tests/generics_defaults_referential.py | 1 - .../generics_mixed_variance_inference.py | 21 +++ .../tests/generics_paramspec_variance.py | 152 ++++++++++++++++++ .../tests/generics_typevartuple_basic.py | 12 +- .../tests/generics_typevartuple_variance.py | 117 ++++++++++++++ .../tests/protocols_class_objects.py | 2 +- .../conformance/tests/protocols_definition.py | 31 +++- .../conformance/tests/protocols_variance.py | 5 +- .../tests/qualifiers_final_annotation.py | 16 +- .../testData/typing/conformance/tests/ty.toml | 1 + 14 files changed, 367 insertions(+), 13 deletions(-) create mode 100644 python/testData/typing/conformance/tests/generics_mixed_variance_inference.py create mode 100644 python/testData/typing/conformance/tests/generics_paramspec_variance.py create mode 100644 python/testData/typing/conformance/tests/generics_typevartuple_variance.py diff --git a/python/testData/typing/conformance/tests/callables_annotation.py b/python/testData/typing/conformance/tests/callables_annotation.py index 35b98f5ee172..8cf25c6ab77e 100644 --- a/python/testData/typing/conformance/tests/callables_annotation.py +++ b/python/testData/typing/conformance/tests/callables_annotation.py @@ -111,7 +111,7 @@ class Proto3(Protocol): def __call__(self, a: int, *args: Any, **kwargs: Any) -> None: ... -class Proto4(Protocol[P]): +class Proto4[**P](Protocol): def __call__(self, a: int, *args: P.args, **kwargs: P.kwargs) -> None: ... diff --git a/python/testData/typing/conformance/tests/callables_protocol.py b/python/testData/typing/conformance/tests/callables_protocol.py index 0ee1b5d34aab..3b05d10ca255 100644 --- a/python/testData/typing/conformance/tests/callables_protocol.py +++ b/python/testData/typing/conformance/tests/callables_protocol.py @@ -173,7 +173,7 @@ P = ParamSpec("P") R = TypeVar("R", covariant=True) -class Proto9(Protocol[P, R]): +class Proto9[**P, R](Protocol): other_attribute: int def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R: diff --git a/python/testData/typing/conformance/tests/callables_subtyping.py b/python/testData/typing/conformance/tests/callables_subtyping.py index 0451d6289d50..9cecc843e9fe 100644 --- a/python/testData/typing/conformance/tests/callables_subtyping.py +++ b/python/testData/typing/conformance/tests/callables_subtyping.py @@ -201,7 +201,7 @@ def func6( # > to a Callable parameterized by P. -class ProtocolWithP(Protocol[P]): +class ProtocolWithP[**P](Protocol): def __call__(self, *args: P.args, **kwargs: P.kwargs) -> None: ... diff --git a/python/testData/typing/conformance/tests/classes_classvar.py b/python/testData/typing/conformance/tests/classes_classvar.py index 3f94fe5a6285..5f0ca92410f3 100644 --- a/python/testData/typing/conformance/tests/classes_classvar.py +++ b/python/testData/typing/conformance/tests/classes_classvar.py @@ -11,11 +11,13 @@ from typing import ( ClassVar, Final, Generic, + NamedTuple, ParamSpec, Protocol, TypeAlias, TypeVar, TypeVarTuple, + TypedDict, assert_type, cast, ) @@ -78,6 +80,20 @@ bad11: ClassVar[int] = 3 # E: ClassVar not allowed here bad12: TypeAlias = ClassVar[str] # E: ClassVar not allowed here +# > ``ClassVar`` cannot be used as a qualifier for a TypedDict item or a +# > NamedTuple field. Such usage also generates an error at runtime. + + +class TDWithClassVar(TypedDict): + a: int + b: ClassVar[int] # E: ClassVar not allowed in a TypedDict + + +class NTWithClassVar(NamedTuple): + a: int + b: ClassVar[int] # E: ClassVar not allowed in a NamedTuple + + assert_type(ClassA.good1, int) assert_type(ClassA.good2, list[str]) assert_type(ClassA.good3, Any) diff --git a/python/testData/typing/conformance/tests/generics_defaults_referential.py b/python/testData/typing/conformance/tests/generics_defaults_referential.py index 30c0281f6657..ee2d9594fe95 100644 --- a/python/testData/typing/conformance/tests/generics_defaults_referential.py +++ b/python/testData/typing/conformance/tests/generics_defaults_referential.py @@ -20,7 +20,6 @@ StepT = TypeVar("StepT", default=int | None) class slice(Generic[StartT, StopT, StepT]): ... -assert_type(slice, type[slice[int, int, int | None]]) assert_type(slice(), slice[int, int, int | None]) assert_type(slice[str](), slice[str, str, int | None]) assert_type(slice[str, bool, complex](), slice[str, bool, complex]) diff --git a/python/testData/typing/conformance/tests/generics_mixed_variance_inference.py b/python/testData/typing/conformance/tests/generics_mixed_variance_inference.py new file mode 100644 index 000000000000..e7cbfd752978 --- /dev/null +++ b/python/testData/typing/conformance/tests/generics_mixed_variance_inference.py @@ -0,0 +1,21 @@ +""" +Tests variance inference for mixed type parameters. +""" + +# Specification: https://typing.readthedocs.io/en/latest/spec/generics.html#variance-inference + +class Mixed[T, *Ts, **P]: + def f(self, x: T, /, *args: P.args, **kwargs: P.kwargs) -> tuple[*Ts]: + raise NotImplementedError + +# T should be contra +_1: Mixed[int, []] = Mixed[object, []]() # OK +_2: Mixed[int, []] = Mixed[bool, []]() # E + +# Ts should be co +_3: Mixed[int, int, []] = Mixed[int, object, []]() # E +_4: Mixed[int, int, []] = Mixed[int, bool, []]() # OK + +# P should be contra +_5: Mixed[int, [int]] = Mixed[int, [object]]() # OK +_6: Mixed[int, [int]] = Mixed[int, [bool]]() # E diff --git a/python/testData/typing/conformance/tests/generics_paramspec_variance.py b/python/testData/typing/conformance/tests/generics_paramspec_variance.py new file mode 100644 index 000000000000..04866e941c9d --- /dev/null +++ b/python/testData/typing/conformance/tests/generics_paramspec_variance.py @@ -0,0 +1,152 @@ +""" +Tests variance of ParamSpec. +""" + +# Specification: https://typing.readthedocs.io/en/latest/spec/generics.html#variance-inference + + +from typing import Callable, Generic, ParamSpec + + +class InvariantParamSpec[**InOutP]: + a: Callable[InOutP, None] + +in_out_obj: InvariantParamSpec[object] = InvariantParamSpec[int]() # E +in_out_int: InvariantParamSpec[int] = InvariantParamSpec[object]() # E + + +class ContravariantParamSpec[**InP]: + def f(self, *args: InP.args, **kwargs: InP.kwargs): ... + +in_obj: ContravariantParamSpec[object] = ContravariantParamSpec[int]() # E +in_int: ContravariantParamSpec[int] = ContravariantParamSpec[object]() # OK + + +class CovariantParamSpec[**OutP]: + def f(self, fn: Callable[OutP, None]) -> None: + raise NotImplementedError + + +out_int: CovariantParamSpec[int] = CovariantParamSpec[object]() # E +out_obj: CovariantParamSpec[object] = CovariantParamSpec[int]() # OK + +# cases involving keyword-only, positional-only parameters, parameter names, defaults and differing callable arities +class Box[T]: + t: T + + def __init__(self, t: T): ... + + +def f(a: int): ... +def kw(*, a: int): ... +def pos(a: int, /): ... +def names(b: int): ... +def default(a: int = 1): ... +def arity(a: int, b: str): ... + + +class InitP[**P]: # contravariant + def __init__(self, fn: Callable[P, None]): ... + + def usage(self) -> Callable[P, None]: + """infer contravariance""" + raise NotImplementedError + + +# `InitP` produces a `Callable[P, None]`, so a replacement is only safe if it +# accepts every call form that `InitP[(a: int)]` accepts. +in_box = Box(InitP(f)) + +in_kw_p = InitP(kw) +in_box.t = in_kw_p # E +in_pos_p = InitP(pos) +in_box.t = in_pos_p # E +in_names_p = InitP(names) +in_box.t = in_names_p # E +in_default_p = InitP(default) +in_box.t = in_default_p # OK +in_arity_p = InitP(arity) +in_box.t = in_arity_p # E + + +class OutitP[**P]: # covariant + def __init__(self, fn: Callable[P, None]): ... + + def usage(self, fn: Callable[P, None]): + """infer covariance""" + + +# `OutitP` consumes a `Callable[P, None]`, so the safe direction is reversed: a +# replacement is only safe if `Callable[(a: int), None]` can be passed to it. +out_box = Box(OutitP(f)) + +out_kw_p = OutitP(kw) +out_box.t = out_kw_p # OK +out_pos_p = OutitP(pos) +out_box.t = out_pos_p # OK +out_names_p = OutitP(names) +out_box.t = out_names_p # E +out_default_p = OutitP(default) +out_box.t = out_default_p # E +out_arity_p = OutitP(arity) +out_box.t = out_arity_p # E + + +# old style +P = ParamSpec("P") # OK +InP = ParamSpec("InP", contravariant=True) # OK +OutP = ParamSpec("OutP", covariant=True) # OK +InferP = ParamSpec("InferP", infer_variance=True) # OK +InvP1 = ParamSpec("InvP1", covariant=True, contravariant=True) # E +InvP2 = ParamSpec("InvP2", covariant=True, infer_variance=True) # E +InvP3 = ParamSpec("InvP3", contravariant=True, infer_variance=True) # E + +class InvariantParamSpecOld(Generic[P]): + def f(self, fn: Callable[P, None]) -> Callable[P, None]: # OK + raise NotImplementedError + +in_out_old: InvariantParamSpecOld[int] +in_out_old = InvariantParamSpecOld[int]() # OK +in_out_old = InvariantParamSpecOld[bool]() # E +in_out_old = InvariantParamSpecOld[object]() # E + +class ContravariantParamSpecOld(Generic[InP]): + def in_f(self) -> Callable[InP, None]: # OK + raise NotImplementedError + + def out_f(self, fn: Callable[InP, None]) -> None: # E + raise NotImplementedError + + +in_obj_old: ContravariantParamSpecOld[object] = ContravariantParamSpecOld[int]() # E +in_int_old: ContravariantParamSpecOld[int] = ContravariantParamSpecOld[object]() # OK + + +class CovariantParamSpecOld(Generic[OutP]): + def in_f(self) -> Callable[OutP, None]: # E + raise NotImplementedError + def out_f(self, fn: Callable[OutP, None]) -> None: # OK + raise NotImplementedError + + +out_int_old: CovariantParamSpecOld[int] = CovariantParamSpecOld[object]() # E +out_obj_old: CovariantParamSpecOld[object] = CovariantParamSpecOld[int]() # OK + + +# `infer_variance=True` on a traditional `ParamSpec` +class InferredContravariantParamSpecOld(Generic[InferP]): + def in_f(self) -> Callable[InferP, None]: # OK + raise NotImplementedError + + +infer_in_obj_old: InferredContravariantParamSpecOld[object] = InferredContravariantParamSpecOld[int]() # E +infer_in_int_old: InferredContravariantParamSpecOld[int] = InferredContravariantParamSpecOld[object]() # OK + + +class InferredCovariantParamSpecOld(Generic[InferP]): + def out_f(self, fn: Callable[InferP, None]) -> None: # OK + raise NotImplementedError + + +infer_out_int_old: InferredCovariantParamSpecOld[int] = InferredCovariantParamSpecOld[object]() # E +infer_out_obj_old: InferredCovariantParamSpecOld[object] = InferredCovariantParamSpecOld[int]() # OK diff --git a/python/testData/typing/conformance/tests/generics_typevartuple_basic.py b/python/testData/typing/conformance/tests/generics_typevartuple_basic.py index 47b493ff093d..672960270ee9 100644 --- a/python/testData/typing/conformance/tests/generics_typevartuple_basic.py +++ b/python/testData/typing/conformance/tests/generics_typevartuple_basic.py @@ -7,6 +7,7 @@ Tests basic usage of TypeVarTuple. from typing import Generic, NewType, TypeVarTuple, assert_type Ts = TypeVarTuple("Ts") +Ts1 = TypeVarTuple("Ts1") class Array1(Generic[*Ts]): @@ -60,11 +61,10 @@ class ClassA(Generic[Shape]): # E: not unpacked ... -# > TypeVarTuple does not yet support specification of variance, bounds, constraints. +# > TypeVarTuple does not support type constraints. -Ts1 = TypeVarTuple("Ts1", covariant=True) # E Ts2 = TypeVarTuple("Ts2", int, float) # E -Ts3 = TypeVarTuple("Ts3", bound=int) # E +Ts3 = TypeVarTuple("Ts3", bound=int) # E: bound is unavailable in Python 3.12 # > If the same TypeVarTuple instance is used in multiple places in a signature @@ -104,5 +104,9 @@ def func3(x: Array[Height], y: Array[Width], z: Array[Height, Width]): # > Only a single type variable tuple may appear in a type parameter list. -class Array3(Generic[*Ts1, *Ts2]): # E +class Array3(Generic[*Ts, *Ts1]): # E + ... + + +class Array4[*Ts1, *Ts2]: # E ... diff --git a/python/testData/typing/conformance/tests/generics_typevartuple_variance.py b/python/testData/typing/conformance/tests/generics_typevartuple_variance.py new file mode 100644 index 000000000000..ace05d77315e --- /dev/null +++ b/python/testData/typing/conformance/tests/generics_typevartuple_variance.py @@ -0,0 +1,117 @@ +""" +Tests variance of TypeVarTuple. +""" + +# Specification: https://typing.readthedocs.io/en/latest/spec/generics.html#variance-inference + + +from typing import Generic +from typing_extensions import TypeVarTuple + +class InvariantTypeVarTuple[*InOutTs]: + a: tuple[*InOutTs] + +in_out_obj: InvariantTypeVarTuple[object] = InvariantTypeVarTuple[int]() # E +in_out_int: InvariantTypeVarTuple[int] = InvariantTypeVarTuple[object]() # E +in_out_int = InvariantTypeVarTuple[int]() +in_out_variadic_int: InvariantTypeVarTuple[*tuple[int, ...]] = InvariantTypeVarTuple[*tuple[object, ...]]() # E +in_out_variadic_object: InvariantTypeVarTuple[*tuple[object, ...]] = InvariantTypeVarTuple[*tuple[int, ...]]() # E +in_out_empty: InvariantTypeVarTuple[()] = InvariantTypeVarTuple[()]() # OK +in_out_fixed_from_variadic: InvariantTypeVarTuple[int] = InvariantTypeVarTuple[*tuple[int, ...]]() # E +in_out_variadic_from_fixed: InvariantTypeVarTuple[*tuple[int, ...]] = InvariantTypeVarTuple[int]() # E + + +class ContravariantTypeVarTuple[*InTs]: + def f(self, t: tuple[*InTs]): + raise NotImplementedError + +in_obj: ContravariantTypeVarTuple[object, object] = ContravariantTypeVarTuple[object, int]() # E +in_int: ContravariantTypeVarTuple[int] = ContravariantTypeVarTuple[object]() # OK +in_variadic_int: ContravariantTypeVarTuple[*tuple[int, ...]] = ContravariantTypeVarTuple[*tuple[object, ...]]() # OK +in_variadic_object: ContravariantTypeVarTuple[*tuple[object, ...]] = ContravariantTypeVarTuple[*tuple[int, ...]]() # E +in_empty: ContravariantTypeVarTuple[()] = ContravariantTypeVarTuple[()]() # OK +in_fixed_from_variadic: ContravariantTypeVarTuple[int] = ContravariantTypeVarTuple[*tuple[int, ...]]() # OK +in_variadic_from_fixed: ContravariantTypeVarTuple[*tuple[int, ...]] = ContravariantTypeVarTuple[int]() # E + + +class CovariantTypeVarTuple[*OutTs]: + def f(self) -> tuple[*OutTs]: + raise NotImplementedError + + +out_int: CovariantTypeVarTuple[int] = CovariantTypeVarTuple[object]() # E +out_obj: CovariantTypeVarTuple[object] = CovariantTypeVarTuple[int]() # OK +out_multiple1: CovariantTypeVarTuple[int, int] = CovariantTypeVarTuple[bool, bool]() # OK +out_multiple2: CovariantTypeVarTuple[int, int] = CovariantTypeVarTuple[bool, object]() # E +out_multiple3: CovariantTypeVarTuple[int, int] = CovariantTypeVarTuple[object, bool]() # E +out_multiple4: CovariantTypeVarTuple[int, int] = CovariantTypeVarTuple[object, object]() # E +out_variadic_int: CovariantTypeVarTuple[*tuple[int, ...]] = CovariantTypeVarTuple[*tuple[object, ...]]() # E +out_variadic_object: CovariantTypeVarTuple[*tuple[object, ...]] = CovariantTypeVarTuple[*tuple[int, ...]]() # OK +out_empty: CovariantTypeVarTuple[()] = CovariantTypeVarTuple[()]() # OK +out_fixed_from_variadic: CovariantTypeVarTuple[int] = CovariantTypeVarTuple[*tuple[int, ...]]() # E +out_variadic_from_fixed: CovariantTypeVarTuple[*tuple[int, ...]] = CovariantTypeVarTuple[int]() # OK + +Ts = TypeVarTuple("Ts") # OK +InferTs = TypeVarTuple("InferTs", infer_variance=True) # OK +InvTs1 = TypeVarTuple("InvTs1", covariant=True, contravariant=True) # E +InvTs2 = TypeVarTuple("InvTs2", covariant=True, infer_variance=True) # E +InvTs3 = TypeVarTuple("InvTs3", contravariant=True, infer_variance=True) # E + +class InvariantTypeVarTupleOld(Generic[*Ts]): + def in_f(self, *args: *Ts) -> None: # OK + raise NotImplementedError + + def out_f(self) -> tuple[*Ts]: # OK + raise NotImplementedError + + +obj_old: InvariantTypeVarTupleOld[object] = InvariantTypeVarTupleOld[int]() # E +int_old: InvariantTypeVarTupleOld[int] = InvariantTypeVarTupleOld[object]() # E +int_old = InvariantTypeVarTupleOld[int]() + + +InTs = TypeVarTuple("InTs", contravariant=True) + +class ContravariantTypeVarTupleOld(Generic[*InTs]): + def in_f(self, *args: *InTs) -> None: # OK + raise NotImplementedError + + def out_f(self) -> tuple[*InTs]: # E + raise NotImplementedError + + +in_obj_old: ContravariantTypeVarTupleOld[object] = ContravariantTypeVarTupleOld[int]() # E +in_int_old: ContravariantTypeVarTupleOld[int] = ContravariantTypeVarTupleOld[object]() # OK + + +OutTs = TypeVarTuple("OutTs", covariant=True) + +class CovariantTypeVarTupleOld(Generic[*OutTs]): + def in_f(self, *args: *OutTs) -> None: # E + raise NotImplementedError + + def out_f(self) -> tuple[*OutTs]: # OK + raise NotImplementedError + + +out_int_old: CovariantTypeVarTupleOld[int] = CovariantTypeVarTupleOld[object]() # E +out_obj_old: CovariantTypeVarTupleOld[object] = CovariantTypeVarTupleOld[int]() # OK + + +# `infer_variance=True` on a traditional `TypeVarTuple` +class InferredContravariantTypeVarTupleOld(Generic[*InferTs]): + def in_f(self, *args: *InferTs) -> None: # OK + raise NotImplementedError + + +infer_in_obj_old: InferredContravariantTypeVarTupleOld[object] = InferredContravariantTypeVarTupleOld[int]() # E +infer_in_int_old: InferredContravariantTypeVarTupleOld[int] = InferredContravariantTypeVarTupleOld[object]() # OK + + +class InferredCovariantTypeVarTupleOld(Generic[*InferTs]): + def out_f(self) -> tuple[*InferTs]: # OK + raise NotImplementedError + + +infer_out_int_old: InferredCovariantTypeVarTupleOld[int] = InferredCovariantTypeVarTupleOld[object]() # E +infer_out_obj_old: InferredCovariantTypeVarTupleOld[object] = InferredCovariantTypeVarTupleOld[int]() # OK diff --git a/python/testData/typing/conformance/tests/protocols_class_objects.py b/python/testData/typing/conformance/tests/protocols_class_objects.py index 79de5120484a..2a498438b9bc 100644 --- a/python/testData/typing/conformance/tests/protocols_class_objects.py +++ b/python/testData/typing/conformance/tests/protocols_class_objects.py @@ -105,5 +105,5 @@ pc1: ProtoC1 = ConcreteC1 # E pc2: ProtoC2 = ConcreteC1 # OK pc3: ProtoC1 = ConcreteC2 # E pc4: ProtoC2 = ConcreteC2 # E -pc5: ProtoC1 = ConcreteC3 # E +pc5: ProtoC1 = ConcreteC3 # E?: Explicit ClassVar matching is unspecified pc6: ProtoC2 = ConcreteC3 # OK diff --git a/python/testData/typing/conformance/tests/protocols_definition.py b/python/testData/typing/conformance/tests/protocols_definition.py index bf046ee8c9af..7252dfc164e2 100644 --- a/python/testData/typing/conformance/tests/protocols_definition.py +++ b/python/testData/typing/conformance/tests/protocols_definition.py @@ -114,7 +114,7 @@ v2_good1: Template2 = Concrete2_Good1() # OK v2_bad1: Template2 = Concrete2_Bad1() # E v2_bad2: Template2 = Concrete2_Bad2() # E v2_bad3: Template2 = Concrete2_Bad3() # E -v2_bad4: Template2 = Concrete2_Bad4() # E +v2_bad4: Template2 = Concrete2_Bad4() # E?: Explicit ClassVar matching is unspecified class Template3(Protocol): @@ -339,3 +339,32 @@ v6_good3: Template6 = Concrete6_Good3() # OK v6_bad1: Template6 = Concrete6_Bad1() # E v6_bad2: Template6 = Concrete6_Bad2() # E: named tuple is immutable v6_bad3: Template6 = Concrete6_Bad3() # E: dataclass is frozen + + +# The specification leaves two possible interpretations of a ClassVar protocol +# member. One interpretation requires the implementing attribute to be explicitly +# declared with ClassVar. The other interpretation imposes only structural +# requirements: the attribute must be readable and writable on the class object +# and readable on instances of the class. Both interpretations therefore require +# the following assignments to be rejected. + + +class Template7(Protocol): + val1: ClassVar[int] + + +class Concrete7_Bad1: + def __init__(self) -> None: + self.val1: int = 42 + + +class Concrete7Meta(type): + val1: int = 42 + + +class Concrete7_Bad2(metaclass=Concrete7Meta): + pass + + +v7_bad1: Template7 = Concrete7_Bad1() # E: val1 is not readable on the class object +v7_bad2: Template7 = Concrete7_Bad2() # E: val1 is not readable on instances diff --git a/python/testData/typing/conformance/tests/protocols_variance.py b/python/testData/typing/conformance/tests/protocols_variance.py index 069ab8ecdc90..724692b60d09 100644 --- a/python/testData/typing/conformance/tests/protocols_variance.py +++ b/python/testData/typing/conformance/tests/protocols_variance.py @@ -4,14 +4,15 @@ Tests type variable variance inference for generic protocols. # Specification: https://typing.readthedocs.io/en/latest/spec/protocol.html#generic-protocols -from typing import ParamSpec, Protocol, TypeVar +from typing import Protocol, TypeVar +from typing_extensions import ParamSpec T1 = TypeVar("T1") T2 = TypeVar("T2", bound=int) T3 = TypeVar("T3", bytes, str) T1_co = TypeVar("T1_co", covariant=True) T1_contra = TypeVar("T1_contra", contravariant=True) -P = ParamSpec("P") +P = ParamSpec("P", contravariant=True) R = TypeVar("R", covariant=True) # > Type checkers will warn if the inferred variance is different from the diff --git a/python/testData/typing/conformance/tests/qualifiers_final_annotation.py b/python/testData/typing/conformance/tests/qualifiers_final_annotation.py index 822ea564ad3d..0dc611211bbf 100644 --- a/python/testData/typing/conformance/tests/qualifiers_final_annotation.py +++ b/python/testData/typing/conformance/tests/qualifiers_final_annotation.py @@ -2,7 +2,7 @@ Tests the typing.Final special form. """ -from typing import ClassVar, Final, Literal, NamedTuple, assert_type +from typing import ClassVar, Final, Literal, NamedTuple, TypedDict, assert_type # Specification: https://typing.readthedocs.io/en/latest/spec/qualifiers.html#id1 @@ -122,6 +122,20 @@ def func1(x: Final[list[int]]) -> None: # E ... +# > ``Final`` cannot be used as a qualifier for a TypedDict item or a +# > NamedTuple field. Such usage also generates an error at runtime. + + +class TDWithFinal(TypedDict): + a: int + b: Final[int] # E: Final not allowed in a TypedDict + + +class NTWithFinal(NamedTuple): + a: int + b: Final[int] # E: Final not allowed in a NamedTuple + + # > Type checkers should treat uses of a final name that was initialized with # > a literal as if it was replaced by the literal. For example, the following # > should be allowed: diff --git a/python/testData/typing/conformance/tests/ty.toml b/python/testData/typing/conformance/tests/ty.toml index 986f5e42951a..dcd178048120 100644 --- a/python/testData/typing/conformance/tests/ty.toml +++ b/python/testData/typing/conformance/tests/ty.toml @@ -9,3 +9,4 @@ assert-type-unspellable-subtype = "ignore" invalid-enum-member-annotation = "error" mismatched-type-name = "error" invalid-named-tuple-override = "error" +ambiguous-protocol-member = "error"