I use the service object pattern in my codebase. I have a base class for service objects:
from abc import ABC, abstractmethod
from typing import Generic, TypeVar
T = TypeVar("T", contravariant=True) # input type
R = TypeVar("R", covariant=True) # return type
class BaseService(Generic[T, R], ABC):
"""Service object that strongly types its inputs and outputs."""
inputs: T
def __init__(self, inputs: T):
self.inputs = inputs
@classmethod
def execute(cls, inputs: T, **kwargs) -> R:
instance = cls(inputs, **kwargs)
return instance.process()
@abstractmethod
def process(self) -> R:
"""
Main method to be overridden; contains the business logic.
"""
Its usage is e.g.
from typing import TypedDict
class Inputs(TypedDict):
foo: str
class DoubleService(BaseService[Inputs, str]):
def process(self):
return self.inputs["foo"] * 2
DoubleService.execute({"foo": "bar"}) # returns "barbar"
I want to enforce correct typing of the process method in subclasses. For example, I want all of the following to fail in the type checker:
class Inputs(TypedDict):
foo: str
class InvalidOne(BaseService[Inputs, str]):
def process(self) -> int: # wrong explicit return type
# ...
class InvalidTwo(BaseService[Inputs, str]):
def process(self):
return 1 # wrong implicit return type
Is is possible to achieve this with any existing type checker? I don't care if it's Mypy / Pyright / something else.