attrs
attrs copied to clipboard
Type check error with asdict
Starting with version attrs 22.1.0, I started running into a type checking issue when running mypy. In particular, this occurs when calling asdict in parent class where that parent class does not use attrs but the child might.
This is a bit of an odd scenario so I'm not sure if the bug belongs here in attrs, mypy, or should just be an error. However, it did not produce any type checking errors using attrs 21.4.0.
import abc
import attr
from typing import Any, Dict
class BaseModel(abc.ABC):
def to_dict(self) -> Dict[str, Any]:
o = {} # type: Dict[str, Any]
if attr.has(type(self)):
return attr.asdict(self)
return vars(self).copy()
@attr.s(auto_attribs=True)
class Model(BaseModel):
id: int = 0
model = Model(id=1)
if attr.has(type(model)):
data = attr.asdict(model)
Given that your asdict is protected by a has, I suspect that belongs into mypy because it's dynamic logic we can't express in attrs. But @Tinche might know more.
The problem is that we introduced an AttrsInstance Protocol. It looks like we forgot to add a newsfragment.
@hynek I notice that AttrsInstance is not imported in attrs.__init__.pyi only defined in attr.__init__.pyi is that intentional?
@Tinche did we just forget it?
Yeah I think so ;/
Probably worth nothing that has is a perfect match for TypeGuard from Python 3.10 (or its backport from typing-extensions). In attrs/__init__.pyi:
def has(cls: type) -> TypeGuard[type[AttrsInstance]]: ...
Elsewhere:
[...]
if attr.has(type(self)):
# `self` is now an `AttrsInstance`
return attr.asdict(self) # Passes!
But I suspect that attrs would not want to depend on typing-extensions.
fixed by #997