From 2b02ea6307283beffc41bfcb339648423f864903 Mon Sep 17 00:00:00 2001 From: Noelle Leigh <5957867+noelleleigh@users.noreply.github.com> Date: Fri, 31 May 2024 12:35:51 -0400 Subject: [PATCH 01/14] BaseUserManager.get_by_natural_key: username is str The implementation doesn't suggest that None is valid. --- django-stubs/contrib/auth/base_user.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django-stubs/contrib/auth/base_user.pyi b/django-stubs/contrib/auth/base_user.pyi index b1fdb132c..0739409e5 100644 --- a/django-stubs/contrib/auth/base_user.pyi +++ b/django-stubs/contrib/auth/base_user.pyi @@ -14,7 +14,7 @@ class BaseUserManager(models.Manager[_ModelT]): def make_random_password( self, length: int = ..., allowed_chars: str = ... ) -> str: ... - def get_by_natural_key(self, username: str | None) -> _ModelT: ... + def get_by_natural_key(self, username: str) -> _ModelT: ... class AbstractBaseUser(models.Model): REQUIRED_FIELDS: list[str] = ... From 2ea97cc1fd32f18337a7d31ad69d81dcf9e56b07 Mon Sep 17 00:00:00 2001 From: Noelle Leigh <5957867+noelleleigh@users.noreply.github.com> Date: Fri, 31 May 2024 12:41:01 -0400 Subject: [PATCH 02/14] auth/models.py: Make _AnyUser more specific Any custom user model should inherit from AbstractUser --- django-stubs/contrib/auth/models.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django-stubs/contrib/auth/models.pyi b/django-stubs/contrib/auth/models.pyi index 0948354df..e7cb93b06 100644 --- a/django-stubs/contrib/auth/models.pyi +++ b/django-stubs/contrib/auth/models.pyi @@ -11,7 +11,7 @@ from django.db import models from django.db.models.base import Model from django.db.models.manager import EmptyManager, ManyToManyRelatedManager -_AnyUser = Model | AnonymousUser +_AnyUser = AbstractUser | AnonymousUser _T = TypeVar("_T", bound=Model) From bad570e0a3f77da473a4d11a6444367e0ee54eea Mon Sep 17 00:00:00 2001 From: Noelle Leigh <5957867+noelleleigh@users.noreply.github.com> Date: Fri, 31 May 2024 12:41:26 -0400 Subject: [PATCH 03/14] Group.natural_key: Returns a tuple with a single string --- django-stubs/contrib/auth/models.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django-stubs/contrib/auth/models.pyi b/django-stubs/contrib/auth/models.pyi index e7cb93b06..35a23e155 100644 --- a/django-stubs/contrib/auth/models.pyi +++ b/django-stubs/contrib/auth/models.pyi @@ -46,7 +46,7 @@ class Group(models.Model): name = models.CharField(max_length=150) permissions = models.ManyToManyField[Permission, Any](Permission) - def natural_key(self) -> tuple[str, ...]: ... + def natural_key(self) -> tuple[str]: ... user_set = ManyToManyRelatedManager["PermissionsMixin", "Group"]() class UserManager(BaseUserManager[_T]): From fe88ecb17d032706c54c53415887ed434183b05d Mon Sep 17 00:00:00 2001 From: Noelle Leigh <5957867+noelleleigh@users.noreply.github.com> Date: Fri, 31 May 2024 12:41:59 -0400 Subject: [PATCH 04/14] UserManager: Add use_in_migrations --- django-stubs/contrib/auth/models.pyi | 1 + 1 file changed, 1 insertion(+) diff --git a/django-stubs/contrib/auth/models.pyi b/django-stubs/contrib/auth/models.pyi index 35a23e155..b79ba50e9 100644 --- a/django-stubs/contrib/auth/models.pyi +++ b/django-stubs/contrib/auth/models.pyi @@ -50,6 +50,7 @@ class Group(models.Model): user_set = ManyToManyRelatedManager["PermissionsMixin", "Group"]() class UserManager(BaseUserManager[_T]): + use_in_migrations: bool = ... def create_user( self, username: str, From 7f9aa7911b2ab2e8d99c2158cff8f0b9eb3a4ae1 Mon Sep 17 00:00:00 2001 From: Noelle Leigh <5957867+noelleleigh@users.noreply.github.com> Date: Fri, 31 May 2024 12:42:51 -0400 Subject: [PATCH 05/14] UserManager.with_perm: Returns self.none() or another UserManager --- django-stubs/contrib/auth/models.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django-stubs/contrib/auth/models.pyi b/django-stubs/contrib/auth/models.pyi index b79ba50e9..82d5816d4 100644 --- a/django-stubs/contrib/auth/models.pyi +++ b/django-stubs/contrib/auth/models.pyi @@ -72,7 +72,7 @@ class UserManager(BaseUserManager[_T]): include_superusers: bool = ..., backend: type[ModelBackend] | str | None = ..., obj: Model | None = ..., - ) -> Any: ... + ) -> Self | UserManager[_T]: ... class PermissionsMixin(models.Model): is_superuser = models.BooleanField() From 5ab5f64d71f8e1f39b5227967b2a7a5928f8f370 Mon Sep 17 00:00:00 2001 From: Noelle Leigh <5957867+noelleleigh@users.noreply.github.com> Date: Fri, 31 May 2024 12:43:56 -0400 Subject: [PATCH 06/14] auth/models.py: has_perms only needs an Iterable Not a whole Collection --- django-stubs/contrib/auth/models.pyi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/django-stubs/contrib/auth/models.pyi b/django-stubs/contrib/auth/models.pyi index 82d5816d4..bb23a5a1e 100644 --- a/django-stubs/contrib/auth/models.pyi +++ b/django-stubs/contrib/auth/models.pyi @@ -1,4 +1,4 @@ -from collections.abc import Collection +from collections.abc import Iterable from typing import Any, ClassVar, TypeVar from typing_extensions import Literal, Self @@ -83,7 +83,7 @@ class PermissionsMixin(models.Model): def get_all_permissions(self, obj: _AnyUser | None = ...) -> set[str]: ... def has_perm(self, perm: str, obj: _AnyUser | None = ...) -> bool: ... def has_perms( - self, perm_list: Collection[str], obj: _AnyUser | None = ... + self, perm_list: Iterable[str], obj: _AnyUser | None = ... ) -> bool: ... def has_module_perms(self, app_label: str) -> bool: ... @@ -129,7 +129,7 @@ class AnonymousUser: def get_all_permissions(self, obj: _AnyUser | None = ...) -> set[str]: ... def has_perm(self, perm: str, obj: _AnyUser | None = ...) -> bool: ... def has_perms( - self, perm_list: Collection[str], obj: _AnyUser | None = ... + self, perm_list: Iterable[str], obj: _AnyUser | None = ... ) -> bool: ... def has_module_perms(self, module: str) -> bool: ... @property From 10260fb47ea95e15f227d7b6f65246a6f262d5bd Mon Sep 17 00:00:00 2001 From: Noelle Leigh <5957867+noelleleigh@users.noreply.github.com> Date: Fri, 31 May 2024 12:44:29 -0400 Subject: [PATCH 07/14] AbstractUser.first_name: fix max_length --- django-stubs/contrib/auth/models.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django-stubs/contrib/auth/models.pyi b/django-stubs/contrib/auth/models.pyi index bb23a5a1e..c1be3eff2 100644 --- a/django-stubs/contrib/auth/models.pyi +++ b/django-stubs/contrib/auth/models.pyi @@ -91,7 +91,7 @@ class AbstractUser(AbstractBaseUser, PermissionsMixin): username_validator: UnicodeUsernameValidator = ... username = models.CharField(max_length=150) - first_name = models.CharField(max_length=30, blank=True) + first_name = models.CharField(max_length=150, blank=True) last_name = models.CharField(max_length=150, blank=True) email = models.EmailField(blank=True) is_staff = models.BooleanField() From 733df04f17cc30a579c28d5d9e3eb5179d729df9 Mon Sep 17 00:00:00 2001 From: Noelle Leigh <5957867+noelleleigh@users.noreply.github.com> Date: Fri, 31 May 2024 12:45:22 -0400 Subject: [PATCH 08/14] AbstractUser.email_user: from_email is None by default --- django-stubs/contrib/auth/models.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django-stubs/contrib/auth/models.pyi b/django-stubs/contrib/auth/models.pyi index c1be3eff2..9fc845bea 100644 --- a/django-stubs/contrib/auth/models.pyi +++ b/django-stubs/contrib/auth/models.pyi @@ -103,7 +103,7 @@ class AbstractUser(AbstractBaseUser, PermissionsMixin): def get_full_name(self) -> str: ... def get_short_name(self) -> str: ... def email_user( - self, subject: str, message: str, from_email: str = ..., **kwargs: Any + self, subject: str, message: str, from_email: str | None = ..., **kwargs: Any ) -> None: ... class User(AbstractUser): From 5559da7be6ef93b94f3bab7158e4ee1e0058c13d Mon Sep 17 00:00:00 2001 From: Noelle Leigh <5957867+noelleleigh@users.noreply.github.com> Date: Fri, 31 May 2024 12:46:40 -0400 Subject: [PATCH 09/14] AbstractUser: Move objects from User This way AbstractUser has access to the special methods on UserManager --- django-stubs/contrib/auth/models.pyi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/django-stubs/contrib/auth/models.pyi b/django-stubs/contrib/auth/models.pyi index 9fc845bea..e159709fb 100644 --- a/django-stubs/contrib/auth/models.pyi +++ b/django-stubs/contrib/auth/models.pyi @@ -106,9 +106,10 @@ class AbstractUser(AbstractBaseUser, PermissionsMixin): self, subject: str, message: str, from_email: str | None = ..., **kwargs: Any ) -> None: ... -class User(AbstractUser): objects: ClassVar[UserManager[Self]] # type: ignore[assignment] +class User(AbstractUser): ... + class AnonymousUser: id: Any = ... pk: Any = ... From 91c85b503d949f776dc890fbfff615752ecb6d3f Mon Sep 17 00:00:00 2001 From: Noelle Leigh <5957867+noelleleigh@users.noreply.github.com> Date: Fri, 31 May 2024 12:47:25 -0400 Subject: [PATCH 10/14] AnonymousUser: More specific types, Never for some methods --- django-stubs/contrib/auth/models.pyi | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/django-stubs/contrib/auth/models.pyi b/django-stubs/contrib/auth/models.pyi index e159709fb..5d101ded2 100644 --- a/django-stubs/contrib/auth/models.pyi +++ b/django-stubs/contrib/auth/models.pyi @@ -1,6 +1,6 @@ from collections.abc import Iterable from typing import Any, ClassVar, TypeVar -from typing_extensions import Literal, Self +from typing_extensions import Literal, Never, Self from django.contrib.auth.backends import ModelBackend from django.contrib.auth.base_user import AbstractBaseUser as AbstractBaseUser @@ -111,22 +111,22 @@ class AbstractUser(AbstractBaseUser, PermissionsMixin): class User(AbstractUser): ... class AnonymousUser: - id: Any = ... - pk: Any = ... + id: None = ... + pk: None = ... username: str = ... is_staff: bool = ... is_active: bool = ... is_superuser: bool = ... - def save(self) -> Any: ... - def delete(self) -> Any: ... - def set_password(self, raw_password: str) -> Any: ... - def check_password(self, raw_password: str) -> Any: ... + def save(self) -> Never: ... + def delete(self) -> Never: ... + def set_password(self, raw_password: str) -> Never: ... + def check_password(self, raw_password: str) -> Never: ... @property def groups(self) -> EmptyManager[Group]: ... @property def user_permissions(self) -> EmptyManager[Permission]: ... def get_user_permissions(self, obj: _AnyUser | None = ...) -> set[str]: ... - def get_group_permissions(self, obj: _AnyUser | None = ...) -> set[Any]: ... + def get_group_permissions(self, obj: _AnyUser | None = ...) -> set[str]: ... def get_all_permissions(self, obj: _AnyUser | None = ...) -> set[str]: ... def has_perm(self, perm: str, obj: _AnyUser | None = ...) -> bool: ... def has_perms( From 5811352f4622b40b761e7249e37597fca000915f Mon Sep 17 00:00:00 2001 From: Noelle Leigh <5957867+noelleleigh@users.noreply.github.com> Date: Fri, 31 May 2024 12:51:12 -0400 Subject: [PATCH 11/14] auth/__init__.py: authenticate request can be None, returns AbstractUser --- django-stubs/contrib/auth/__init__.pyi | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/django-stubs/contrib/auth/__init__.pyi b/django-stubs/contrib/auth/__init__.pyi index 4590ade3a..3a5a81bc5 100644 --- a/django-stubs/contrib/auth/__init__.pyi +++ b/django-stubs/contrib/auth/__init__.pyi @@ -2,7 +2,7 @@ from typing import Any from django.contrib.auth.backends import ModelBackend from django.contrib.auth.base_user import AbstractBaseUser -from django.contrib.auth.models import AnonymousUser +from django.contrib.auth.models import AbstractUser, AnonymousUser from django.db.models.options import Options from django.http.request import HttpRequest from django.test.client import Client @@ -18,7 +18,9 @@ REDIRECT_FIELD_NAME: str def load_backend(path: str) -> ModelBackend: ... def get_backends() -> list[ModelBackend]: ... -def authenticate(request: HttpRequest = ..., **credentials: Any) -> AbstractBaseUser | None: ... +def authenticate( + request: HttpRequest | None = ..., **credentials: Any +) -> AbstractUser | None: ... def login( request: HttpRequest, user: AbstractBaseUser | None, From aba9cb20264010c923d44cc79dc85dbfc7cbcb67 Mon Sep 17 00:00:00 2001 From: Noelle Leigh <5957867+noelleleigh@users.noreply.github.com> Date: Fri, 31 May 2024 12:51:36 -0400 Subject: [PATCH 12/14] auth/__init__.py: aauthenticate Black format --- django-stubs/contrib/auth/__init__.pyi | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/django-stubs/contrib/auth/__init__.pyi b/django-stubs/contrib/auth/__init__.pyi index 3a5a81bc5..9032dfa61 100644 --- a/django-stubs/contrib/auth/__init__.pyi +++ b/django-stubs/contrib/auth/__init__.pyi @@ -27,7 +27,9 @@ def login( backend: type[ModelBackend] | str | None = ..., ) -> None: ... def logout(request: HttpRequest) -> None: ... -async def aauthenticate(request: HttpRequest = ..., **credentials: Any) -> AbstractBaseUser | None: ... +async def aauthenticate( + request: HttpRequest = ..., **credentials: Any +) -> AbstractBaseUser | None: ... async def alogin( request: HttpRequest, user: AbstractBaseUser | None, From 16d32e2cf9dacde8c08e4a9e58c88927012bf65f Mon Sep 17 00:00:00 2001 From: Noelle Leigh <5957867+noelleleigh@users.noreply.github.com> Date: Fri, 31 May 2024 12:52:22 -0400 Subject: [PATCH 13/14] auth/__init__.py: get_user_model should return more useful AbstractUser --- django-stubs/contrib/auth/__init__.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django-stubs/contrib/auth/__init__.pyi b/django-stubs/contrib/auth/__init__.pyi index 9032dfa61..c1836d0a0 100644 --- a/django-stubs/contrib/auth/__init__.pyi +++ b/django-stubs/contrib/auth/__init__.pyi @@ -35,7 +35,7 @@ async def alogin( user: AbstractBaseUser | None, backend: type[ModelBackend] | str | None = ..., ) -> None: ... -def get_user_model() -> type[AbstractBaseUser]: ... +def get_user_model() -> type[AbstractUser]: ... def get_user(request: HttpRequest | Client) -> AbstractBaseUser | AnonymousUser: ... def get_permission_codename(action: str, opts: Options[Any]) -> str: ... def update_session_auth_hash(request: HttpRequest, user: AbstractBaseUser) -> None: ... From af33bbe25929524376befbe5cfa7fb43baad9d9e Mon Sep 17 00:00:00 2001 From: Noelle Leigh <5957867+noelleleigh@users.noreply.github.com> Date: Fri, 31 May 2024 12:52:46 -0400 Subject: [PATCH 14/14] auth/__init__.py: get_user should return more useful AbstractUser --- django-stubs/contrib/auth/__init__.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django-stubs/contrib/auth/__init__.pyi b/django-stubs/contrib/auth/__init__.pyi index c1836d0a0..593d3c4dc 100644 --- a/django-stubs/contrib/auth/__init__.pyi +++ b/django-stubs/contrib/auth/__init__.pyi @@ -36,7 +36,7 @@ async def alogin( backend: type[ModelBackend] | str | None = ..., ) -> None: ... def get_user_model() -> type[AbstractUser]: ... -def get_user(request: HttpRequest | Client) -> AbstractBaseUser | AnonymousUser: ... +def get_user(request: HttpRequest | Client) -> AbstractUser | AnonymousUser: ... def get_permission_codename(action: str, opts: Options[Any]) -> str: ... def update_session_auth_hash(request: HttpRequest, user: AbstractBaseUser) -> None: ...