-
-
Notifications
You must be signed in to change notification settings - Fork 518
Description
Enhancement
What's wrong
The current type stubs define the authenticate method of the ModelBackend (django.contrib.auth.backends.ModelBackend) as such:
def authenticate(
self,
request: HttpRequest | None,
username: str | None = ...,
password: str | None = ...,
**kwargs: Any,
) -> _UserModel | None: ...The parent class, BaseBackend defines it as such:
def authenticate(self, request: HttpRequest | None, **kwargs: Any) -> _UserModel | None: ...When Django looks for which authentication backend to use, it'll always call said backend using the parameters as kwargs, until it finds the first backend that accepts the parameters and returns a valid user (or None if they all fail). The documentation itself instructs the user to define it's own kwargs when defining a custom authentication backend (relevant docs).
However, a very common use case here is to subclass ModelBackend instead of BaseBackend, in cases where we want to make simple adjustments to how authentication is done, but not how it's handled once you have the specific user; in this cases, you'll subclass the ModelBackend, which already has all the code to handle permissions that BaseBackend does not, and simply overwrite the authenticate method so that instead of, for example, a username and password, it uses a token or a code or something of the sorts. For example:
class MyCustomBackend(ModelBackend):
def authenticate(self, code: Optional[str] = None, **kwargs: Any) -> Optional[User]:
return User.get_user_for_code(code)In this simple example Mypy will give an "override" error: Signature of "authenticate" incompatible with supertype "ModelBackend", even though this backend does not use the username / password at all.
Alternatives
There are already alternatives to getting around this of course; simply #type: ignore[override] will do, or adding the typed arguments to the definition even though they are not used at all, as such:
class MyCustomBackend(ModelBackend):
def authenticate(
self,
username: Optional[str] = None,
password: Optional[str] = None,
code: Optional[str] = None,
**kwargs: Any
) -> Optional[User]:
return User.get_user_for_code(code)How is that should be
The stubs for the ModelBackend should not override the parent class' method definition at all (it should not define it at all and simply inherit). This will be inline to how all authentication backends are used, and allow users to override with their own type definitions without extra work.
System information
- OS: -
pythonversion: 3.13.2djangoversion: 5.1.7mypyversion: 1.15.0django-stubsversion: 5.1.3django-stubs-extversion: 5.1.3