I'm trying to extract a pattern that we are using in our code base into a more generic, reusable construct. However, I can't seem to get the generic type annotations to work with mypy.
Here's what I got:
from abc import (
ABC,
abstractmethod
)
import asyncio
import contextlib
from typing import (
Any,
Iterator,
Generic,
TypeVar
)
_TMsg = TypeVar('_TMsg')
class MsgQueueExposer(ABC, Generic[_TMsg]):
@abstractmethod
def subscribe(self, subscriber: 'MsgQueueSubscriber[_TMsg]') -> None:
raise NotImplementedError("Must be implemented by subclasses")
@abstractmethod
def unsubscribe(self, subscriber: 'MsgQueueSubscriber[_TMsg]') -> None:
raise NotImplementedError("Must be implemented by subclasses")
class MsgQueueSubscriber(Generic[_TMsg]):
@contextlib.contextmanager
def subscribe(
self,
msg_queue_exposer: MsgQueueExposer[_TMsg]) -> Iterator[None]:
msg_queue_exposer.subscribe(self)
try:
yield
finally:
msg_queue_exposer.unsubscribe(self)
class DemoMsgQueSubscriber(MsgQueueSubscriber[int]):
pass
class DemoMsgQueueExposer(MsgQueueExposer[int]):
# The following works for mypy:
# def subscribe(self, subscriber: MsgQueueSubscriber[int]) -> None:
# pass
# def unsubscribe(self, subscriber: MsgQueueSubscriber[int]) -> None:
# pass
# This doesn't work but I want it to work :)
def subscribe(self, subscriber: DemoMsgQueSubscriber) -> None:
pass
def unsubscribe(self, subscriber: DemoMsgQueSubscriber) -> None:
pass
I commented out some code that works but doesn't quite fulfill my needs. Basically I want that the DemoMsgQueueExposer
accepts a DemoMsgQueSubscriber
in its subscribe
and unsubscribe
methods. The code type checks just fine if I use MsgQueueSubscriber[int]
as a type but I want it to accept subtypes of that.
I keep running into the following error.
generic_msg_queue.py:55: error: Argument 1 of "subscribe" incompatible with supertype "MsgQueueExposer"
I feel that this has something to do with co-/contravariants but I tried several things before I gave up and came here.
from Get mypy to accept subtype of generic type as a method argument
No comments:
Post a Comment