I’m writing an attrs
class called SessionInfo
that looks like this:
from attrs import define, field
@define(kw_only=True)
class ControllerInfo:
controller_data: int = field(default=0)
@define(kw_only=True)
class SessionInfo:
controllers: dict[str, ControllerInfo] = field(factory=dict)
ControllerInfo
should serve as a base class for other classes in order to inherit the original attributes and be able to expand on those.
I’m trying to explain that to the type checker, but for example when doing:
@define
class MyInfo(ControllerInfo):
other_controller_data: str
ctrls = {
"my_controller": MyInfo()
"my_other_controller": MyInfo()
}
session = SessionInfo(ctrls)
mypy returns the following error:
Argument "controllers" to "SessionInfo" has incompatible type "dict[str, MyInfo]"; expected "dict[str, ControllerInfo]"
In itself it’s not a too big of a problem because this is part of a plugin architecture and I know that at runtime it should not cause problems (unless the user specifically doesn’t inherit from ControllerInfo
). At the same time it bothers me a bit in testing and I would like to address this.
I tried using dict[str, builtins.type[ControllerInfo]
because I’m trying to specify that the values of the dictionary should be of type ControllerInfo
and any of its descendants; but apparently that didn’t work, and now my understanding of the differences between builtins.type
and typing.Type
went out the window as well.
So the question is: how do I instruct mypy to understand that the values of Session.controllers
can be descendants of ControllerInfo
?
A secondary question: did I misunderstand the definitions of builtins.type
and typing.Type
? My understanding was:
builtins.type[Class]
is used to specify objects that are of typeClass
and any of its descendants;typing.Type[Class]
is used to specify classes of typeClass
and any of its descendants.
EDIT: sorry for the multiple edits, lots of typos