mirror of
https://github.com/davidhalter/django-stubs.git
synced 2025-12-06 12:14:28 +08:00
Issue 309 (#383)
* added tags for user models * type test for HttpRequest.user * test for User and AnonymousUser tags * httrequest test fix * checking python version fix for readibility * Rewrite version check for readability * Annotate is_authenticated/is_anonymous with Literal-type * Add auth in INSTALLED_APPS in test * Fix wrong type assertion in test * Fix misconception of how branch-testing works * Remove user from WSGIRequest * Change HttpRequest-transformer to set user-type to include AnonymousUser * Add check for anonymous_user_info=None to appease mypy * Isort transformers/request * Remove trailing whitespace * Remove unused import Co-authored-by: Kacper Szmigiel <szmigielkacper@gmai.com>
This commit is contained in:
committed by
GitHub
parent
25f92e8e56
commit
71751d3795
@@ -1,9 +1,15 @@
|
||||
import sys
|
||||
from typing import Any, Optional, Tuple, List, overload, TypeVar
|
||||
|
||||
from django.db.models.base import Model
|
||||
|
||||
from django.db import models
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
|
||||
_T = TypeVar("_T", bound=Model)
|
||||
|
||||
class BaseUserManager(models.Manager[_T]):
|
||||
@@ -20,9 +26,9 @@ class AbstractBaseUser(models.Model):
|
||||
def get_username(self) -> str: ...
|
||||
def natural_key(self) -> Tuple[str]: ...
|
||||
@property
|
||||
def is_anonymous(self) -> bool: ...
|
||||
def is_anonymous(self) -> Literal[False]: ...
|
||||
@property
|
||||
def is_authenticated(self) -> bool: ...
|
||||
def is_authenticated(self) -> Literal[True]: ...
|
||||
def set_password(self, raw_password: Optional[str]) -> None: ...
|
||||
def check_password(self, raw_password: str) -> bool: ...
|
||||
def set_unusable_password(self) -> None: ...
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import sys
|
||||
from typing import Any, Collection, Optional, Set, Tuple, Type, TypeVar, Union
|
||||
|
||||
from django.contrib.auth.backends import ModelBackend
|
||||
@@ -9,6 +10,11 @@ from django.db.models.manager import EmptyManager
|
||||
|
||||
from django.db import models
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
|
||||
_AnyUser = Union[Model, "AnonymousUser"]
|
||||
|
||||
def update_last_login(sender: Type[AbstractBaseUser], user: AbstractBaseUser, **kwargs: Any) -> None: ...
|
||||
@@ -105,7 +111,7 @@ class AnonymousUser:
|
||||
def has_perms(self, perm_list: Collection[str], obj: Optional[_AnyUser] = ...) -> bool: ...
|
||||
def has_module_perms(self, module: str) -> bool: ...
|
||||
@property
|
||||
def is_anonymous(self) -> bool: ...
|
||||
def is_anonymous(self) -> Literal[True]: ...
|
||||
@property
|
||||
def is_authenticated(self) -> bool: ...
|
||||
def is_authenticated(self) -> Literal[False]: ...
|
||||
def get_username(self) -> str: ...
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
from io import BytesIO
|
||||
from typing import Any, Callable, Dict, Optional, Union
|
||||
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.contrib.sessions.backends.base import SessionBase
|
||||
from django.http.response import HttpResponse
|
||||
|
||||
from django.core.handlers import base
|
||||
from django.http import HttpRequest
|
||||
from django.http.response import HttpResponse
|
||||
|
||||
_Stream = Union[BytesIO, str]
|
||||
_WSGIEnviron = Dict[str, Any]
|
||||
@@ -22,7 +20,6 @@ class LimitedStream:
|
||||
|
||||
class WSGIRequest(HttpRequest):
|
||||
environ: _WSGIEnviron = ...
|
||||
user: AbstractUser
|
||||
session: SessionBase
|
||||
encoding: Any = ...
|
||||
def __init__(self, environ: _WSGIEnviron) -> None: ...
|
||||
|
||||
@@ -17,6 +17,7 @@ from typing import (
|
||||
)
|
||||
|
||||
from django.contrib.auth.base_user import AbstractBaseUser
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
from django.contrib.sessions.backends.base import SessionBase
|
||||
from django.contrib.sites.models import Site
|
||||
from django.utils.datastructures import CaseInsensitiveMapping, ImmutableList, MultiValueDict
|
||||
@@ -51,7 +52,7 @@ class HttpRequest(BytesIO):
|
||||
resolver_match: ResolverMatch = ...
|
||||
content_type: Optional[str] = ...
|
||||
content_params: Optional[Dict[str, str]] = ...
|
||||
user: AbstractBaseUser
|
||||
user: Union[AbstractBaseUser, AnonymousUser]
|
||||
site: Site
|
||||
session: SessionBase
|
||||
encoding: Optional[str] = ...
|
||||
|
||||
@@ -10,3 +10,5 @@ select = F401, Y
|
||||
max_line_length = 120
|
||||
per-file-ignores =
|
||||
*__init__.pyi: F401
|
||||
base_user.pyi: Y003
|
||||
models.pyi: Y003
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from mypy.plugin import AttributeContext
|
||||
from mypy.types import Instance
|
||||
from mypy.types import Type as MypyType
|
||||
from mypy.types import UnionType
|
||||
|
||||
from mypy_django_plugin.django.context import DjangoContext
|
||||
from mypy_django_plugin.lib import helpers
|
||||
@@ -8,9 +9,18 @@ from mypy_django_plugin.lib import helpers
|
||||
|
||||
def set_auth_user_model_as_type_for_request_user(ctx: AttributeContext, django_context: DjangoContext) -> MypyType:
|
||||
auth_user_model = django_context.settings.AUTH_USER_MODEL
|
||||
model_cls = django_context.apps_registry.get_model(auth_user_model)
|
||||
model_info = helpers.lookup_class_typeinfo(helpers.get_typechecker_api(ctx), model_cls)
|
||||
if model_info is None:
|
||||
user_cls = django_context.apps_registry.get_model(auth_user_model)
|
||||
user_info = helpers.lookup_class_typeinfo(helpers.get_typechecker_api(ctx), user_cls)
|
||||
|
||||
if user_info is None:
|
||||
return ctx.default_attr_type
|
||||
|
||||
return Instance(model_info, [])
|
||||
# Imported here because django isn't properly loaded yet when module is loaded
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
|
||||
anonymous_user_info = helpers.lookup_class_typeinfo(helpers.get_typechecker_api(ctx), AnonymousUser)
|
||||
if anonymous_user_info is None:
|
||||
# This shouldn't be able to happen, as we managed to import the model above...
|
||||
return Instance(user_info, [])
|
||||
|
||||
return UnionType([Instance(user_info, []), Instance(anonymous_user_info, [])])
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
reveal_type(User().is_active) # N: Revealed type is 'builtins.bool*'
|
||||
reveal_type(User().date_joined) # N: Revealed type is 'datetime.datetime*'
|
||||
reveal_type(User().last_login) # N: Revealed type is 'Union[datetime.datetime, None]'
|
||||
reveal_type(User().is_authenticated) # N: Revealed type is 'Literal[True]'
|
||||
reveal_type(User().is_anonymous) # N: Revealed type is 'Literal[False]'
|
||||
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
reveal_type(AnonymousUser().is_authenticated) # N: Revealed type is 'Literal[False]'
|
||||
reveal_type(AnonymousUser().is_anonymous) # N: Revealed type is 'Literal[True]'
|
||||
|
||||
from django.contrib.auth.models import Permission
|
||||
reveal_type(Permission().name) # N: Revealed type is 'builtins.str*'
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
disable_cache: true
|
||||
main: |
|
||||
from django.http.request import HttpRequest
|
||||
reveal_type(HttpRequest().user) # N: Revealed type is 'myapp.models.MyUser'
|
||||
reveal_type(HttpRequest().user) # N: Revealed type is 'Union[myapp.models.MyUser, django.contrib.auth.models.AnonymousUser]'
|
||||
# check that other fields work ok
|
||||
reveal_type(HttpRequest().method) # N: Revealed type is 'Union[builtins.str, None]'
|
||||
custom_settings: |
|
||||
INSTALLED_APPS = ('django.contrib.contenttypes', 'myapp')
|
||||
INSTALLED_APPS = ('django.contrib.contenttypes', 'django.contrib.auth', 'myapp')
|
||||
AUTH_USER_MODEL='myapp.MyUser'
|
||||
files:
|
||||
- path: myapp/__init__.py
|
||||
@@ -14,4 +14,16 @@
|
||||
content: |
|
||||
from django.db import models
|
||||
class MyUser(models.Model):
|
||||
pass
|
||||
pass
|
||||
- case: request_object_user_can_be_descriminated
|
||||
disable_cache: true
|
||||
main: |
|
||||
from django.http.request import HttpRequest
|
||||
request = HttpRequest()
|
||||
reveal_type(request.user) # N: Revealed type is 'Union[django.contrib.auth.models.User, django.contrib.auth.models.AnonymousUser]'
|
||||
if not request.user.is_anonymous:
|
||||
reveal_type(request.user) # N: Revealed type is 'django.contrib.auth.models.User'
|
||||
if request.user.is_authenticated:
|
||||
reveal_type(request.user) # N: Revealed type is 'django.contrib.auth.models.User'
|
||||
custom_settings: |
|
||||
INSTALLED_APPS = ('django.contrib.contenttypes', 'django.contrib.auth')
|
||||
|
||||
Reference in New Issue
Block a user