Проблемы с созданием протокола типов для пользовательского класса Django

У меня есть функция, которая оперирует пользователями, но в одном из проектов, где она используется, мы не используем Django user. У нас есть класс данных, который притворяется пользователем.

Проблемы начались, когда я пытался напечатать эту функцию. Я не мог использовать AbstractBaseUser в качестве типа пользователя, потому что это явно не работало бы в этом проекте с dataclass user.

Однако в Python есть решение для таких проблем - протоколы!

Я быстро создал пользовательский протокол, содержащий все возможности, которые я использовал в функции:

class ManagerProtocol(Protocol):
    def get(self, **kwargs: Any) -> UserProtocol:
        ...


class UserProtocol(Protocol):
    objects: ManagerProtocol

    class DoesNotExist(Exception):
        ...

и настроили нашего пользователя класса данных, чтобы он следовал этому протоколу:

class FakeManager:
    def get(self, **kwargs: Any) -> StaticUser:
        return StaticUser(user_id=kwargs.get('user_id', ''))


@dataclass(frozen=True)
class StaticUser:
    user_id: str
    is_authenticated: bool = True
    objects = FakeManager()

    class DoesNotExist(Exception):
        pass

и затем я запустил mypy и получил следующее:

error: Argument 1 to "function" has incompatible type "StaticUser"; expected "UserProtocol"  [arg-type]
note: Following member(s) of "StaticUser" have conflicts:
note:     DoesNotExist: expected "Type[UserProtocol.DoesNotExist]", got "Type[StaticUser.DoesNotExist]"
note:     objects: expected "ManagerProtocol", got "FakeManager"

Я прочитал несколько статей в Интернете, и решение было ясным - использовать свойства вместо членов класса!

class UserProtocol(Protocol):
    @property
    def objects(self) -> ManagerProtocol:
        ...

    @property
    def DoesNotExist(self) -> Type[Exception]:
        ...

но после повторного запуска mypy возникли другие проблемы:

error: "Callable[[UserProtocol], ManagerProtocol]" has no attribute "get"  [attr-defined]
error: Exception type must be derived from BaseException  [misc]

Совместимость протоколов была в порядке, но mypy видел ошибки в тех местах, где я действительно использовал класс UserProtocol.

У вас есть идеи, как создать протокол, который бы работал здесь, не вызывая ошибок типа?

Вернуться на верх