Skip to content

overloaded __post_init__ in a dataclass: [override] error for an overload item that does not take the InitVar type #22385

Open

Description

@DerekLaymn

Bug Report

For a dataclass with an InitVar, mypy checks the user's __post_init__ against the signature built from the InitVar fields (added in #15503). When __post_init__ is overloaded, every overload item is checked on its own, so an item that does not take the InitVar type is reported as an incompatible override even though another item does. The overloaded method as a whole accepts what the dataclass passes, and CPython runs the program.

To Reproduce

from dataclasses import InitVar, dataclass
from typing import overload


@dataclass
class Record:
    value: InitVar[int]

    @overload
    def __post_init__(self, value: int) -> None: ...
    @overload
    def __post_init__(self, value: str) -> None: ...
    def __post_init__(self, value: int | str) -> None:
        print(type(value))


Record(1)

Actual Behavior

$ mypy --python-version 3.13 test_bug.py
test_bug.py:12: error: Argument 2 of "__post_init__" is incompatible with supertype "dataclass"; supertype defines the argument type as "int"  [override]
Found 1 error in 1 file (checked 1 source file)

$ python test_bug.py
<class 'int'>

The error is on the str item (line 12). The int item and the implementation (int | str) are not reported.

Expected Behavior

No error. The generated call is __post_init__(value) with an int, which the first overload accepts. For an ordinary method, mypy already accepts an overloaded override of a non-overloaded method when one item is compatible:

from typing import overload


class Base:
    def post(self, value: int) -> None: ...


class Child(Base):
    @overload
    def post(self, value: int) -> None: ...
    @overload
    def post(self, value: str) -> None: ...
    def post(self, value: int | str) -> None:
        print(type(value))

mypy test_control.py prints Success: no issues found. If no item takes the InitVar type (for example overloads for str and bytes with InitVar[int]), an error is right, and mypy reports both items.

I read checker.py on master: check_func_def calls dataclasses_plugin.check_post_init(self, defn, defn.info) for a function named __post_init__, and check_post_init passes defn.type to check_override. For an overloaded method defn is a single item (the line of the error above) and not the Overloaded type, which would explain the difference to the ordinary override. I did not debug it further.

Playground URL
My Environment

  • Mypy version used: 2.4.0, 2.4.1 and master 2.5.0+dev.879da562
  • Mypy command-line flags: --python-version 3.13
  • Mypy configuration options from mypy.ini (and other config files): none
  • Python version used: 3.13.16
  • Operating system: Linux

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmypy got something wrong

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions