File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -660,6 +660,14 @@ def collect_attributes(self) -> list[DataclassAttribute] | None:
660660 else :
661661 self ._api .fail ('"kw_only" argument must be a boolean literal' , stmt .rvalue )
662662
663+ # Allow bare x: Final[int] in class body, since it will be set in the generated
664+ # __init__() method (unless it is an InitVar), to match regular class semantics.
665+ if node .is_final and not node .is_classvar and node .final_unset_in_class :
666+ if is_init_var :
667+ self ._api .fail ("InitVar cannot be final" , stmt .rvalue )
668+ else :
669+ node .final_set_in_init = True
670+
663671 if sym .type is None and node .is_final and node .is_inferred :
664672 # This is a special case, assignment like x: Final = 42 is classified
665673 # annotated above, but mypy strips the `Final` turning it into x = 42.
Original file line number Diff line number Diff line change @@ -2698,3 +2698,30 @@ class ClassB(ClassA):
26982698 def value(self) -> int:
26992699 return 0
27002700[builtins fixtures/dict.pyi]
2701+
2702+ [case testDataclassAllowsFinalField]
2703+ # flags: --python-version=3.13
2704+ from dataclasses import InitVar, dataclass
2705+ from typing import Final, ClassVar
2706+
2707+ @dataclass
2708+ class C:
2709+ x: int
2710+ y: Final[int]
2711+ z: ClassVar[Final[int]] = 4
2712+
2713+ c = C(1, 2)
2714+ c.y = 3 # E: Cannot assign to final attribute "y"
2715+
2716+ @dataclass
2717+ class D(C):
2718+ x: Final[int] # E: Cannot override writable attribute "x" with a final one
2719+
2720+ @dataclass
2721+ class Bad1:
2722+ x: Final[InitVar[int]] # E: InitVar cannot be final
2723+
2724+ @dataclass
2725+ class Bad2:
2726+ x: InitVar[Final[int]] # E: Final can be only used as an outermost qualifier in a variable annotation
2727+ [builtins fixtures/dict.pyi]
You can’t perform that action at this time.
0 commit comments