IlyaChch
IlyaChch

Reputation: 11

abstract class annotation with overridable static attribute

I've got abstract class:

import abc
from pydantic import BaseModel

class Abstract(abc.ABC):
    context_class: ClassVar[Type['BaseModel']]
    error: ClassVar[Type[Exception]]

    def __init__(self, data: Dict) -> None:
        self.context = self.context_class(**data)

    @abc.abstractmethod
    def process(self) -> None:
        pass

In it's inheritor I overridden attribute context_class:

class Context(BaseModel):
    email: str

class Concrete(Abstract):
    context_class = Context

    def process(self) -> None:
        print(self.context.email)

Mypy check fails with such error:

... error: "BaseModel" has no attribute "email"

Package versions:

Upvotes: 0

Views: 1299

Answers (1)

IlyaChch
IlyaChch

Reputation: 11

Finally, answer is found. Generic types should be used:

import abc
from typing import ClassVar, Type, Dict, Generic, TypeVar
from pydantic import BaseModel

T = TypeVar('T', bound=BaseModel)


class Abstract(abc.ABC, Generic[T]):
    context_class: ClassVar[Type[T]]
    error: ClassVar[Type[Exception]]

    def __init__(self, data: Dict) -> None:
        self.context = self.context_class(**data)

    @abc.abstractmethod
    def process(self) -> None:
        pass


class Context(BaseModel):
    email: str


class Concrete(Abstract[Context]):
    context_class = Context

    def process(self) -> None:
        print(self.context.email)

Upvotes: 1

Related Questions