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
Do you have any idea how to create a protocol that would work here without causing type errors?