Skip to content

dataclasses with generated __hash__ subclassing Hashable are considered abstract #18962

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
ralismark opened this issue Apr 24, 2025 · 2 comments · May be fixed by #19043
Open

dataclasses with generated __hash__ subclassing Hashable are considered abstract #18962

ralismark opened this issue Apr 24, 2025 · 2 comments · May be fixed by #19043
Labels
bug mypy got something wrong topic-dataclasses

Comments

@ralismark
Copy link

Bug Report

Dataclasses that are hashable (e.g. frozen=True) that extend any abc/protocol requiring __hash__ (e.g. collections.abc.Hashable) is considered abstract and gives an error when trying to be instantiated.

In addition to frozen=True/Hashable, you also get the same error with unsafe_hash=True, as well as using your own protocol or abc that requires __hash__.

To Reproduce

https://mypy-play.net/?mypy=latest&python=3.12&gist=390504f01055e489b12b388eec1de256

from dataclasses import dataclass
from collections.abc import Hashable


@dataclass(frozen=True)
class A:
    a: int


@dataclass(frozen=True)
class B(Hashable):
    a: int


a: Hashable = A(1)  # ok
b = B(1)  # error: Cannot instantiate abstract class "A" with abstract attribute "__hash__"  [abstract]

print(hash(b))  # prints -6644214454873602895

Expected Behavior

This works at runtime -- running the script prints the hash, demonstrating that it has __hash__ defined.

Actual Behavior

main.py:16: error: Cannot instantiate abstract class "B" with abstract attribute "__hash__"  [abstract]

Your Environment

  • Mypy version used: 1.15.0
  • Mypy command-line flags: N/A
  • Mypy configuration options from mypy.ini (and other config files): N/A
  • Python version used: 3.12
@ralismark ralismark added the bug mypy got something wrong label Apr 24, 2025
@A5rocks
Copy link
Collaborator

A5rocks commented Apr 24, 2025

More generally:

from abc import ABC, abstractmethod
import dataclasses

class Hashable(ABC):
    @abstractmethod
    def __hash__(self) -> int:
        ...

@dataclasses.dataclass(frozen=True)
class X(Hashable):
    a: int

X(4)

I suspect this is that mypy doesn't check what methods a plugin adds when looking at whether a class is abstract.

@sterliakov
Copy link
Collaborator

No, there's no distinction between plugin-generated and regular methods for this check. is_abstract is set after semanal, so plugin should have already been called at that point.

This problem is more obvious: mypy does not generate __hash__ on dataclasses at all. At least grepping for hash finds no matches in dataclass plugin code. A is accepted because we have object.__hash__, so A is indeed hashable from mypy perspective. B explicitly inherits from Hashable and thus Hashable.__hash__ is the highest MRO entry, and it's abstract.

Probably we should just generate __hash__ on dataclasses. This should be easy to do, dunder-hash is simple and non-generic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-dataclasses
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants