How to correctly add type annotations to python Mixin?

Viewed 410

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?

0 Answers
Related