Python typing and SOLID principles

  python, python-typing, solid-principles

I’m trying to refactor some classes using SOLID principles in python, and I have a question about how to mix SOLID with python typing.

Suppose I have these classes:

from asyncpg import Pool

class PGQuery:
    async def execute(self, connection: Pool):
        raise NotImplementedError

class PGQueryExecutor:
    def __init__(self, connection: Pool):
        self._connection = connection

    async def execute(self, query: PGQuery):
        return await query.execute(self._connection)


from pydantic import BaseModel, parse_obj_as

class QualitySummary(BaseModel):
    count: int
    score: float

class PGQueryQualitySummary(PGQuery):
    def __init__(self, node: str):
        self.node = node

    async def execute(self, connection: Pool) -> QualitySummary:
        result = await connection.fetchrow(...)

        return parse_obj_as(QualitySummary, result)

Example usage:

pgqueryexecutor = PGQueryExecutor(...)
result = await pgqueryexecutor.execute(PGQueryQualitySummary(...))

The problem is that the inferred type for result is Any, which is the one of the base class PGQuery. I would like (maybe with generics?) that each subclass of PGQuery which implements its own execute method with its own return type is then correctly inferred by the execute method of the PGQueryExecutor, so the return value of:


is exactly the return type of PGQueryAnySubclass.execute.

How can I achieve that?

Source: Python Questions