Small case to reproduce:
from typing import Tuple
from dataclasses import dataclass
@dataclass
class Foo:
spams: Tuple[int, ...]
def __init__(self, *spams: int) -> None:
self.spams = spams
def build_foo(*spams: int) -> Foo:
return Foo(*spams)
Checking that program with mypy 0.670 (Python 3.6), results in:
bug.py:13: error: Argument 1 to "Foo" has incompatible type "*Tuple[int, ...]"; expected "Tuple[int, ...]"
Without the @dataclass decorator the program passes. It seems that the dataclass is hiding the actual __init__.
Hm, it looks like this behavior is unspecified. I just looked in the PEP, and it explicitly recommends using @dataclass(init=False) for custom __init__ methods, see https://www.python.org/dev/peps/pep-0557/#custom-init-method. My works correctly with init=False (i.e. doesn't auto-generate the __init__()).
On the other hand, mypy probably should follow the runtime behavior for such case. This is however very low priority, since mypy works correctly in the documented case.
I think that the python3.7 documentation defines the behavior:
init: If true (the default), a __init__() method will be generated.
If the class already defines __init__(), this parameter is ignored.
So if you have an __init__, then the dataclass is going to ignore the property that will instruct it to create an __init__ method (at least, that's how I read it).
Most helpful comment
Hm, it looks like this behavior is unspecified. I just looked in the PEP, and it explicitly recommends using
@dataclass(init=False)for custom__init__methods, see https://www.python.org/dev/peps/pep-0557/#custom-init-method. My works correctly withinit=False(i.e. doesn't auto-generate the__init__()).On the other hand, mypy probably should follow the runtime behavior for such case. This is however very low priority, since mypy works correctly in the documented case.