The Code Setup
I have the following class that I want to insert a new feature using Mixins:
class InputCollection(StringReprMixin, AbstractVariableCollection):
def __init__(self, data: Optional[ValidInputCollection]):
super().__init__()
# rest of the code
This is the Mixin implementation I did following the mypy documentation using Protocols:
class StringReprMixin:
def __str__(self: HasEmptyProtocol) -> str:
if self.empty:
return "Empty collection."
else:
return _collection_to_string(self)
The HasEmptyProtocol is to enable the mypy checker that the mixin has the emptyproperty. The _collection_to_string function has the following signature:
CollectionType = Union[InputCollection, OutputCollection, ExpressionCollection]
def _collection_to_string(collection: CollectionType):
# rest of function code
The problem
I don't know how to make the mypy correctly check on the call of _collection_to_string in the StringReprMixin function, since the mypy checker thinks that the self is a instance of HasEmptyProtocol instead of any of the classes in CollectionType.
This is the error thrown by the static checker:
Argument 1 to "_collection_to_string" has incompatible type "HasEmptyProtocol"; expected "Union[InputCollection, OutputCollection, ExpressionCollection]"
What I have tried
I've seen some questions/issues, in particular, this one seems to work. However, to me, the use of class attributes in a Mixin defeats the purpose of a Protocol subclass as suggested by the mypy docs.
What is working for me
I did a cast, together with a runtime check, of the InputCollection instance before calling _collection_to_string:
class StringReprMixin:
def __str__(self: HasEmptyProtocol) -> str:
if self.empty:
return "Empty collection."
else:
if TYPE_CHECKING:
self = cast(CollectionType, self)
return __collection_to_string(self)
However, I have no idea if this is proper way handle referencing of instances inside of a Mixin that is type-annotated.
So the final question is:
Is this the correct way to annotate this kind Mixin?