Improve stubs with minor fixes (#1038)

* Add a missing attribute to Jinja2.

https://github.com/django/django/blob/main/django/template/backends/jinja2.py#L35

Signed-off-by: Zixuan James Li <p359101898@gmail.com>

* Make _QuerySet.extra's signature more generic.

This makes sure that we don't reject tuples, which is also valid
according to the implementation.

Relevant source code:
03eec9ff6c/django/db/models/sql/where.py (L271-L281)
03eec9ff6c/django/db/models/sql/query.py (L2307-L2308)

Signed-off-by: Zixuan James Li <p359101898@gmail.com>

* Fix user_passes_test to use AUTH_USER_MODEL.

According to the documentation, `test_func` is a callable that takes a
`User` (possibly anonymous).

Relevant documentation:
https://docs.djangoproject.com/en/4.0/topics/auth/default/#django.contrib.auth.decorators.user_passes_test

Signed-off-by: Zixuan James Li <p359101898@gmail.com>

* Add more accurate type annotations for dirs.

Though not documented, it's possible for `dirs` to contain
`pathlib.Path`.

`django.template.loaders.app_directories.Loader` is an example for this:
03eec9ff6c/django/template/loaders/app_directories.py
03eec9ff6c/django/template/utils.py (L97-L111)

Signed-off-by: Zixuan James Li <p359101898@gmail.com>

* serve should return FileResponse.

There are several serve functions that should return a `FileResponse`.

Source code:
863aa7541d/django/views/static.py (L17-L53)
863aa7541d/django/contrib/staticfiles/views.py (L15-L39)
863aa7541d/django/contrib/staticfiles/handlers.py (L48-L50)
863aa7541d/django/test/testcases.py (L1680-L1687)

Signed-off-by: Zixuan James Li <p359101898@gmail.com>
This commit is contained in:
PIG208
2022-07-04 16:46:53 -04:00
committed by GitHub
parent ae30525404
commit 516deba2fa
10 changed files with 26 additions and 22 deletions

View File

@@ -1,13 +1,15 @@
from typing import Callable, Iterable, Optional, TypeVar, Union, overload from typing import Callable, Iterable, Optional, TypeVar, Union, overload
from django.contrib.auth import REDIRECT_FIELD_NAME as REDIRECT_FIELD_NAME # noqa: F401 from django.contrib.auth import REDIRECT_FIELD_NAME as REDIRECT_FIELD_NAME # noqa: F401
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractBaseUser, AnonymousUser
from django.http.response import HttpResponseBase from django.http.response import HttpResponseBase
_VIEW = TypeVar("_VIEW", bound=Callable[..., HttpResponseBase]) _VIEW = TypeVar("_VIEW", bound=Callable[..., HttpResponseBase])
def user_passes_test( def user_passes_test(
test_func: Callable[[AbstractUser], bool], login_url: Optional[str] = ..., redirect_field_name: str = ... test_func: Callable[[Union[AbstractBaseUser, AnonymousUser]], bool],
login_url: Optional[str] = ...,
redirect_field_name: str = ...,
) -> Callable[[_VIEW], _VIEW]: ... ) -> Callable[[_VIEW], _VIEW]: ...
# There are two ways of calling @login_required: @with(arguments) and @bare # There are two ways of calling @login_required: @with(arguments) and @bare

View File

@@ -1,11 +1,11 @@
from typing import Any, Awaitable, Callable, Dict, Mapping, Sequence, Tuple from typing import Any, Awaitable, Callable, Dict, Mapping, Sequence, Tuple
from urllib.parse import ParseResult from urllib.parse import ParseResult
from django.core.handlers.asgi import ASGIHandler, ASGIRequest from django.core.handlers.asgi import ASGIHandler
from django.core.handlers.base import BaseHandler from django.core.handlers.base import BaseHandler
from django.core.handlers.wsgi import WSGIHandler, WSGIRequest from django.core.handlers.wsgi import WSGIHandler
from django.http import HttpRequest from django.http import HttpRequest
from django.http.response import HttpResponseBase from django.http.response import FileResponse, HttpResponseBase
class StaticFilesHandlerMixin: class StaticFilesHandlerMixin:
handles_files: bool = ... handles_files: bool = ...
@@ -15,7 +15,7 @@ class StaticFilesHandlerMixin:
def get_base_url(self) -> str: ... def get_base_url(self) -> str: ...
def _should_handle(self, path: str) -> bool: ... def _should_handle(self, path: str) -> bool: ...
def file_path(self, url: str) -> str: ... def file_path(self, url: str) -> str: ...
def serve(self, request: HttpRequest) -> HttpResponseBase: ... def serve(self, request: HttpRequest) -> FileResponse: ...
def get_response(self, request: HttpRequest) -> HttpResponseBase: ... def get_response(self, request: HttpRequest) -> HttpResponseBase: ...
async def get_response_async(self, request: HttpRequest) -> HttpResponseBase: ... async def get_response_async(self, request: HttpRequest) -> HttpResponseBase: ...

View File

@@ -1,6 +1,6 @@
from typing import Any from typing import Any
from django.http.request import HttpRequest from django.http.request import HttpRequest
from django.http.response import HttpResponseBase from django.http.response import FileResponse
def serve(request: HttpRequest, path: str, insecure: bool = ..., **kwargs: Any) -> HttpResponseBase: ... def serve(request: HttpRequest, path: str, insecure: bool = ..., **kwargs: Any) -> FileResponse: ...

View File

@@ -115,9 +115,9 @@ class _QuerySet(Generic[_T, _Row], Collection[_Row], Reversible[_Row], Sized):
def extra( def extra(
self, self,
select: Optional[Dict[str, Any]] = ..., select: Optional[Dict[str, Any]] = ...,
where: Optional[List[str]] = ..., where: Optional[Sequence[str]] = ...,
params: Optional[List[Any]] = ..., params: Optional[Sequence[Any]] = ...,
tables: Optional[List[str]] = ..., tables: Optional[Sequence[str]] = ...,
order_by: Optional[Sequence[str]] = ..., order_by: Optional[Sequence[str]] = ...,
select_params: Optional[Sequence[Any]] = ..., select_params: Optional[Sequence[Any]] = ...,
) -> _QuerySet[Any, Any]: ... ) -> _QuerySet[Any, Any]: ...

View File

@@ -5,6 +5,7 @@ from django.template.exceptions import TemplateSyntaxError
from .base import BaseEngine from .base import BaseEngine
class Jinja2(BaseEngine): class Jinja2(BaseEngine):
env: Any = ...
context_processors: List[str] = ... context_processors: List[str] = ...
def __init__(self, params: Dict[str, Any]) -> None: ... def __init__(self, params: Dict[str, Any]) -> None: ...
@property @property

View File

@@ -1,4 +1,5 @@
from typing import Iterator, List, Optional from pathlib import Path
from typing import Iterator, List, Optional, Union
from django.template.base import Origin from django.template.base import Origin
from django.template.engine import Engine from django.template.engine import Engine
@@ -6,8 +7,8 @@ from django.template.engine import Engine
from .base import Loader as BaseLoader from .base import Loader as BaseLoader
class Loader(BaseLoader): class Loader(BaseLoader):
dirs: Optional[List[str]] = ... dirs: Optional[List[Union[str, Path]]] = ...
def __init__(self, engine: Engine, dirs: Optional[List[str]] = ...) -> None: ... def __init__(self, engine: Engine, dirs: Optional[List[Union[str, Path]]] = ...) -> None: ...
def get_dirs(self) -> List[str]: ... def get_dirs(self) -> List[Union[str, Path]]: ...
def get_contents(self, origin: Origin) -> str: ... def get_contents(self, origin: Origin) -> str: ...
def get_template_sources(self, template_name: str) -> Iterator[Origin]: ... def get_template_sources(self, template_name: str) -> Iterator[Origin]: ...

View File

@@ -26,7 +26,7 @@ from django.db.backends.base.base import BaseDatabaseWrapper
from django.db.models.base import Model from django.db.models.base import Model
from django.db.models.query import QuerySet, RawQuerySet from django.db.models.query import QuerySet, RawQuerySet
from django.forms.fields import EmailField from django.forms.fields import EmailField
from django.http.response import HttpResponse, HttpResponseBase from django.http.response import FileResponse, HttpResponseBase
from django.template.base import Template from django.template.base import Template
from django.test.client import AsyncClient, Client from django.test.client import AsyncClient, Client
from django.test.html import Element from django.test.html import Element
@@ -202,7 +202,7 @@ class FSFilesHandler(WSGIHandler):
base_url: Any = ... base_url: Any = ...
def __init__(self, application: Any) -> None: ... def __init__(self, application: Any) -> None: ...
def file_path(self, url: Any): ... def file_path(self, url: Any): ...
def serve(self, request: Any): ... def serve(self, request: Any) -> FileResponse: ...
class _StaticFilesHandler(FSFilesHandler): class _StaticFilesHandler(FSFilesHandler):
def get_base_dir(self): ... def get_base_dir(self): ...

View File

@@ -1,11 +1,11 @@
from typing import Any, Optional from typing import Any, Optional
from django.http import FileResponse
from django.http.request import HttpRequest from django.http.request import HttpRequest
from django.http.response import HttpResponseBase
def serve( def serve(
request: HttpRequest, path: str, document_root: Optional[str] = ..., show_indexes: bool = ... request: HttpRequest, path: str, document_root: Optional[str] = ..., show_indexes: bool = ...
) -> HttpResponseBase: ... ) -> FileResponse: ...
DEFAULT_DIRECTORY_INDEX_TEMPLATE: str DEFAULT_DIRECTORY_INDEX_TEMPLATE: str
template_translatable: Any template_translatable: Any

View File

@@ -27,14 +27,14 @@
- case: user_passes_test - case: user_passes_test
main: | main: |
from django.contrib.auth.decorators import user_passes_test from django.contrib.auth.decorators import user_passes_test
@user_passes_test(lambda u: u.username.startswith('super')) @user_passes_test(lambda u: u.get_username().startswith('super'))
def view_func(request): ... def view_func(request): ...
reveal_type(view_func) # N: Revealed type is "def (request: Any) -> Any" reveal_type(view_func) # N: Revealed type is "def (request: Any) -> Any"
- case: user_passes_test_bare_is_error - case: user_passes_test_bare_is_error
main: | main: |
from django.http.response import HttpResponse from django.http.response import HttpResponse
from django.contrib.auth.decorators import user_passes_test from django.contrib.auth.decorators import user_passes_test
@user_passes_test # E: Argument 1 to "user_passes_test" has incompatible type "Callable[[Any], HttpResponse]"; expected "Callable[[AbstractUser], bool]" @user_passes_test # E: Argument 1 to "user_passes_test" has incompatible type "Callable[[Any], HttpResponse]"; expected "Callable[[Union[AbstractBaseUser, AnonymousUser]], bool]"
def view_func(request) -> HttpResponse: ... def view_func(request) -> HttpResponse: ...
- case: permission_required - case: permission_required
main: | main: |

View File

@@ -407,7 +407,7 @@
reveal_type(MyModel.objects.difference) # N: Revealed type is "def (*other_qs: Any) -> myapp.models.MyQuerySet[myapp.models.MyModel]" reveal_type(MyModel.objects.difference) # N: Revealed type is "def (*other_qs: Any) -> myapp.models.MyQuerySet[myapp.models.MyModel]"
reveal_type(MyModel.objects.distinct) # N: Revealed type is "def (*field_names: Any) -> myapp.models.MyQuerySet[myapp.models.MyModel]" reveal_type(MyModel.objects.distinct) # N: Revealed type is "def (*field_names: Any) -> myapp.models.MyQuerySet[myapp.models.MyModel]"
reveal_type(MyModel.objects.exclude) # N: Revealed type is "def (*args: Any, **kwargs: Any) -> myapp.models.MyQuerySet[myapp.models.MyModel]" reveal_type(MyModel.objects.exclude) # N: Revealed type is "def (*args: Any, **kwargs: Any) -> myapp.models.MyQuerySet[myapp.models.MyModel]"
reveal_type(MyModel.objects.extra) # N: Revealed type is "def (select: Union[builtins.dict[builtins.str, Any], None] =, where: Union[builtins.list[builtins.str], None] =, params: Union[builtins.list[Any], None] =, tables: Union[builtins.list[builtins.str], None] =, order_by: Union[typing.Sequence[builtins.str], None] =, select_params: Union[typing.Sequence[Any], None] =) -> myapp.models.MyQuerySet[myapp.models.MyModel]" reveal_type(MyModel.objects.extra) # N: Revealed type is "def (select: Union[builtins.dict[builtins.str, Any], None] =, where: Union[typing.Sequence[builtins.str], None] =, params: Union[typing.Sequence[Any], None] =, tables: Union[typing.Sequence[builtins.str], None] =, order_by: Union[typing.Sequence[builtins.str], None] =, select_params: Union[typing.Sequence[Any], None] =) -> myapp.models.MyQuerySet[myapp.models.MyModel]"
reveal_type(MyModel.objects.filter) # N: Revealed type is "def (*args: Any, **kwargs: Any) -> myapp.models.MyQuerySet[myapp.models.MyModel]" reveal_type(MyModel.objects.filter) # N: Revealed type is "def (*args: Any, **kwargs: Any) -> myapp.models.MyQuerySet[myapp.models.MyModel]"
reveal_type(MyModel.objects.intersection) # N: Revealed type is "def (*other_qs: Any) -> myapp.models.MyQuerySet[myapp.models.MyModel]" reveal_type(MyModel.objects.intersection) # N: Revealed type is "def (*other_qs: Any) -> myapp.models.MyQuerySet[myapp.models.MyModel]"
reveal_type(MyModel.objects.none) # N: Revealed type is "def () -> myapp.models.MyQuerySet[myapp.models.MyModel]" reveal_type(MyModel.objects.none) # N: Revealed type is "def () -> myapp.models.MyQuerySet[myapp.models.MyModel]"