Skip to content

Report final dataclass fields that are never initialized - #22314

Open
DipanshuAmbilkar03 wants to merge 2 commits into
python:masterfrom
DipanshuAmbilkar03:fix/final-dataclass-field-init-false
Open

DipanshuAmbilkar03 wants to merge 2 commits into
python:masterfrom
DipanshuAmbilkar03:fix/final-dataclass-field-init-false

Conversation

@DipanshuAmbilkar03

Copy link
Copy Markdown

Fixes #13119

Summary

A Final dataclass field can only be assigned inside __init__(). If the field is declared with field(init=False) and has neither a default nor a default_factory, the generated __init__() never sets it, so the attribute is missing at runtime:

from dataclasses import dataclass, field
from typing import Final

@dataclass
class Foo:
    a: Final[int] = field(init=False)

Foo().a  # AttributeError: 'Foo' object has no attribute 'a'

mypy accepts this today, because the field(...) call counts as an initializer and that is enough to skip the regular "Final name must be initialized with a value" check.

Fix

While collecting dataclass attributes, I report a field when it is final, excluded from the generated __init__() and has neither a default nor a default_factory — that combination means nothing can ever assign the attribute.

Fields with a default, plain Final fields that the generated __init__() sets, and fields of custom dataclass_transform specs keep the current behaviour.

Test

testDataclassFinalFieldNotInInit in test-data/unit/check-dataclasses.test covers the reported case plus the three shapes that must stay accepted: field(init=False, default=0), field(init=False, default_factory=int) and a plain Final[int] = 0.

Verification

  • pytest mypy/test/testcheck.py -k "Dataclass or dataclass" — 212 passed.
  • pytest mypy/test/testfinegrained.py -k dataclass — 14 passed.
  • python -m mypy --config-file mypy_self_check.ini -p mypy — clean.
  • Full mypy/test suite is running in CI as part of this PR.

DipanshuAmbilkar03 and others added 2 commits October 29, 2026 00:01
A `Final` dataclass attribute can only be assigned inside `__init__()`. If
the field is declared with `field(init=False)` and has neither a `default`
nor a `default_factory`, nothing ever sets it, so reading the attribute
fails with `AttributeError` at runtime.

The `field(...)` call counted as an initializer, so the "Final name must be
initialized with a value" check was skipped. Report the field instead when it
is final, excluded from the generated `__init__()` and has no default value.
@github-actions

Copy link
Copy Markdown
Contributor

According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

no error when setting init=False on Final field in dataclass

1 participant