Problems with creating a type protocol for Django user class
I have a function that operates on users, but in one of the projects that uses it we don't use Django user. We have a dataclass that pretends to be a user.
Problems started when I was trying to type this function. I couldn't use AbstractBaseUser as the user type, because that would obviously not work in this project with dataclass user.
However, Python has a solution for such problems - protocols!
I quickly created a user protocol containing all features I used in the function:
class ManagerProtocol(Protocol):
def get(self, **kwargs: Any) -> UserProtocol:
...
class UserProtocol(Protocol):
objects: ManagerProtocol
class DoesNotExist(Exception):
...
and adjusted our dataclass user to follow this protocol:
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
and then I ran mypy and got this:
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"
I've read some articles on the web and the solution was clear - use properties instead of class members!
class UserProtocol(Protocol):
@property
def objects(self) -> ManagerProtocol:
...
@property
def DoesNotExist(self) -> Type[Exception]:
...
but after running mypy again another problems emerged:
error: "Callable[[UserProtocol], ManagerProtocol]" has no attribute "get" [attr-defined]
error: Exception type must be derived from BaseException [misc]
The protocol compatibility was ok, but mypy saw errors in places where I actually used the UserProtocol
class.
Do you have any idea how to create a protocol that would work here without causing type errors?