Closed
Description
This issue is copied, mostly verbatim, from here: microsoft/pyright#3245.
If a @dataclass
field is initialized with a descriptor as a default value, mypy should use the value type of the __set__
method for the descriptor when determining the type of the corresponding parameter within the synthesized __init__
method.
Types are also evaluated incorrectly in this case.
from dataclasses import dataclass
from typing import Any, cast
class MyDescriptor:
def __get__(self, __obj: object | None, __owner: Any) -> "int | MyDescriptor":
if __obj is None:
return self
return cast(Any, __obj)._x
def __set__(self, __obj: object | None, __value: int) -> None:
if __obj is not None:
cast(Any, __obj)._x = __value
@dataclass
class Foo:
y: MyDescriptor = MyDescriptor()
f = Foo(3) # Currently a false positive error in mypy
print(f.y) # 3
f.y = 4
print(f.y) # 4
print(Foo.y) # MyDescriptor object
reveal_type(f.y) # int | MyDescriptor, which is wrong
reveal_type(Foo.y) # int | MyDescriptor, which is wrong
To Reproduce
Run mypy against the above script.
Expected Behavior
No Errors
Actual Behavior
test.py:23: error: Argument 1 to "Foo" has incompatible type "int"; expected "MyDescriptor"
test.py:30: note: Revealed type is "Union[builtins.int, test.MyDescriptor]"
test.py:31: note: Revealed type is "Union[builtins.int, test.MyDescriptor]"
Found 1 error in 1 file (checked 1 source file)
Your Environment
- OS: Ubuntu 22.04.1
- Mypy version used: 0.982
- Mypy command-line flags: None
- Mypy configuration options from
mypy.ini
(and other config files): None - Python version used: 3.10.6