I have two abstract base classes that are linked, and should be subclassed together. For the sake of a minimal example, let's say its some class TobeProcessed
, and a another class Processor
that performs some processing on instances of the TobeProcessed
class. I made the Processor
Generic
with the type of the TobeProcessed
class as type-argument.
from abc import ABC, abstractmethod
from typing import Generic, TypeVar
class TobeProcessed(ABC):
pass
TobeProcessedType = TypeVar("TobeProcessedType", bound=TobeProcessed)
class Processor(ABC, Generic[TobeProcessedType]):
@abstractmethod
def process(self, to_be_processed: TobeProcessedType) -> None:
pass
Now I have some concrete implementations of both classes:
class TobeProcessedConcrete(TobeProcessed):
pass
class ProcessorConcrete(Processor[TobeProcessedConcrete]):
def process(self, to_be_processed: TobeProcessedConcrete) -> None:
return None
Finally, I have a "wrapper" class which has an attribute processor
which is an instance of any subclass of the Processor
class.
class WrapperClass:
processor: Processor
def __init__(self, processor: Processor) -> None:
self.processor = processor
processor = ProcessorConcrete()
wrapper = WrapperClass(processor=processor)
If I check this with mypy
with --disallow-any-generics
(or --strict
), I get two errors for WrapperClass
because I omitted the type parameter for Processor
, which makes sense. However, if I replace Processor
with Processor[TobeProcessed]
, I get an error for the line wrapper = WrapperClass(processor=processor)
:
Argument "processor" to "WrapperClass" has incompatible type "ProcessorConcrete"; expected "Processor[TobeProcessed]"
.
Is there a way to do this without errors, and without making mypy
less strict?
It should be Processor[TobeProcessedType]
instead.
from abc import ABC, abstractmethod
from typing import Generic, TypeVar
class TobeProcessed(ABC):
pass
TobeProcessedType = TypeVar("TobeProcessedType", bound=TobeProcessed)
class Processor(ABC, Generic[TobeProcessedType]):
@abstractmethod
def process(self, to_be_processed: TobeProcessedType) -> None:
pass
class TobeProcessedConcrete(TobeProcessed):
pass
class ProcessorConcrete(Processor[TobeProcessedConcrete]):
def process(self, to_be_processed: TobeProcessedConcrete) -> None:
return None
class WrapperClass(Generic[TobeProcessedType]):
processor: Processor[TobeProcessedType]
def __init__(self, processor: Processor[TobeProcessedType]) -> None:
self.processor = processor
processor = ProcessorConcrete()
wrapper = WrapperClass(processor=processor)