From 1efa5dace20ddaa399bdcedcf4565365bca4a0af Mon Sep 17 00:00:00 2001 From: Oleg Hoefling Date: Sat, 12 Nov 2022 17:39:47 +0100 Subject: [PATCH] address review comments, extract follow flag checks in a separate test case Signed-off-by: Oleg Hoefling --- django-stubs/test/client.pyi | 35 ++++++++++--- tests/typecheck/test/test_client.yml | 76 ++++++++++++++++++++++++++-- 2 files changed, 102 insertions(+), 9 deletions(-) diff --git a/django-stubs/test/client.pyi b/django-stubs/test/client.pyi index 59c86dabd..b6bd8a577 100644 --- a/django-stubs/test/client.pyi +++ b/django-stubs/test/client.pyi @@ -1,4 +1,3 @@ -import sys from io import BytesIO from json import JSONEncoder from types import TracebackType @@ -32,11 +31,7 @@ from django.http.response import HttpResponseBase from django.template.base import Template from django.test.utils import ContextList from django.urls import ResolverMatch - -if sys.version_info >= (3, 8): - from typing import Literal -else: - from typing_extensions import Literal +from typing_extensions import Literal BOUNDARY: str = ... MULTIPART_CONTENT: str = ... @@ -176,6 +171,10 @@ class Client(ClientMixin, _RequestFactory[_MonkeyPatchedWSGIResponse]): def get( self, path: str, data: Any = ..., follow: Literal[True] = ..., secure: bool = ..., **extra: Any ) -> _MonkeyPatchedWSGIResponseRedirect: ... + @overload + def get( + self, path: str, data: Any = ..., follow: bool = ..., secure: bool = ..., **extra: Any + ) -> _MonkeyPatchedWSGIResponse: ... @overload # type: ignore def post( self, @@ -196,6 +195,10 @@ class Client(ClientMixin, _RequestFactory[_MonkeyPatchedWSGIResponse]): secure: bool = ..., **extra: Any ) -> _MonkeyPatchedWSGIResponseRedirect: ... + @overload + def post( + self, path: str, data: Any = ..., content_type: str = ..., follow: bool = ..., secure: bool = ..., **extra: Any + ) -> _MonkeyPatchedWSGIResponse: ... @overload # type: ignore def head( self, path: str, data: Any = ..., follow: Literal[False] = ..., secure: bool = ..., **extra: Any @@ -204,6 +207,10 @@ class Client(ClientMixin, _RequestFactory[_MonkeyPatchedWSGIResponse]): def head( self, path: str, data: Any = ..., follow: Literal[True] = ..., secure: bool = ..., **extra: Any ) -> _MonkeyPatchedWSGIResponseRedirect: ... + @overload + def head( + self, path: str, data: Any = ..., follow: bool = ..., secure: bool = ..., **extra: Any + ) -> _MonkeyPatchedWSGIResponse: ... @overload # type: ignore def trace( self, path: str, data: Any = ..., follow: Literal[False] = ..., secure: bool = ..., **extra: Any @@ -212,6 +219,10 @@ class Client(ClientMixin, _RequestFactory[_MonkeyPatchedWSGIResponse]): def trace( self, path: str, data: Any = ..., follow: Literal[True] = ..., secure: bool = ..., **extra: Any ) -> _MonkeyPatchedWSGIResponseRedirect: ... + @overload + def trace( + self, path: str, data: Any = ..., follow: bool = ..., secure: bool = ..., **extra: Any + ) -> _MonkeyPatchedWSGIResponse: ... @overload # type: ignore def put( self, @@ -232,6 +243,10 @@ class Client(ClientMixin, _RequestFactory[_MonkeyPatchedWSGIResponse]): secure: bool = ..., **extra: Any ) -> _MonkeyPatchedWSGIResponseRedirect: ... + @overload + def put( + self, path: str, data: Any = ..., content_type: str = ..., follow: bool = ..., secure: bool = ..., **extra: Any + ) -> _MonkeyPatchedWSGIResponse: ... @overload # type: ignore def patch( self, @@ -252,6 +267,10 @@ class Client(ClientMixin, _RequestFactory[_MonkeyPatchedWSGIResponse]): secure: bool = ..., **extra: Any ) -> _MonkeyPatchedWSGIResponseRedirect: ... + @overload + def patch( + self, path: str, data: Any = ..., content_type: str = ..., follow: bool = ..., secure: bool = ..., **extra: Any + ) -> _MonkeyPatchedWSGIResponse: ... @overload # type: ignore def delete( self, @@ -272,6 +291,10 @@ class Client(ClientMixin, _RequestFactory[_MonkeyPatchedWSGIResponse]): secure: bool = ..., **extra: Any ) -> _MonkeyPatchedWSGIResponseRedirect: ... + @overload + def delete( + self, path: str, data: Any = ..., content_type: str = ..., follow: bool = ..., secure: bool = ..., **extra: Any + ) -> _MonkeyPatchedWSGIResponse: ... class AsyncClient(ClientMixin, _AsyncRequestFactory[Awaitable[_MonkeyPatchedASGIResponse]]): handler: AsyncClientHandler diff --git a/tests/typecheck/test/test_client.yml b/tests/typecheck/test/test_client.yml index 37178cbf7..93cfb8881 100644 --- a/tests/typecheck/test/test_client.yml +++ b/tests/typecheck/test/test_client.yml @@ -9,10 +9,7 @@ reveal_type(response.client) # N: Revealed type is "django.test.client.Client" reveal_type(response.context) # N: Revealed type is "Union[django.test.utils.ContextList, builtins.dict[builtins.str, Any]]" reveal_type(response.content) # N: Revealed type is "builtins.bytes" - response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain" response.json() - redirected_response = client.get('foo', follow=True) - reveal_type(redirected_response.redirect_chain) # N: Revealed type is "builtins.list[Tuple[builtins.str, builtins.int]]" - case: async_client_methods main: | from django.test.client import AsyncClient @@ -37,3 +34,76 @@ async_factory = AsyncRequestFactory() async_request = async_factory.get('foo') reveal_type(async_request) # N: Revealed type is "django.core.handlers.asgi.ASGIRequest" +- case: client_follow_flag + main: | + from django.test.client import Client + client = Client() + response = client.get('foo') + response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain" + response = client.get('foo', follow=False) + response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain" + response = client.get('foo', follow=True) + reveal_type(response.redirect_chain) # N: Revealed type is "builtins.list[Tuple[builtins.str, builtins.int]]" + x: bool + response = client.get('foo', follow=x) + response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain" + + response = client.post('foo') + response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain" + response = client.post('foo', follow=False) + response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain" + response = client.post('foo', follow=True) + reveal_type(response.redirect_chain) # N: Revealed type is "builtins.list[Tuple[builtins.str, builtins.int]]" + x: bool + response = client.post('foo', follow=x) + response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain" + + response = client.head('foo') + response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain" + response = client.head('foo', follow=False) + response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain" + response = client.head('foo', follow=True) + reveal_type(response.redirect_chain) # N: Revealed type is "builtins.list[Tuple[builtins.str, builtins.int]]" + x: bool + response = client.head('foo', follow=x) + response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain" + + response = client.trace('foo') + response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain" + response = client.trace('foo', follow=False) + response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain" + response = client.trace('foo', follow=True) + reveal_type(response.redirect_chain) # N: Revealed type is "builtins.list[Tuple[builtins.str, builtins.int]]" + x: bool + response = client.trace('foo', follow=x) + response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain" + + response = client.put('foo') + response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain" + response = client.put('foo', follow=False) + response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain" + response = client.put('foo', follow=True) + reveal_type(response.redirect_chain) # N: Revealed type is "builtins.list[Tuple[builtins.str, builtins.int]]" + x: bool + response = client.put('foo', follow=x) + response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain" + + response = client.patch('foo') + response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain" + response = client.patch('foo', follow=False) + response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain" + response = client.patch('foo', follow=True) + reveal_type(response.redirect_chain) # N: Revealed type is "builtins.list[Tuple[builtins.str, builtins.int]]" + x: bool + response = client.patch('foo', follow=x) + response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain" + + response = client.delete('foo') + response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain" + response = client.delete('foo', follow=False) + response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain" + response = client.delete('foo', follow=True) + reveal_type(response.redirect_chain) # N: Revealed type is "builtins.list[Tuple[builtins.str, builtins.int]]" + x: bool + response = client.delete('foo', follow=x) + response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain"