Repository navigation
Accept nesting Final in ClassVar for dataclasses #18235
Description
Bug Report
[Python 3.13] mypy does not accept nesting ClassVar and Final in class body
The official docs of the typing module say:
Changed in version 3.13:
ClassVarcan now be nested inFinaland vice versa.
The typing specs on qualifiers are more specific:
Finalmay be wrapped only by other type qualifiers (e.g.ClassVaror
Annotation).
In particular, nesting ClassVar and Final is a special case for dataclasses:
Type checkers should infer a final attribute that is initialized in a class
body as being a class variable, except in the case ofdataclasses, where
x: Final[int] = 3creates a dataclass field and instance-level final
attributexwith default value3;x: ClassVar[Final[int]] = 3is
necessary to create a final class variable with value3. In
non-dataclasses, combiningClassVarandFinalis redundant, and type
checkers may choose to warn or error on the redundancy.
To Reproduce
In both classes below the foo statement is not accepted by mypy:
from dataclasses import dataclass
from typing import ClassVar, Final
@dataclass
class Bar:
foo: ClassVar[Final[int]] = 0
@dataclass
class Baz:
foo: Final[ClassVar[int]] = 0Note that the docs only mention ClassVar[Final[int]] and not Final[ClassVar[int]]. In fact, the latter is not considered a class variable by the current dataclasses implementation:
>>> Bar(foo=1) # foo is a class variable
Traceback (most recent call last):
File "<python-input-2>", line 1, in <module>
Bar(foo=1)
~~~^^^^^^^
TypeError: Bar.__init__() got an unexpected keyword argument 'foo'
>>> Baz(foo=1) # foo is an instance variable
Baz(foo=1)Expected Behavior
[Python 3.13] mypy should accept ClassVar[Final[<type>]] in the body of a dataclass
The form ClassVar[Final[int]] conforms with the official typing specs and behaves as expected. I think it should be accepted as part of Python 3.13 support.
The typing specs allow for a warning or error when ClassVar and Final are nested outside of a dataclass body. I think this should result in an error since it is redundant, perhaps only in strict mode.
For the form Final[ClassVar[int]] I am not sure. It could either result in an error or simply be parsed as a final instance variable.
Actual Behavior
The form ClassVar[Final[int]] results in:
error: Final can be only used as an outermost qualifier in a variable annotation [valid-type]
The form Final[ClassVar[int]] results in:
error: Variable should not be annotated with both ClassVar and Final [misc]
The behavior is the same with or without the @dataclass decorator.
Your Environment
- Mypy version used: 1.13.0
- Mypy command-line flags:
- Mypy configuration options from
mypy.ini(and other config files):strict = true - Python version used: 3.13.0
Notes
The typing specs were changed in python/typing#1669
Related discussion is found in python/cpython#89547
The difference between ClassVar[Final[int]] and Final[ClassVar[int]] was noticed in microsoft/pyright#8676 (comment)
This issue is about Python 3.13 so could be added to #17264
This issue is related to #12061
Activity
erictraut commentedon Dec 3, 2024
For additional context, this case is covered by the typing spec conformance tests, and mypy does not currently pass this test case. This is reflected in the conformance test result summary page. (Scroll to the
dataclasses_finalline and hover over the mypy results in the table.)hauntsaninja commentedon Mar 6, 2025
It looks like this has been fixed in #18358