From a2f30a01875e851d2dd17a5f949032d7a7fd0621 Mon Sep 17 00:00:00 2001 From: Xavier Francisco <98830734+XF-FW@users.noreply.github.com> Date: Sun, 29 May 2022 08:12:47 +0000 Subject: [PATCH 01/42] Fix "HttpResponse" has no attribute "data" on TestCases (#205) * Update test.pyi * Add test * Update tests Co-authored-by: Xavier Francisco --- rest_framework-stubs/test.pyi | 4 ++++ tests/typecheck/test_test.yml | 28 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 tests/typecheck/test_test.yml diff --git a/rest_framework-stubs/test.pyi b/rest_framework-stubs/test.pyi index 00f5a6617..0b862369e 100644 --- a/rest_framework-stubs/test.pyi +++ b/rest_framework-stubs/test.pyi @@ -81,14 +81,18 @@ class APIClient(APIRequestFactory, DjangoClient): class APITransactionTestCase(testcases.TransactionTestCase): client_class: Type[APIClient] = ... + client: APIClient class APITestCase(testcases.TestCase): client_class: Type[APIClient] = ... + client: APIClient class APISimpleTestCase(testcases.SimpleTestCase): client_class: Type[APIClient] = ... + client: APIClient class APILiveServerTestCase(testcases.LiveServerTestCase): client_class: Type[APIClient] = ... + client: APIClient class URLPatternsTestCase(testcases.SimpleTestCase): ... diff --git a/tests/typecheck/test_test.yml b/tests/typecheck/test_test.yml new file mode 100644 index 000000000..69940d325 --- /dev/null +++ b/tests/typecheck/test_test.yml @@ -0,0 +1,28 @@ +- case: test_testcases_client_api + parametrized: + - test_class: APITransactionTestCase + - test_class: APITestCase + - test_class: APISimpleTestCase + - test_class: APILiveServerTestCase + main: | + from rest_framework import test, status + + class MyTest(test.{{ test_class }}): + def test_example(self) -> None: + reveal_type(self.client) # N: Revealed type is "rest_framework.test.APIClient" + response = self.client.get('/', format="json") + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + self.assertEqual(response.data, {"detail": {"not_found"}}) + +- case: test_testcases_client_api_urlpatterns + main: | + from typing import Union, List + from django.urls import URLPattern, URLResolver + from rest_framework import test, status + + class MyTest(test.URLPatternsTestCase): + urlpatterns : List[Union[URLPattern, URLResolver]] = [] + def test_example(self) -> None: + reveal_type(self.client) # N: Revealed type is "django.test.client.Client" + response = self.client.get('/', format="json") + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) From 44f8de323e4065fb0d832f50111c6465e0a0dad8 Mon Sep 17 00:00:00 2001 From: Timur Safin Date: Fri, 3 Jun 2022 10:33:59 +0400 Subject: [PATCH 02/42] Fix return types for ModelSerializer methods build_* (#227) --- .gitignore | 1 + rest_framework-stubs/serializers.pyi | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index b8b771679..36a05a7b2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *.egg-info .DS_Store +.python-version .idea/ .mypy_cache/ .pytest_cache/ diff --git a/rest_framework-stubs/serializers.pyi b/rest_framework-stubs/serializers.pyi index 6e4040935..838d656e1 100644 --- a/rest_framework-stubs/serializers.pyi +++ b/rest_framework-stubs/serializers.pyi @@ -257,18 +257,18 @@ class ModelSerializer(Serializer, BaseSerializer[_MT]): def get_default_field_names(self, declared_fields: Mapping[str, Field], model_info: FieldInfo) -> List[str]: ... def build_field( self, field_name: str, info: FieldInfo, model_class: _MT, nested_depth: int - ) -> Tuple[Field, Dict[str, Any]]: ... + ) -> Tuple[Type[Field], Dict[str, Any]]: ... def build_standard_field( self, field_name: str, model_field: Type[models.Field] - ) -> Tuple[Field, Dict[str, Any]]: ... + ) -> Tuple[Type[Field], Dict[str, Any]]: ... def build_relational_field( self, field_name: str, relation_info: RelationInfo ) -> Tuple[Type[Field], Dict[str, Any]]: ... def build_nested_field( self, field_name: str, relation_info: RelationInfo, nested_depth: int - ) -> Tuple[Field, Dict[str, Any]]: ... - def build_property_field(self, field_name: str, model_class: _MT) -> Tuple[Field, Dict[str, Any]]: ... - def build_url_field(self, field_name: str, model_class: _MT) -> Tuple[Field, Dict[str, Any]]: ... + ) -> Tuple[Type[Field], Dict[str, Any]]: ... + def build_property_field(self, field_name: str, model_class: _MT) -> Tuple[Type[Field], Dict[str, Any]]: ... + def build_url_field(self, field_name: str, model_class: _MT) -> Tuple[Type[Field], Dict[str, Any]]: ... def build_unknown_field(self, field_name: str, model_class: _MT) -> NoReturn: ... def include_extra_kwargs( self, kwargs: MutableMapping[str, Any], extra_kwargs: MutableMapping[str, Any] From 2c884820e99915ae6bdc7519588de4fd42477a4f Mon Sep 17 00:00:00 2001 From: Terence Honles Date: Wed, 8 Jun 2022 00:04:32 -0700 Subject: [PATCH 03/42] Add GitHub release action to upload to PyPI & create GitHub release (#228) --- .github/workflows/release.yml | 72 +++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..1dac81986 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,72 @@ +name: Release + +on: + push: + tags: + - '*' + +jobs: + build: + if: github.repository == 'typeddjango/djangorestframework-stubs' + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-python@v3 + with: + python-version: '3.9' + + - name: Install dependencies + run: | + python -m pip install -U pip + python -m pip install -U setuptools twine wheel + + - name: Build package + run: | + python setup.py --version + python setup.py sdist bdist_wheel + + - name: Publish package to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + user: __token__ + password: ${{ secrets.PYPI_API_TOKEN }} + + print_hash: true + + - name: Create release + uses: actions/github-script@v6 + with: + script: | + const tagName = context.ref.replace(/^refs\/tags\//, ''); + const release = await github.rest.repos.createRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + tag_name: tagName, + name: `Release ${tagName.replace(/^v/, '')}`, + }); + + if (release.status < 200 || release.status >= 300) { + core.setFailed(`Could not create release for tag '${tagName}'`); + return; + } + + # https://github.community/t/run-github-actions-job-only-if-previous-job-has-failed/174786/2 + create-issue-on-failure: + name: Create an issue if release failed + runs-on: ubuntu-latest + needs: [build] + if: ${{ github.repository == 'typeddjango/djangorestframework-stubs' && always() && needs.build.result == 'failure' }} + permissions: + issues: write + steps: + - uses: actions/github-script@v6 + with: + script: | + await github.rest.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: `Release failure on ${new Date().toDateString()}`, + body: `Details: https://github.com/${context.repo.owner}/${context.repo.repo}/actions/workflows/release.yml`, + }) From fa288326e0fc82a12a693c2a0a2979ecb7fdf501 Mon Sep 17 00:00:00 2001 From: Terence Honles Date: Mon, 13 Jun 2022 11:32:55 -0700 Subject: [PATCH 04/42] Enable GitHub auto generated release notes for GitHub releases (#229) --- .github/workflows/release.yml | 1 + scripts/typecheck_tests.py | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1dac81986..fd27195f8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -45,6 +45,7 @@ jobs: repo: context.repo.repo, tag_name: tagName, name: `Release ${tagName.replace(/^v/, '')}`, + generate_release_notes: true, }); if (release.status < 200 || release.status >= 300) { diff --git a/scripts/typecheck_tests.py b/scripts/typecheck_tests.py index 3e219b136..3b5b612e4 100644 --- a/scripts/typecheck_tests.py +++ b/scripts/typecheck_tests.py @@ -80,6 +80,7 @@ "browsable_api": [ '(expression has type "List[Dict[str, Dict[str, int]]]", base class "GenericAPIView" defined the type as "Union[QuerySet[_MT?], Manager[_MT?], None]")', # noqa: E501 'expression has type "List[Dict[str, Dict[str, int]]]"', + 'List item 0 has incompatible type "Type[IsAuthenticated]', ], "conftest.py": ["Unsupported operand types for"], "models.py": ['"ForeignKeyTarget" has no attribute "sources"'], From 621694133a6d8023199ee77b86099bad448c2026 Mon Sep 17 00:00:00 2001 From: David Hotham Date: Sun, 19 Jun 2022 10:51:14 +0100 Subject: [PATCH 05/42] compatible-mypy extra (#233) --- README.md | 2 +- requirements.txt | 2 +- setup.py | 7 ++++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c6a6b5776..c081734b6 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Supports Python 3.6, 3.7, 3.8 and 3.9. ## Installation ```bash -pip install djangorestframework-stubs +pip install djangorestframework-stubs[compatible-mypy] ``` To make mypy aware of the plugin, you need to add diff --git a/requirements.txt b/requirements.txt index e5ae1c8a6..b51fc94e7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,4 +5,4 @@ pytest==7.1.2 pytest-mypy-plugins==1.9.3 djangorestframework==3.13.1 types-pytz==2021.3.8 --e . +-e .[compatible-mypy] diff --git a/setup.py b/setup.py index 32381d124..f191920fa 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ def find_stub_files(name): readme = f.read() dependencies = [ - "mypy>=0.950,<0.970", + "mypy>=0.950", "django-stubs>=1.11.0", "typing-extensions>=3.10.0", "requests>=2.0.0", @@ -29,6 +29,10 @@ def find_stub_files(name): "types-Markdown>=0.1.5", ] +extras_require = { + "compatible-mypy": ["mypy>=0.950,<0.970"], +} + setup( name="djangorestframework-stubs", version="1.6.0", @@ -40,6 +44,7 @@ def find_stub_files(name): author_email="maxim.kurnikov@gmail.com", license="MIT", install_requires=dependencies, + extras_require=extras_require, packages=["rest_framework-stubs", *find_packages(exclude=["scripts"])], package_data={"rest_framework-stubs": find_stub_files("rest_framework-stubs")}, python_requires=">=3.7", From 5d630baabdb0ee87c2eb8b6aa3b534187c85e2d4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Jun 2022 11:39:03 +0300 Subject: [PATCH 06/42] Bump types-pytz from 2021.3.8 to 2022.1.0 (#235) Bumps [types-pytz](https://github.com/python/typeshed) from 2021.3.8 to 2022.1.0. - [Release notes](https://github.com/python/typeshed/releases) - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-pytz dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b51fc94e7..4f8e695f6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,5 +4,5 @@ pre-commit==2.19.0 pytest==7.1.2 pytest-mypy-plugins==1.9.3 djangorestframework==3.13.1 -types-pytz==2021.3.8 +types-pytz==2022.1.0 -e .[compatible-mypy] From bf412d40b3d7db1dcf3ef39acc469cc958413fcc Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Wed, 22 Jun 2022 12:25:39 +0300 Subject: [PATCH 07/42] Version 1.7.0 release (#236) Version 1.7.0 release, closes #234 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index f191920fa..3a47c4ac0 100644 --- a/setup.py +++ b/setup.py @@ -35,7 +35,7 @@ def find_stub_files(name): setup( name="djangorestframework-stubs", - version="1.6.0", + version="1.7.0", description="PEP-484 stubs for django-rest-framework", long_description=readme, long_description_content_type="text/markdown", From 9bfea3a317f49230798d0d9b509b404526361ab4 Mon Sep 17 00:00:00 2001 From: Marti Raudsepp Date: Wed, 22 Jun 2022 18:03:22 +0300 Subject: [PATCH 08/42] Use ImmutableQueryDict for request params (#237) * Use ImmutableQueryDict for request params * Bump typing-extensions requirement for assert_type * Drop assert_type --- rest_framework-stubs/parsers.pyi | 6 +++--- rest_framework-stubs/request.pyi | 7 ++++--- tests/typecheck/test_request.yml | 7 +++++++ 3 files changed, 14 insertions(+), 6 deletions(-) create mode 100644 tests/typecheck/test_request.yml diff --git a/rest_framework-stubs/parsers.pyi b/rest_framework-stubs/parsers.pyi index 7493fb2f6..b3b0b779b 100644 --- a/rest_framework-stubs/parsers.pyi +++ b/rest_framework-stubs/parsers.pyi @@ -1,7 +1,7 @@ from typing import IO, Any, Dict, Generic, Mapping, Optional, Type, TypeVar, Union from django.core.files.uploadedfile import UploadedFile -from django.http import QueryDict +from django.http.request import _ImmutableQueryDict from django.utils.datastructures import MultiValueDict from rest_framework.renderers import JSONRenderer @@ -29,12 +29,12 @@ class JSONParser(BaseParser): class FormParser(BaseParser): def parse( self, stream: IO[Any], media_type: Optional[str] = ..., parser_context: Optional[Mapping[str, Any]] = ... - ) -> QueryDict: ... + ) -> _ImmutableQueryDict: ... class MultiPartParser(BaseParser): def parse( self, stream: IO[Any], media_type: Optional[str] = ..., parser_context: Optional[Mapping[str, Any]] = ... - ) -> DataAndFiles[QueryDict, MultiValueDict]: ... + ) -> DataAndFiles[_ImmutableQueryDict, MultiValueDict]: ... class FileUploadParser(BaseParser): errors: Dict[str, str] = ... diff --git a/rest_framework-stubs/request.pyi b/rest_framework-stubs/request.pyi index 685f632c7..3b670f22a 100644 --- a/rest_framework-stubs/request.pyi +++ b/rest_framework-stubs/request.pyi @@ -4,7 +4,8 @@ from typing import Any, ContextManager, Dict, Iterator, Optional, Sequence, Tupl from django.contrib.auth.base_user import AbstractBaseUser from django.contrib.auth.models import AnonymousUser -from django.http import HttpRequest, QueryDict +from django.http import HttpRequest +from django.http.request import _ImmutableQueryDict from rest_framework.authentication import BaseAuthentication from rest_framework.authtoken.models import Token from rest_framework.negotiation import BaseContentNegotiation @@ -64,7 +65,7 @@ class Request(HttpRequest): @property def stream(self) -> Any: ... @property - def query_params(self) -> QueryDict: ... + def query_params(self) -> _ImmutableQueryDict: ... @property def data(self) -> Dict[str, Any]: ... @property # type: ignore[override] @@ -81,7 +82,7 @@ class Request(HttpRequest): @property def DATA(self) -> None: ... @property - def POST(self) -> QueryDict: ... # type: ignore[override] + def POST(self) -> _ImmutableQueryDict: ... # type: ignore[override] @property def FILES(self): ... @property diff --git a/tests/typecheck/test_request.yml b/tests/typecheck/test_request.yml new file mode 100644 index 000000000..421569528 --- /dev/null +++ b/tests/typecheck/test_request.yml @@ -0,0 +1,7 @@ +- case: request_querydict + main: | + from rest_framework.request import Request + + def some_view(request: Request) -> None: + reveal_type(request.query_params['field']) # N: Revealed type is "builtins.str" + reveal_type(request.POST['field']) # N: Revealed type is "builtins.str" From 4e6b585fdc4d073cc4784e54a698588c419eb703 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jun 2022 13:45:05 +0300 Subject: [PATCH 09/42] Bump types-pytz from 2022.1.0 to 2022.1.1 (#240) Bumps [types-pytz](https://github.com/python/typeshed) from 2022.1.0 to 2022.1.1. - [Release notes](https://github.com/python/typeshed/releases) - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-pytz dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 4f8e695f6..e7f427f9e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,5 +4,5 @@ pre-commit==2.19.0 pytest==7.1.2 pytest-mypy-plugins==1.9.3 djangorestframework==3.13.1 -types-pytz==2022.1.0 +types-pytz==2022.1.1 -e .[compatible-mypy] From 093acb78bf7b218ca4e75b57059e059806925eae Mon Sep 17 00:00:00 2001 From: sobolevn Date: Tue, 28 Jun 2022 23:15:52 +0300 Subject: [PATCH 10/42] Bump `actions/setup-python` --- .github/workflows/test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ec54f7014..4808becdb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install dependencies @@ -37,7 +37,7 @@ jobs: - name: Setup system dependencies run: sudo apt-get install binutils libproj-dev gdal-bin - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install dependencies @@ -58,7 +58,7 @@ jobs: - name: Setup system dependencies run: sudo apt-get install binutils libproj-dev gdal-bin - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install dependencies From 9eee73bc016193fd3fbf08c0ffe5e6298f2b6a6f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Jun 2022 23:31:06 +0300 Subject: [PATCH 11/42] Bump actions/setup-python from 3 to 4 (#231) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 3 to 4. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fd27195f8..a2994202e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ jobs: steps: - uses: actions/checkout@v3 - - uses: actions/setup-python@v3 + - uses: actions/setup-python@v4 with: python-version: '3.9' From 5575bbddbbe76d564c9ed4aae1913a88f8b9a558 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Jul 2022 11:49:12 +0300 Subject: [PATCH 12/42] Bump pre-commit from 2.19.0 to 2.20.0 (#241) Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 2.19.0 to 2.20.0. - [Release notes](https://github.com/pre-commit/pre-commit/releases) - [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md) - [Commits](https://github.com/pre-commit/pre-commit/compare/v2.19.0...v2.20.0) --- updated-dependencies: - dependency-name: pre-commit dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index e7f427f9e..76b6461ac 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ wheel gitpython==3.1.27 -pre-commit==2.19.0 +pre-commit==2.20.0 pytest==7.1.2 pytest-mypy-plugins==1.9.3 djangorestframework==3.13.1 From 955482c4a309018f6b1a87ddf02c560c0156b7d5 Mon Sep 17 00:00:00 2001 From: Marti Raudsepp Date: Tue, 19 Jul 2022 15:04:01 +0300 Subject: [PATCH 13/42] Make coreapi & markdown requirements optional (#243) * Make coreapi & markdown deps optional * Fix Black * Enable extras in requirements.txt --- requirements.txt | 2 +- rest_framework-stubs/compat.pyi | 9 ++++++--- setup.py | 4 ++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/requirements.txt b/requirements.txt index 76b6461ac..91ac611bb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,4 +5,4 @@ pytest==7.1.2 pytest-mypy-plugins==1.9.3 djangorestframework==3.13.1 types-pytz==2022.1.1 --e .[compatible-mypy] +-e .[compatible-mypy,coreapi,markdown] diff --git a/rest_framework-stubs/compat.pyi b/rest_framework-stubs/compat.pyi index a036ee1b3..1680cb5b8 100644 --- a/rest_framework-stubs/compat.pyi +++ b/rest_framework-stubs/compat.pyi @@ -1,6 +1,5 @@ from typing import Any, Optional, Tuple, Union -import coreapi # noqa: F401 import requests # noqa: F401 from django.db.models import QuerySet @@ -8,6 +7,10 @@ try: from django.contrib.postgres import fields as postgres_fields except ImportError: postgres_fields = None # type: ignore +try: + import coreapi +except ImportError: + coreapi = None # type: ignore try: import uritemplate except ImportError: @@ -29,7 +32,7 @@ try: except ImportError: pygments = None # type: ignore try: - import markdown + import markdown # type: ignore def apply_markdown(text: str): ... except ImportError: @@ -37,7 +40,7 @@ except ImportError: markdown = None # type: ignore if markdown is not None and pygments is not None: - from markdown.preprocessors import Preprocessor + from markdown.preprocessors import Preprocessor # type: ignore class CodeBlockPreprocessor(Preprocessor): pattern: Any = ... diff --git a/setup.py b/setup.py index 3a47c4ac0..967db117f 100644 --- a/setup.py +++ b/setup.py @@ -23,14 +23,14 @@ def find_stub_files(name): "django-stubs>=1.11.0", "typing-extensions>=3.10.0", "requests>=2.0.0", - "coreapi>=2.0.0", "types-requests>=0.1.12", "types-PyYAML>=5.4.3", - "types-Markdown>=0.1.5", ] extras_require = { "compatible-mypy": ["mypy>=0.950,<0.970"], + "coreapi": ["coreapi>=2.0.0"], + "markdown": ["types-Markdown>=0.1.5"], } setup( From 670f5218dae28dd65df2c75bb9bb6fc7d382dee8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Jul 2022 09:34:04 +0300 Subject: [PATCH 14/42] Bump types-pytz from 2022.1.1 to 2022.1.2 (#245) Bumps [types-pytz](https://github.com/python/typeshed) from 2022.1.1 to 2022.1.2. - [Release notes](https://github.com/python/typeshed/releases) - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-pytz dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 91ac611bb..82a3cf604 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,5 +4,5 @@ pre-commit==2.20.0 pytest==7.1.2 pytest-mypy-plugins==1.9.3 djangorestframework==3.13.1 -types-pytz==2022.1.1 +types-pytz==2022.1.2 -e .[compatible-mypy,coreapi,markdown] From 4b62d406151a142f7b24600014b97df38f5b64cd Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Fri, 22 Jul 2022 09:42:34 +0300 Subject: [PATCH 15/42] Create pre-commit-autoupdate.yml --- .github/workflows/pre-commit-autoupdate.yml | 45 +++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 .github/workflows/pre-commit-autoupdate.yml diff --git a/.github/workflows/pre-commit-autoupdate.yml b/.github/workflows/pre-commit-autoupdate.yml new file mode 100644 index 000000000..55660cbc3 --- /dev/null +++ b/.github/workflows/pre-commit-autoupdate.yml @@ -0,0 +1,45 @@ +# Run pre-commit autoupdate every day at midnight +# and create a pull request if any changes +# Copied from +# https://github.com/cookiecutter/cookiecutter-django + +name: Pre-commit auto-update + +on: + schedule: + - cron: "15 2 * * *" + workflow_dispatch: # to trigger manually + +permissions: + contents: read + +jobs: + auto-update: + # Disables this workflow from running in a repository that is not part of the indicated organization/user + if: github.repository_owner == 'typeddjango' + permissions: + contents: write # for peter-evans/create-pull-request to create branch + pull-requests: write # for peter-evans/create-pull-request to create a PR + + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: "3.9" + + - name: Install pre-commit + run: pip install pre-commit + + - name: Autoupdate deps + run: pre-commit autoupdate + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + branch: update/pre-commit-autoupdate + title: Auto-update pre-commit hooks + commit-message: Auto-update pre-commit hooks + body: Update versions of tools in pre-commit configs to latest version + labels: dependencies From 03b404a237f618aa500d7604044004cf80f2d482 Mon Sep 17 00:00:00 2001 From: henribru <6639509+henribru@users.noreply.github.com> Date: Fri, 22 Jul 2022 08:43:33 +0200 Subject: [PATCH 16/42] Preserve generic in extended generic views and viewsets (#215) --- rest_framework-stubs/generics.pyi | 18 +++++++++--------- rest_framework-stubs/viewsets.pyi | 7 ++++--- tests/typecheck/test_views.yml | 26 ++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/rest_framework-stubs/generics.pyi b/rest_framework-stubs/generics.pyi index aef92b11b..9efc6ced0 100644 --- a/rest_framework-stubs/generics.pyi +++ b/rest_framework-stubs/generics.pyi @@ -46,37 +46,37 @@ class GenericAPIView(views.APIView, UsesQuerySet[_MT_co]): def paginate_queryset(self, queryset: Union[QuerySet[_MT_co], Sequence[Any]]) -> Optional[Sequence[Any]]: ... def get_paginated_response(self, data: Any) -> Response: ... -class CreateAPIView(mixins.CreateModelMixin, GenericAPIView): +class CreateAPIView(mixins.CreateModelMixin, GenericAPIView[_MT_co]): def post(self, request: Request, *args: Any, **kwargs: Any) -> Response: ... -class ListAPIView(mixins.ListModelMixin, GenericAPIView): +class ListAPIView(mixins.ListModelMixin, GenericAPIView[_MT_co]): def get(self, request: Request, *args: Any, **kwargs: Any) -> Response: ... -class RetrieveAPIView(mixins.RetrieveModelMixin, GenericAPIView): +class RetrieveAPIView(mixins.RetrieveModelMixin, GenericAPIView[_MT_co]): def get(self, request: Request, *args: Any, **kwargs: Any) -> Response: ... -class DestroyAPIView(mixins.DestroyModelMixin, GenericAPIView): +class DestroyAPIView(mixins.DestroyModelMixin, GenericAPIView[_MT_co]): def delete(self, request: Request, *args: Any, **kwargs: Any) -> Response: ... -class UpdateAPIView(mixins.UpdateModelMixin, GenericAPIView): +class UpdateAPIView(mixins.UpdateModelMixin, GenericAPIView[_MT_co]): def put(self, request: Request, *args: Any, **kwargs: Any) -> Response: ... def patch(self, request: Request, *args: Any, **kwargs: Any) -> Response: ... -class ListCreateAPIView(mixins.ListModelMixin, mixins.CreateModelMixin, GenericAPIView): +class ListCreateAPIView(mixins.ListModelMixin, mixins.CreateModelMixin, GenericAPIView[_MT_co]): def get(self, request: Request, *args: Any, **kwargs: Any) -> Response: ... def post(self, request: Request, *args: Any, **kwargs: Any) -> Response: ... -class RetrieveUpdateAPIView(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, GenericAPIView): +class RetrieveUpdateAPIView(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, GenericAPIView[_MT_co]): def get(self, request: Request, *args: Any, **kwargs: Any) -> Response: ... def put(self, request: Request, *args: Any, **kwargs: Any) -> Response: ... def patch(self, request: Request, *args: Any, **kwargs: Any) -> Response: ... -class RetrieveDestroyAPIView(mixins.RetrieveModelMixin, mixins.DestroyModelMixin, GenericAPIView): +class RetrieveDestroyAPIView(mixins.RetrieveModelMixin, mixins.DestroyModelMixin, GenericAPIView[_MT_co]): def get(self, request: Request, *args: Any, **kwargs: Any) -> Response: ... def delete(self, request: Request, *args: Any, **kwargs: Any) -> Response: ... class RetrieveUpdateDestroyAPIView( - mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, GenericAPIView + mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, GenericAPIView[_MT_co] ): def get(self, request: Request, *args: Any, **kwargs: Any) -> Response: ... def put(self, request: Request, *args: Any, **kwargs: Any) -> Response: ... diff --git a/rest_framework-stubs/viewsets.pyi b/rest_framework-stubs/viewsets.pyi index 06be5c955..e02509b68 100644 --- a/rest_framework-stubs/viewsets.pyi +++ b/rest_framework-stubs/viewsets.pyi @@ -5,6 +5,7 @@ from django.http.request import HttpRequest from django.http.response import HttpResponseBase from rest_framework import generics, mixins, views from rest_framework.decorators import ViewSetAction +from rest_framework.generics import _MT_co from rest_framework.request import Request from rest_framework.views import AsView, GenericView @@ -36,13 +37,13 @@ class ViewSetMixin: def get_extra_action_url_map(self) -> OrderedDict[str, str]: ... class ViewSet(ViewSetMixin, views.APIView): ... -class GenericViewSet(ViewSetMixin, generics.GenericAPIView): ... -class ReadOnlyModelViewSet(mixins.RetrieveModelMixin, mixins.ListModelMixin, GenericViewSet): ... +class GenericViewSet(ViewSetMixin, generics.GenericAPIView[_MT_co]): ... +class ReadOnlyModelViewSet(mixins.RetrieveModelMixin, mixins.ListModelMixin, GenericViewSet[_MT_co]): ... class ModelViewSet( mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, - GenericViewSet, + GenericViewSet[_MT_co], ): ... diff --git a/tests/typecheck/test_views.yml b/tests/typecheck/test_views.yml index f9dfb93aa..c0137bce6 100644 --- a/tests/typecheck/test_views.yml +++ b/tests/typecheck/test_views.yml @@ -29,3 +29,29 @@ view: APIView api_request = view.initialize_request(request) reveal_type(api_request) # N: Revealed type is "rest_framework.request.Request" + +- case: test_generics_of_extended_generic_view + main: | + from rest_framework import generics + from django.db.models import Model + + class MyModel(Model): + pass + + class MyRetrieveView(generics.RetrieveAPIView[MyModel]): + pass + + reveal_type(MyRetrieveView().get_object()) # N: Revealed type is "main.MyModel*" + +- case: test_generics_of_extended_generic_view_set + main: | + from rest_framework import viewsets + from django.db.models import Model + + class MyModel(Model): + pass + + class MyRetrieveViewSet(viewsets.GenericViewSet[MyModel]): + pass + + reveal_type(MyRetrieveViewSet().get_object()) # N: Revealed type is "main.MyModel*" From de32b9c4b3f5d34712bc9fb5d972a22647d25b66 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Fri, 22 Jul 2022 09:50:03 +0300 Subject: [PATCH 17/42] Fix CI --- tests/typecheck/test_views.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/typecheck/test_views.yml b/tests/typecheck/test_views.yml index c0137bce6..cad9aaee2 100644 --- a/tests/typecheck/test_views.yml +++ b/tests/typecheck/test_views.yml @@ -41,7 +41,7 @@ class MyRetrieveView(generics.RetrieveAPIView[MyModel]): pass - reveal_type(MyRetrieveView().get_object()) # N: Revealed type is "main.MyModel*" + reveal_type(MyRetrieveView().get_object()) # N: Revealed type is "main.MyModel" - case: test_generics_of_extended_generic_view_set main: | @@ -54,4 +54,4 @@ class MyRetrieveViewSet(viewsets.GenericViewSet[MyModel]): pass - reveal_type(MyRetrieveViewSet().get_object()) # N: Revealed type is "main.MyModel*" + reveal_type(MyRetrieveViewSet().get_object()) # N: Revealed type is "main.MyModel" From aecbccbeb88ab183342e073ae7df5048595976e2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 22 Jul 2022 09:53:07 +0300 Subject: [PATCH 18/42] Auto-update pre-commit hooks (#246) Co-authored-by: sobolevn --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d7f5d7023..3e5e7d410 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.1.0 + rev: v4.3.0 hooks: - id: check-yaml - id: trailing-whitespace @@ -11,7 +11,7 @@ repos: - id: check-merge-conflict - id: end-of-file-fixer - repo: https://github.com/asottile/pyupgrade - rev: v2.31.1 + rev: v2.37.2 hooks: - id: pyupgrade args: ["--py36-plus"] @@ -20,7 +20,7 @@ repos: hooks: - id: isort - repo: https://github.com/psf/black - rev: 22.3.0 + rev: 22.6.0 hooks: - id: black - repo: https://gitlab.com/pycqa/flake8 From f6eb80c2018cb297843ae7b197d9a23a2cc901f7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 27 Jul 2022 10:23:25 +0300 Subject: [PATCH 19/42] Auto-update pre-commit hooks (#248) Co-authored-by: sobolevn --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3e5e7d410..97ef3d1ba 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ repos: - id: check-merge-conflict - id: end-of-file-fixer - repo: https://github.com/asottile/pyupgrade - rev: v2.37.2 + rev: v2.37.3 hooks: - id: pyupgrade args: ["--py36-plus"] From 06f84b20070304e24bd364cebc0f2fcfeac192c5 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Fri, 26 Aug 2022 13:09:07 +0300 Subject: [PATCH 20/42] Delete release.yml --- .github/workflows/release.yml | 73 ----------------------------------- 1 file changed, 73 deletions(-) delete mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index a2994202e..000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,73 +0,0 @@ -name: Release - -on: - push: - tags: - - '*' - -jobs: - build: - if: github.repository == 'typeddjango/djangorestframework-stubs' - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - - uses: actions/setup-python@v4 - with: - python-version: '3.9' - - - name: Install dependencies - run: | - python -m pip install -U pip - python -m pip install -U setuptools twine wheel - - - name: Build package - run: | - python setup.py --version - python setup.py sdist bdist_wheel - - - name: Publish package to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 - with: - user: __token__ - password: ${{ secrets.PYPI_API_TOKEN }} - - print_hash: true - - - name: Create release - uses: actions/github-script@v6 - with: - script: | - const tagName = context.ref.replace(/^refs\/tags\//, ''); - const release = await github.rest.repos.createRelease({ - owner: context.repo.owner, - repo: context.repo.repo, - tag_name: tagName, - name: `Release ${tagName.replace(/^v/, '')}`, - generate_release_notes: true, - }); - - if (release.status < 200 || release.status >= 300) { - core.setFailed(`Could not create release for tag '${tagName}'`); - return; - } - - # https://github.community/t/run-github-actions-job-only-if-previous-job-has-failed/174786/2 - create-issue-on-failure: - name: Create an issue if release failed - runs-on: ubuntu-latest - needs: [build] - if: ${{ github.repository == 'typeddjango/djangorestframework-stubs' && always() && needs.build.result == 'failure' }} - permissions: - issues: write - steps: - - uses: actions/github-script@v6 - with: - script: | - await github.rest.issues.create({ - owner: context.repo.owner, - repo: context.repo.repo, - title: `Release failure on ${new Date().toDateString()}`, - body: `Details: https://github.com/${context.repo.owner}/${context.repo.repo}/actions/workflows/release.yml`, - }) From 86597b5f375e4c58857e716ef1dfa484d2af7e15 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 11:41:59 +0300 Subject: [PATCH 21/42] Auto-update pre-commit hooks (#252) Co-authored-by: sobolevn --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 97ef3d1ba..671ce5f1b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,7 +20,7 @@ repos: hooks: - id: isort - repo: https://github.com/psf/black - rev: 22.6.0 + rev: 22.8.0 hooks: - id: black - repo: https://gitlab.com/pycqa/flake8 From ed16be9761c7ab530a97659469aa568c379bf3fd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 25 Sep 2022 08:51:47 +0300 Subject: [PATCH 22/42] Auto-update pre-commit hooks (#254) Co-authored-by: sobolevn --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 671ce5f1b..7b5485a15 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ repos: - id: check-merge-conflict - id: end-of-file-fixer - repo: https://github.com/asottile/pyupgrade - rev: v2.37.3 + rev: v2.38.1 hooks: - id: pyupgrade args: ["--py36-plus"] From e46f90ecb16eb9a0a32a5762843d3f36f0af9075 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 26 Sep 2022 09:17:24 +0300 Subject: [PATCH 23/42] Auto-update pre-commit hooks (#257) Co-authored-by: sobolevn --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7b5485a15..165120ca9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ repos: - id: check-merge-conflict - id: end-of-file-fixer - repo: https://github.com/asottile/pyupgrade - rev: v2.38.1 + rev: v2.38.2 hooks: - id: pyupgrade args: ["--py36-plus"] From ec5ecd40c0be07418accbe1f94fda74d4b377c24 Mon Sep 17 00:00:00 2001 From: Marti Raudsepp Date: Tue, 8 Nov 2022 00:38:09 +0200 Subject: [PATCH 24/42] Fix errors in CI (#273) --- pyproject.toml | 3 +++ requirements.txt | 2 ++ rest_framework-stubs/decorators.pyi | 2 ++ rest_framework-stubs/permissions.pyi | 4 ++-- scripts/typecheck_tests.py | 2 ++ 5 files changed, 11 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c2f6735a3..2a369e0dc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,3 +7,6 @@ line_length = 120 multi_line_output = 3 include_trailing_comma = true profile = 'black' + +[build-system] +requires = ["setuptools<64", "wheel"] diff --git a/requirements.txt b/requirements.txt index 82a3cf604..5728f75d5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,4 +5,6 @@ pytest==7.1.2 pytest-mypy-plugins==1.9.3 djangorestframework==3.13.1 types-pytz==2022.1.2 +django-stubs==1.12.0 +django-stubs-ext==0.5.0 -e .[compatible-mypy,coreapi,markdown] diff --git a/rest_framework-stubs/decorators.pyi b/rest_framework-stubs/decorators.pyi index d2265dfb6..a301826ea 100644 --- a/rest_framework-stubs/decorators.pyi +++ b/rest_framework-stubs/decorators.pyi @@ -48,6 +48,7 @@ _MIXED_CASE_HTTP_VERBS = List[ "PUT", "PATCH", "TRACE", + "HEAD", "OPTIONS", "get", "post", @@ -55,6 +56,7 @@ _MIXED_CASE_HTTP_VERBS = List[ "put", "patch", "trace", + "head", "options", ] ] diff --git a/rest_framework-stubs/permissions.pyi b/rest_framework-stubs/permissions.pyi index 5a0823941..5b7acba92 100644 --- a/rest_framework-stubs/permissions.pyi +++ b/rest_framework-stubs/permissions.pyi @@ -43,8 +43,8 @@ class OR(_SupportsHasPermission): class NOT(_SupportsHasPermission): def __init__(self, op1: _SupportsHasPermission) -> None: ... -class BasePermissionMetaclass(OperationHolderMixin, type): ... -class BasePermission(_SupportsHasPermission, metaclass=BasePermissionMetaclass): ... +class BasePermissionMetaclass(OperationHolderMixin, type): ... # type: ignore[misc] +class BasePermission(_SupportsHasPermission, metaclass=BasePermissionMetaclass): ... # type: ignore[misc] class AllowAny(BasePermission): ... class IsAuthenticated(BasePermission): ... class IsAdminUser(BasePermission): ... diff --git a/scripts/typecheck_tests.py b/scripts/typecheck_tests.py index 3b5b612e4..819c1b579 100644 --- a/scripts/typecheck_tests.py +++ b/scripts/typecheck_tests.py @@ -157,6 +157,8 @@ '"ResolverMatch" has incompatible type "str"; expected "Callable[..., Any]"', "_SupportsHasPermission", "Invalid type alias: expression is not a valid type", + '"object" not callable', + 'Cannot assign multiple types to name "composed_perm" without an explicit "Type[...]" annotation', ], "test_relations.py": [ 'Invalid index type "int" for "Union[str, List[Any], Dict[str, Any]]"; expected type "str"', From 06a2f2f9f6c05a07f03bc1bd7f1b54ecfd7a3c43 Mon Sep 17 00:00:00 2001 From: Marti Raudsepp Date: Tue, 8 Nov 2022 01:20:49 +0200 Subject: [PATCH 25/42] Add missing PageNumberPagination.get_page_number() method (#263) --- rest_framework-stubs/pagination.pyi | 1 + 1 file changed, 1 insertion(+) diff --git a/rest_framework-stubs/pagination.pyi b/rest_framework-stubs/pagination.pyi index 7759908fe..2b97c7d05 100644 --- a/rest_framework-stubs/pagination.pyi +++ b/rest_framework-stubs/pagination.pyi @@ -68,6 +68,7 @@ class PageNumberPagination(BasePagination): def get_paginated_response_schema(self, schema: Dict[str, Any]) -> Dict[str, Any]: ... def get_schema_fields(self, view: APIView) -> List[CoreAPIField]: ... def get_schema_operation_parameters(self, view: APIView) -> List[Dict[str, Any]]: ... + def get_page_number(self, request: Request, paginator: Paginator) -> Union[int, str]: ... def get_page_size(self, request: Request) -> Optional[int]: ... def get_next_link(self) -> Optional[str]: ... def get_previous_link(self) -> Optional[str]: ... From 42b0d20d34c95165133e034b1e91eed88c846361 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 10 Nov 2022 10:57:36 +0300 Subject: [PATCH 26/42] Auto-update pre-commit hooks (#281) Co-authored-by: sobolevn --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 165120ca9..a4ce73d66 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ repos: - id: check-merge-conflict - id: end-of-file-fixer - repo: https://github.com/asottile/pyupgrade - rev: v2.38.2 + rev: v3.2.1 hooks: - id: pyupgrade args: ["--py36-plus"] @@ -20,7 +20,7 @@ repos: hooks: - id: isort - repo: https://github.com/psf/black - rev: 22.8.0 + rev: 22.10.0 hooks: - id: black - repo: https://gitlab.com/pycqa/flake8 From b8e865fb7815f6609505a1a5775031ab95e0d370 Mon Sep 17 00:00:00 2001 From: Marti Raudsepp Date: Fri, 11 Nov 2022 12:13:48 +0200 Subject: [PATCH 27/42] Update django-stubs, mypy, pytest-mypy-plugins & fix tests (#279) All these updates have to be done together, otherwise one dependency is incompatible with another in some way that fails in CI. --- requirements.txt | 6 +++--- scripts/drf_tests_settings.py | 4 ++-- scripts/typecheck_tests.py | 1 + setup.py | 6 +++--- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/requirements.txt b/requirements.txt index 5728f75d5..bd0c99099 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,9 +2,9 @@ wheel gitpython==3.1.27 pre-commit==2.20.0 pytest==7.1.2 -pytest-mypy-plugins==1.9.3 +pytest-mypy-plugins==1.10.1 djangorestframework==3.13.1 types-pytz==2022.1.2 -django-stubs==1.12.0 -django-stubs-ext==0.5.0 +django-stubs==1.13.0 +django-stubs-ext==0.7.0 -e .[compatible-mypy,coreapi,markdown] diff --git a/scripts/drf_tests_settings.py b/scripts/drf_tests_settings.py index a2ff5ffb4..14c0d6dac 100644 --- a/scripts/drf_tests_settings.py +++ b/scripts/drf_tests_settings.py @@ -1,7 +1,7 @@ SECRET_KEY = "1" SITE_ID = 1 -INSTALLED_APPS = [ +INSTALLED_APPS = ( "django.contrib.contenttypes", "django.contrib.sites", "django.contrib.sessions", @@ -11,4 +11,4 @@ "django.contrib.auth", "rest_framework", "rest_framework.authtoken", -] +) diff --git a/scripts/typecheck_tests.py b/scripts/typecheck_tests.py index 819c1b579..ccf84dfe8 100644 --- a/scripts/typecheck_tests.py +++ b/scripts/typecheck_tests.py @@ -76,6 +76,7 @@ 'Incompatible types in assignment (expression has type "AsView[GenericView]", variable has type "AsView[Callable[[HttpRequest], Any]]")', # noqa: E501 'Argument "patterns" to "SchemaGenerator" has incompatible type "List[object]"', 'Argument 1 to "field_to_schema" has incompatible type "object"; expected "Field[Any, Any, Any, Any]"', + 'Argument "help_text" to "CharField" has incompatible type "_StrPromise"', ], "browsable_api": [ '(expression has type "List[Dict[str, Dict[str, int]]]", base class "GenericAPIView" defined the type as "Union[QuerySet[_MT?], Manager[_MT?], None]")', # noqa: E501 diff --git a/setup.py b/setup.py index 967db117f..d0139eec2 100644 --- a/setup.py +++ b/setup.py @@ -19,8 +19,8 @@ def find_stub_files(name): readme = f.read() dependencies = [ - "mypy>=0.950", - "django-stubs>=1.11.0", + "mypy>=0.980", + "django-stubs>=1.13.0", "typing-extensions>=3.10.0", "requests>=2.0.0", "types-requests>=0.1.12", @@ -28,7 +28,7 @@ def find_stub_files(name): ] extras_require = { - "compatible-mypy": ["mypy>=0.950,<0.970"], + "compatible-mypy": ["mypy>=0.980,<0.990"], "coreapi": ["coreapi>=2.0.0"], "markdown": ["types-Markdown>=0.1.5"], } From 89f8925c67027a759ca08c3643934aa8de107859 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 12 Nov 2022 11:43:01 +0300 Subject: [PATCH 28/42] Auto-update pre-commit hooks (#285) Co-authored-by: sobolevn --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a4ce73d66..7b7161b35 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ repos: - id: check-merge-conflict - id: end-of-file-fixer - repo: https://github.com/asottile/pyupgrade - rev: v3.2.1 + rev: v3.2.2 hooks: - id: pyupgrade args: ["--py36-plus"] From 09ac1ac551ce051680af25798e42cfaafe6c88ac Mon Sep 17 00:00:00 2001 From: mattwwarren Date: Tue, 15 Nov 2022 05:02:03 -0500 Subject: [PATCH 29/42] Fixes #230 - Response stub should inherit from TemplateResponse (#283) * Fixes #230 - Response stub should inherit from TemplateResponse * monkey-patch first attempt * flip monkey patching and use in APIClient * define remaining _MonkeyPatchedResponse attributes from django-stubs note: content is not defined here because it is provided already by SimpleTemplateResponse * use APIClient as _MonkeyPatchedResponse.client Co-authored-by: Matthew Warren --- rest_framework-stubs/response.pyi | 15 ++++++++++++++- rest_framework-stubs/test.pyi | 16 ++++++++-------- tests/typecheck/test_api_client.yml | 7 ++++++- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/rest_framework-stubs/response.pyi b/rest_framework-stubs/response.pyi index 97577e447..7a091e60b 100644 --- a/rest_framework-stubs/response.pyi +++ b/rest_framework-stubs/response.pyi @@ -1,8 +1,12 @@ -from typing import Any, Mapping, Optional +from typing import Any, Dict, List, Mapping, Optional, Tuple +from django.template.base import Template +from django.test.utils import ContextList from django.template.response import SimpleTemplateResponse +from django.urls import ResolverMatch from rest_framework.request import Request +from rest_framework.test import APIClient class Response(SimpleTemplateResponse): data: Any = ... @@ -23,3 +27,12 @@ class Response(SimpleTemplateResponse): def render(self) -> Any: ... @property def status_text(self) -> str: ... + +class _MonkeyPatchedResponse(Response): + client: APIClient + context: ContextList | Dict[str, Any] + redirect_chain: List[Tuple[str, int]] + request: Dict[str, Any] + resolver_match: ResolverMatch + templates: List[Template] + def json(self) -> Any: ... diff --git a/rest_framework-stubs/test.pyi b/rest_framework-stubs/test.pyi index 0b862369e..97e1130a5 100644 --- a/rest_framework-stubs/test.pyi +++ b/rest_framework-stubs/test.pyi @@ -12,7 +12,7 @@ from django.test.client import ClientHandler from django.test.client import RequestFactory as DjangoRequestFactory from rest_framework.authtoken.models import Token from rest_framework.request import Request -from rest_framework.response import Response +from rest_framework.response import _MonkeyPatchedResponse def force_authenticate( request: HttpRequest, user: Optional[Union[AnonymousUser, AbstractBaseUser]] = ..., token: Optional[Token] = ... @@ -62,7 +62,7 @@ class APIRequestFactory(DjangoRequestFactory): class ForceAuthClientHandler(ClientHandler): def __init__(self, *args: Any, **kwargs: Any): ... - def get_response(self, request: Request) -> Response: ... # type: ignore[override] + def get_response(self, request: Request) -> _MonkeyPatchedResponse: ... # type: ignore[override] class APIClient(APIRequestFactory, DjangoClient): handler: Any = ... @@ -70,13 +70,13 @@ class APIClient(APIRequestFactory, DjangoClient): def force_authenticate( self, user: Union[AnonymousUser, AbstractBaseUser] = ..., token: Optional[Token] = ... ) -> None: ... - def request(self, **kwargs: Any) -> Response: ... # type: ignore[override] + def request(self, **kwargs: Any) -> _MonkeyPatchedResponse: ... # type: ignore[override] def get(self, path: str, data: Optional[Union[Dict[str, Any], str]] = ..., follow: bool = ..., **extra: Any): ... # type: ignore[override] - def post(self, path: str, data: Optional[Any] = ..., format: Optional[str] = ..., content_type: Optional[str] = ..., follow: bool = ..., **extra: Any) -> Response: ... # type: ignore[override] - def put(self, path: str, data: Optional[Any] = ..., format: Optional[str] = ..., content_type: Optional[str] = ..., follow: bool = ..., **extra: Any) -> Response: ... # type: ignore[override] - def patch(self, path: str, data: Optional[Any] = ..., format: Optional[str] = ..., content_type: Optional[str] = ..., follow: bool = ..., **extra: Any) -> Response: ... # type: ignore[override] - def delete(self, path: str, data: Optional[Any] = ..., format: Optional[str] = ..., content_type: Optional[str] = ..., follow: bool = ..., **extra: Any) -> Response: ... # type: ignore[override] - def options(self, path: str, data: Union[Dict[str, str], str] = ..., format: Optional[str] = ..., content_type: Optional[Any] = ..., follow: bool = ..., **extra: Any) -> Response: ... # type: ignore[override] + def post(self, path: str, data: Optional[Any] = ..., format: Optional[str] = ..., content_type: Optional[str] = ..., follow: bool = ..., **extra: Any) -> _MonkeyPatchedResponse: ... # type: ignore[override] + def put(self, path: str, data: Optional[Any] = ..., format: Optional[str] = ..., content_type: Optional[str] = ..., follow: bool = ..., **extra: Any) -> _MonkeyPatchedResponse: ... # type: ignore[override] + def patch(self, path: str, data: Optional[Any] = ..., format: Optional[str] = ..., content_type: Optional[str] = ..., follow: bool = ..., **extra: Any) -> _MonkeyPatchedResponse: ... # type: ignore[override] + def delete(self, path: str, data: Optional[Any] = ..., format: Optional[str] = ..., content_type: Optional[str] = ..., follow: bool = ..., **extra: Any) -> _MonkeyPatchedResponse: ... # type: ignore[override] + def options(self, path: str, data: Union[Dict[str, str], str] = ..., format: Optional[str] = ..., content_type: Optional[Any] = ..., follow: bool = ..., **extra: Any) -> _MonkeyPatchedResponse: ... # type: ignore[override] def logout(self) -> None: ... class APITransactionTestCase(testcases.TransactionTestCase): diff --git a/tests/typecheck/test_api_client.yml b/tests/typecheck/test_api_client.yml index 9f7819990..c32e9a332 100644 --- a/tests/typecheck/test_api_client.yml +++ b/tests/typecheck/test_api_client.yml @@ -6,4 +6,9 @@ def test_my_code(self): client = test.APIClient() - reveal_type(client.post('http://google.com')) # N: Revealed type is "rest_framework.response.Response" + reveal_type(client.post('http://google.com')) # N: Revealed type is "rest_framework.response._MonkeyPatchedResponse" + + def test_json_attribute_on_response(self): + client = test.APIClient() + resp = client.get('http://someapi.com/1') + self.assertTrue(resp.json()) From d1b1641433fdfd766c51cd9f228161bf555f7f14 Mon Sep 17 00:00:00 2001 From: Marti Raudsepp Date: Tue, 15 Nov 2022 12:39:49 +0200 Subject: [PATCH 30/42] Fix CI: Use flake8 from GitHub not GitLab (#289) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7b7161b35..d13efb0b6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -23,7 +23,7 @@ repos: rev: 22.10.0 hooks: - id: black - - repo: https://gitlab.com/pycqa/flake8 + - repo: https://github.com/PyCQA/flake8 rev: 3.9.2 hooks: - id: flake8 From 47f08e45c28c390cf2043c4349b187fa3bd6c80e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 16 Nov 2022 11:28:25 +0300 Subject: [PATCH 31/42] Auto-update pre-commit hooks (#291) Co-authored-by: sobolevn --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d13efb0b6..06496c511 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,7 +24,7 @@ repos: hooks: - id: black - repo: https://github.com/PyCQA/flake8 - rev: 3.9.2 + rev: 5.0.4 hooks: - id: flake8 - repo: local From a1ec425434daf5e392e1d640bddca1486d4c98f9 Mon Sep 17 00:00:00 2001 From: Marti Raudsepp Date: Wed, 16 Nov 2022 10:48:52 +0200 Subject: [PATCH 32/42] Update to mypy 0.991 for compatible-mypy & CI (#280) * Update to mypy 0.991 for compatible-mypy & CI * Restore typecheck_tests.py ignores --- mypy.ini | 3 ++- rest_framework-stubs/permissions.pyi | 6 +++++- scripts/typecheck_tests.py | 6 +++++- setup.py | 2 +- tests/plugins.ini | 2 ++ 5 files changed, 15 insertions(+), 4 deletions(-) diff --git a/mypy.ini b/mypy.ini index feff15457..cb92fd27e 100644 --- a/mypy.ini +++ b/mypy.ini @@ -2,10 +2,11 @@ strict_optional = True ignore_missing_imports = True check_untyped_defs = True -warn_no_return = False show_traceback = True allow_redefinition = True incremental = True +show_error_codes = False +disable_error_code = empty-body plugins = mypy_django_plugin.main, diff --git a/rest_framework-stubs/permissions.pyi b/rest_framework-stubs/permissions.pyi index 5b7acba92..1a5c17650 100644 --- a/rest_framework-stubs/permissions.pyi +++ b/rest_framework-stubs/permissions.pyi @@ -44,7 +44,11 @@ class NOT(_SupportsHasPermission): def __init__(self, op1: _SupportsHasPermission) -> None: ... class BasePermissionMetaclass(OperationHolderMixin, type): ... # type: ignore[misc] -class BasePermission(_SupportsHasPermission, metaclass=BasePermissionMetaclass): ... # type: ignore[misc] + +class BasePermission(metaclass=BasePermissionMetaclass): # type: ignore[misc] + def has_permission(self, request: Request, view: APIView) -> bool: ... + def has_object_permission(self, request: Request, view: APIView, obj: Any) -> bool: ... + class AllowAny(BasePermission): ... class IsAuthenticated(BasePermission): ... class IsAdminUser(BasePermission): ... diff --git a/scripts/typecheck_tests.py b/scripts/typecheck_tests.py index ccf84dfe8..0bf7979cb 100644 --- a/scripts/typecheck_tests.py +++ b/scripts/typecheck_tests.py @@ -60,6 +60,9 @@ '"BaseTokenAuthTests" has no attribute "assertNumQueries"', 'Module "django.middleware.csrf" has no attribute "_mask_cipher_secret"', "All conditional function variants must have identical signatures", + "note: def _get_new_csrf_token() ->", + "note: Original:", + "note: Redefinition:", ], "schemas": [ '(expression has type "CharField", base class "Field" defined the type as "bool")', @@ -77,6 +80,7 @@ 'Argument "patterns" to "SchemaGenerator" has incompatible type "List[object]"', 'Argument 1 to "field_to_schema" has incompatible type "object"; expected "Field[Any, Any, Any, Any]"', 'Argument "help_text" to "CharField" has incompatible type "_StrPromise"', + '"Module rest_framework.schemas.coreapi" does not explicitly export attribute "coreapi"', ], "browsable_api": [ '(expression has type "List[Dict[str, Dict[str, int]]]", base class "GenericAPIView" defined the type as "Union[QuerySet[_MT?], Manager[_MT?], None]")', # noqa: E501 @@ -114,7 +118,7 @@ 'Argument "params" to "ValidationError" has incompatible type "Tuple[str]"', '"MultipleChoiceField[Model]" has no attribute "partial"', 'Argument 1 to "to_internal_value" of "Field" has incompatible type "Dict[str, str]"; expected "List[Any]"', - 'Module "rest_framework.fields" has no attribute "DjangoImageField"; maybe "ImageField"?', + 'Module "rest_framework.fields" does not explicitly export attribute "DjangoImageField"', 'Argument 1 to "ListField" has incompatible type "CharField"; expected "bool"', "Possible overload variants:", "def __init__(self, *, mutable: Literal[True], query_string: Union[str, bytes, None] = ..., encoding: Optional[str] = ...) -> QueryDict", # noqa: E501 diff --git a/setup.py b/setup.py index d0139eec2..8d2304b92 100644 --- a/setup.py +++ b/setup.py @@ -28,7 +28,7 @@ def find_stub_files(name): ] extras_require = { - "compatible-mypy": ["mypy>=0.980,<0.990"], + "compatible-mypy": ["mypy>=0.991,<0.1000"], "coreapi": ["coreapi>=2.0.0"], "markdown": ["types-Markdown>=0.1.5"], } diff --git a/tests/plugins.ini b/tests/plugins.ini index 4eb5060b7..4fb8ddabe 100644 --- a/tests/plugins.ini +++ b/tests/plugins.ini @@ -1,5 +1,7 @@ [mypy] check_untyped_defs = True +show_error_codes = False +disable_error_code = empty-body plugins = mypy_django_plugin.main, mypy_drf_plugin.main From 158fd4f8dcf7165928d68583dd7822a6cff14cd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oleg=20H=C3=B6fling?= Date: Wed, 16 Nov 2022 14:29:31 +0100 Subject: [PATCH 33/42] Introduce `flake8-pyi` in `pre-commit` checks (#286) This is a PR similar to typeddjango/django-stubs#1253, only for rest_framework-stubs. All statements that are unclear on how to proceed are marked with # noqa: in the code, with the exception of compat.pyi, which has additional rules turned off in setup.cfg. * configure flake8-pyi plugin in pre-commit * fix Y015 * fix Y037 * use PEP 585 container types where possible, replace obsolete typing types with collections.abc * disable Y041 rule * add typealias annotation where feasible, add self annotations * fix failing tests, silence remaining warnings since unclear how to proceed * address review * amend tests * amend rebase error Signed-off-by: Oleg Hoefling --- .pre-commit-config.yaml | 4 + rest_framework-stubs/authentication.pyi | 22 +- rest_framework-stubs/authtoken/__init__.pyi | 2 +- .../management/commands/drf_create_token.pyi | 2 +- rest_framework-stubs/authtoken/models.pyi | 6 +- .../authtoken/serializers.pyi | 6 +- rest_framework-stubs/authtoken/views.pyi | 6 +- rest_framework-stubs/checks.pyi | 4 +- rest_framework-stubs/compat.pyi | 18 +- rest_framework-stubs/decorators.pyi | 35 +- rest_framework-stubs/documentation.pyi | 45 +- rest_framework-stubs/exceptions.pyi | 47 +- rest_framework-stubs/fields.pyi | 459 +++++++++--------- rest_framework-stubs/filters.pyi | 35 +- rest_framework-stubs/generics.pyi | 27 +- .../management/commands/generateschema.pyi | 2 +- rest_framework-stubs/metadata.pyi | 12 +- rest_framework-stubs/mixins.pyi | 4 +- rest_framework-stubs/negotiation.pyi | 12 +- rest_framework-stubs/pagination.pyi | 155 +++--- rest_framework-stubs/parsers.pyi | 27 +- rest_framework-stubs/permissions.pyi | 17 +- rest_framework-stubs/relations.pyi | 138 +++--- rest_framework-stubs/renderers.pyi | 93 ++-- rest_framework-stubs/request.pyi | 58 ++- rest_framework-stubs/response.pyi | 25 +- rest_framework-stubs/reverse.pyi | 23 +- rest_framework-stubs/routers.pyi | 45 +- rest_framework-stubs/schemas/__init__.pyi | 19 +- rest_framework-stubs/schemas/coreapi.pyi | 49 +- rest_framework-stubs/schemas/generators.pyi | 54 +-- rest_framework-stubs/schemas/inspectors.pyi | 8 +- rest_framework-stubs/schemas/openapi.pyi | 57 +-- rest_framework-stubs/schemas/utils.pyi | 4 +- rest_framework-stubs/schemas/views.pyi | 8 +- rest_framework-stubs/serializers.pyi | 159 +++--- rest_framework-stubs/settings.pyi | 131 ++--- .../templatetags/rest_framework.pyi | 20 +- rest_framework-stubs/test.pyi | 57 ++- rest_framework-stubs/throttling.pyi | 29 +- rest_framework-stubs/urlpatterns.pyi | 13 +- rest_framework-stubs/urls.pyi | 4 +- rest_framework-stubs/utils/breadcrumbs.pyi | 4 +- rest_framework-stubs/utils/field_mapping.pyi | 17 +- rest_framework-stubs/utils/formatting.pyi | 9 +- rest_framework-stubs/utils/html.pyi | 4 +- rest_framework-stubs/utils/mediatypes.pyi | 2 +- rest_framework-stubs/utils/model_meta.pyi | 20 +- rest_framework-stubs/utils/representation.pyi | 4 +- .../utils/serializer_helpers.pyi | 15 +- rest_framework-stubs/validators.pyi | 32 +- rest_framework-stubs/versioning.pyi | 32 +- rest_framework-stubs/views.pyi | 81 ++-- rest_framework-stubs/viewsets.pyi | 22 +- scripts/typecheck_tests.py | 2 +- setup.cfg | 11 +- 56 files changed, 1073 insertions(+), 1123 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 06496c511..747ee0c51 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -27,6 +27,10 @@ repos: rev: 5.0.4 hooks: - id: flake8 + additional_dependencies: + - flake8-pyi==22.10.0 + types: [] + files: ^.*.pyi?$ - repo: local hooks: - id: mypy diff --git a/rest_framework-stubs/authentication.pyi b/rest_framework-stubs/authentication.pyi index dc16e94ff..3b6ae1e1b 100644 --- a/rest_framework-stubs/authentication.pyi +++ b/rest_framework-stubs/authentication.pyi @@ -1,4 +1,4 @@ -from typing import Any, Optional, Tuple, Type +from typing import Any from django.contrib.auth import authenticate as authenticate from django.db.models import Model @@ -10,23 +10,23 @@ def get_authorization_header(request: Request) -> bytes: ... class CSRFCheck(CsrfViewMiddleware): ... class BaseAuthentication: - def authenticate(self, request: Request) -> Optional[Tuple[Any, Any]]: ... - def authenticate_header(self, request: Request) -> Optional[str]: ... + def authenticate(self, request: Request) -> tuple[Any, Any] | None: ... # noqa: F811 + def authenticate_header(self, request: Request) -> str | None: ... class BasicAuthentication(BaseAuthentication): - www_authenticate_realm: str = ... + www_authenticate_realm: str def authenticate_credentials( - self, userid: str, password: str, request: Optional[Request] = ... - ) -> Tuple[Any, None]: ... + self, userid: str, password: str, request: Request | None = ... + ) -> tuple[Any, None]: ... class SessionAuthentication(BaseAuthentication): def enforce_csrf(self, request: Request) -> None: ... class TokenAuthentication(BaseAuthentication): - keyword: str = ... - model: Optional[Type[Model]] = ... - def get_model(self) -> Type[Model]: ... - def authenticate_credentials(self, key: str) -> Tuple[Any, Any]: ... + keyword: str + model: type[Model] | None + def get_model(self) -> type[Model]: ... + def authenticate_credentials(self, key: str) -> tuple[Any, Any]: ... class RemoteUserAuthentication(BaseAuthentication): - header: str = ... + header: str diff --git a/rest_framework-stubs/authtoken/__init__.pyi b/rest_framework-stubs/authtoken/__init__.pyi index ca4d6e939..99a607422 100644 --- a/rest_framework-stubs/authtoken/__init__.pyi +++ b/rest_framework-stubs/authtoken/__init__.pyi @@ -1 +1 @@ -default_app_config: str = ... +default_app_config: str diff --git a/rest_framework-stubs/authtoken/management/commands/drf_create_token.pyi b/rest_framework-stubs/authtoken/management/commands/drf_create_token.pyi index efdc1f3d7..0b1e541ee 100644 --- a/rest_framework-stubs/authtoken/management/commands/drf_create_token.pyi +++ b/rest_framework-stubs/authtoken/management/commands/drf_create_token.pyi @@ -6,7 +6,7 @@ from django.core.management.base import BaseCommand UserModel: AbstractBaseUser class Command(BaseCommand): - help: str = ... + help: str def create_user_token(self, username: str, reset_token: bool): ... def add_arguments(self, parser: Any) -> None: ... def handle(self, *args: Any, **options: Any) -> None: ... diff --git a/rest_framework-stubs/authtoken/models.pyi b/rest_framework-stubs/authtoken/models.pyi index f4fca2b67..c333ee837 100644 --- a/rest_framework-stubs/authtoken/models.pyi +++ b/rest_framework-stubs/authtoken/models.pyi @@ -3,9 +3,9 @@ from typing import Any from django.db import models class Token(models.Model): - key: models.CharField = ... - user: models.OneToOneField = ... - created: models.DateTimeField = ... + key: models.CharField + user: models.OneToOneField + created: models.DateTimeField @classmethod def generate_key(cls) -> str: ... diff --git a/rest_framework-stubs/authtoken/serializers.pyi b/rest_framework-stubs/authtoken/serializers.pyi index 7137425f6..c17157ac4 100644 --- a/rest_framework-stubs/authtoken/serializers.pyi +++ b/rest_framework-stubs/authtoken/serializers.pyi @@ -1,6 +1,6 @@ from rest_framework import serializers class AuthTokenSerializer(serializers.Serializer): - username: serializers.CharField = ... - password: serializers.CharField = ... - token: serializers.CharField = ... + username: serializers.CharField + password: serializers.CharField + token: serializers.CharField diff --git a/rest_framework-stubs/authtoken/views.pyi b/rest_framework-stubs/authtoken/views.pyi index ef301c727..2fc0fc6e6 100644 --- a/rest_framework-stubs/authtoken/views.pyi +++ b/rest_framework-stubs/authtoken/views.pyi @@ -1,4 +1,4 @@ -from typing import Any, Type +from typing import Any from rest_framework.request import Request from rest_framework.response import Response @@ -6,7 +6,7 @@ from rest_framework.serializers import Serializer from rest_framework.views import APIView, AsView, GenericView class ObtainAuthToken(APIView): - serializer_class: Type[Serializer] = ... + serializer_class: type[Serializer] def post(self, request: Request, *args: Any, **kwargs: Any) -> Response: ... -obtain_auth_token: AsView[GenericView] = ... +obtain_auth_token: AsView[GenericView] diff --git a/rest_framework-stubs/checks.pyi b/rest_framework-stubs/checks.pyi index 1d0347f0e..ba4d48fe0 100644 --- a/rest_framework-stubs/checks.pyi +++ b/rest_framework-stubs/checks.pyi @@ -1,3 +1,3 @@ -from typing import Any, List +from typing import Any -def pagination_system_check(app_configs: Any, **kwargs: Any) -> List[Any]: ... +def pagination_system_check(app_configs: Any, **kwargs: Any) -> list[Any]: ... diff --git a/rest_framework-stubs/compat.pyi b/rest_framework-stubs/compat.pyi index 1680cb5b8..cf9b99a35 100644 --- a/rest_framework-stubs/compat.pyi +++ b/rest_framework-stubs/compat.pyi @@ -1,4 +1,4 @@ -from typing import Any, Optional, Tuple, Union +from typing import Any import requests # noqa: F401 from django.db.models import QuerySet @@ -43,19 +43,19 @@ if markdown is not None and pygments is not None: from markdown.preprocessors import Preprocessor # type: ignore class CodeBlockPreprocessor(Preprocessor): - pattern: Any = ... - formatter: Any = ... + pattern: Any + formatter: Any def run(self, lines: Any): ... -def pygments_css(style: Any) -> Optional[str]: ... +def pygments_css(style: Any) -> str | None: ... def pygments_highlight(text: str, lang: str, style: Any) -> Any: ... def md_filter_add_syntax_highlight(md: Any) -> bool: ... -def unicode_http_header(value: Union[str, bytes]) -> str: ... -def distinct(queryset: QuerySet, base: Optional[QuerySet]) -> QuerySet: ... +def unicode_http_header(value: str | bytes) -> str: ... +def distinct(queryset: QuerySet, base: QuerySet | None) -> QuerySet: ... -SHORT_SEPARATORS: Tuple[str, str] -LONG_SEPARATORS: Tuple[str, str] -INDENT_SEPARATORS: Tuple[str, str] +SHORT_SEPARATORS: tuple[str, str] +LONG_SEPARATORS: tuple[str, str] +INDENT_SEPARATORS: tuple[str, str] __all__ = [ "coreapi", diff --git a/rest_framework-stubs/decorators.pyi b/rest_framework-stubs/decorators.pyi index a301826ea..a1d5288a3 100644 --- a/rest_framework-stubs/decorators.pyi +++ b/rest_framework-stubs/decorators.pyi @@ -1,4 +1,5 @@ -from typing import Any, Callable, List, Mapping, Optional, Protocol, Sequence, Type, TypeVar, Union +from collections.abc import Callable, Mapping, Sequence +from typing import Any, Protocol, TypeVar from django.http import HttpRequest from django.http.response import HttpResponseBase @@ -10,7 +11,7 @@ from rest_framework.request import Request from rest_framework.schemas.inspectors import ViewInspector from rest_framework.throttling import BaseThrottle from rest_framework.views import APIView, AsView # noqa: F401 -from typing_extensions import Concatenate, Literal, ParamSpec +from typing_extensions import Concatenate, Literal, ParamSpec, TypeAlias _View = TypeVar("_View", bound=Callable[..., HttpResponseBase]) _P = ParamSpec("_P") @@ -28,7 +29,7 @@ class MethodMapper(dict): def options(self, func: _View) -> _View: ... def trace(self, func: _View) -> _View: ... -_LOWER_CASE_HTTP_VERBS = List[ +_LOWER_CASE_HTTP_VERBS: TypeAlias = list[ Literal[ "get", "post", @@ -40,7 +41,7 @@ _LOWER_CASE_HTTP_VERBS = List[ ] ] -_MIXED_CASE_HTTP_VERBS = List[ +_MIXED_CASE_HTTP_VERBS: TypeAlias = list[ Literal[ "GET", "POST", @@ -71,26 +72,22 @@ class ViewSetAction(Protocol[_View]): __call__: _View def api_view( - http_method_names: Optional[Sequence[str]] = ..., + http_method_names: Sequence[str] | None = ..., ) -> Callable[[Callable[Concatenate[Request, _P], _RESP]], AsView[Callable[Concatenate[HttpRequest, _P], _RESP]]]: ... -def renderer_classes( - renderer_classes: Sequence[Union[BaseRenderer, Type[BaseRenderer]]] -) -> Callable[[_View], _View]: ... -def parser_classes(parser_classes: Sequence[Union[BaseParser, Type[BaseParser]]]) -> Callable[[_View], _View]: ... +def renderer_classes(renderer_classes: Sequence[BaseRenderer | type[BaseRenderer]]) -> Callable[[_View], _View]: ... +def parser_classes(parser_classes: Sequence[BaseParser | type[BaseParser]]) -> Callable[[_View], _View]: ... def authentication_classes( - authentication_classes: Sequence[Union[BaseAuthentication, Type[BaseAuthentication]]] -) -> Callable[[_View], _View]: ... -def throttle_classes( - throttle_classes: Sequence[Union[BaseThrottle, Type[BaseThrottle]]] + authentication_classes: Sequence[BaseAuthentication | type[BaseAuthentication]], ) -> Callable[[_View], _View]: ... +def throttle_classes(throttle_classes: Sequence[BaseThrottle | type[BaseThrottle]]) -> Callable[[_View], _View]: ... def permission_classes(permission_classes: Sequence[_PermissionClass]) -> Callable[[_View], _View]: ... -def schema(view_inspector: Optional[Union[ViewInspector, Type[ViewInspector]]]) -> Callable[[_View], _View]: ... +def schema(view_inspector: ViewInspector | type[ViewInspector] | None) -> Callable[[_View], _View]: ... def action( - methods: Optional[_MIXED_CASE_HTTP_VERBS] = ..., + methods: _MIXED_CASE_HTTP_VERBS | None = ..., detail: bool = ..., - url_path: Optional[str] = ..., - url_name: Optional[str] = ..., - suffix: Optional[str] = ..., - name: Optional[str] = ..., + url_path: str | None = ..., + url_name: str | None = ..., + suffix: str | None = ..., + name: str | None = ..., **kwargs: Any, ) -> Callable[[_View], ViewSetAction[_View]]: ... diff --git a/rest_framework-stubs/documentation.pyi b/rest_framework-stubs/documentation.pyi index 7f857968f..5f716bddb 100644 --- a/rest_framework-stubs/documentation.pyi +++ b/rest_framework-stubs/documentation.pyi @@ -1,42 +1,43 @@ -from typing import Any, Callable, Optional, Sequence, Type +from collections.abc import Callable, Sequence +from typing import Any from rest_framework.renderers import BaseRenderer from rest_framework.schemas import SchemaGenerator from rest_framework.urlpatterns import _AnyURL def get_docs_view( - title: Optional[str] = ..., - url: Optional[str] = ..., - description: Optional[str] = ..., - urlconf: Optional[str] = ..., - renderer_classes: Optional[Sequence[Type[BaseRenderer]]] = ..., + title: str | None = ..., + url: str | None = ..., + description: str | None = ..., + urlconf: str | None = ..., + renderer_classes: Sequence[type[BaseRenderer]] | None = ..., public: bool = ..., - patterns: Optional[Sequence[_AnyURL]] = ..., - generator_class: Type[SchemaGenerator] = ..., + patterns: Sequence[_AnyURL] | None = ..., + generator_class: type[SchemaGenerator] = ..., authentication_classes: Sequence[str] = ..., permission_classes: Sequence[str] = ..., ) -> Callable[..., Any]: ... def get_schemajs_view( - title: Optional[str] = ..., - url: Optional[str] = ..., - description: Optional[str] = ..., - urlconf: Optional[str] = ..., - renderer_classes: Optional[Sequence[Type[BaseRenderer]]] = ..., + title: str | None = ..., + url: str | None = ..., + description: str | None = ..., + urlconf: str | None = ..., + renderer_classes: Sequence[type[BaseRenderer]] | None = ..., public: bool = ..., - patterns: Optional[Sequence[_AnyURL]] = ..., - generator_class: Type[SchemaGenerator] = ..., + patterns: Sequence[_AnyURL] | None = ..., + generator_class: type[SchemaGenerator] = ..., authentication_classes: Sequence[str] = ..., permission_classes: Sequence[str] = ..., ) -> Callable[..., Any]: ... def include_docs_urls( - title: Optional[str] = ..., - url: Optional[str] = ..., - description: Optional[str] = ..., - urlconf: Optional[str] = ..., - renderer_classes: Optional[Sequence[Type[BaseRenderer]]] = ..., + title: str | None = ..., + url: str | None = ..., + description: str | None = ..., + urlconf: str | None = ..., + renderer_classes: Sequence[type[BaseRenderer]] | None = ..., public: bool = ..., - patterns: Optional[Sequence[_AnyURL]] = ..., - generator_class: Type[SchemaGenerator] = ..., + patterns: Sequence[_AnyURL] | None = ..., + generator_class: type[SchemaGenerator] = ..., authentication_classes: Sequence[str] = ..., permission_classes: Sequence[str] = ..., ) -> Any: ... diff --git a/rest_framework-stubs/exceptions.pyi b/rest_framework-stubs/exceptions.pyi index 9290da06e..7dcaf8f57 100644 --- a/rest_framework-stubs/exceptions.pyi +++ b/rest_framework-stubs/exceptions.pyi @@ -1,26 +1,29 @@ -from typing import Any, Dict, List, Optional, Sequence, Union +from collections.abc import Sequence +from typing import Any + +from typing_extensions import TypeAlias from django.http import HttpRequest, JsonResponse from rest_framework.renderers import BaseRenderer from rest_framework.request import Request -def _get_error_details(data: Any, default_code: Optional[str] = ...) -> Any: ... +def _get_error_details(data: Any, default_code: str | None = ...) -> Any: ... def _get_codes(detail: Any) -> Any: ... def _get_full_details(detail: Any) -> Any: ... class ErrorDetail(str): - code: Optional[str] = None - def __new__(cls, string: str, code: Optional[str] = ...): ... + code: str | None + def __new__(cls, string: str, code: str | None = ...): ... -_Detail = Union[str, List[Any], Dict[str, Any]] +_Detail: TypeAlias = str | list[Any] | dict[str, Any] class APIException(Exception): - status_code: int = ... - default_detail: _Detail = ... - default_code: str = ... + status_code: int + default_detail: _Detail + default_code: str detail: _Detail - def __init__(self, detail: Optional[_Detail] = ..., code: Optional[str] = ...) -> None: ... + def __init__(self, detail: _Detail | None = ..., code: str | None = ...) -> None: ... def get_codes(self) -> Any: ... def get_full_details(self) -> Any: ... @@ -32,26 +35,24 @@ class PermissionDenied(APIException): ... class NotFound(APIException): ... class MethodNotAllowed(APIException): - def __init__(self, method: str, detail: Optional[_Detail] = ..., code: Optional[str] = ...) -> None: ... + def __init__(self, method: str, detail: _Detail | None = ..., code: str | None = ...) -> None: ... class NotAcceptable(APIException): - available_renderers: Optional[Sequence[BaseRenderer]] + available_renderers: Sequence[BaseRenderer] | None def __init__( self, - detail: Optional[_Detail] = ..., - code: Optional[str] = ..., - available_renderers: Optional[Sequence[BaseRenderer]] = ..., + detail: _Detail | None = ..., + code: str | None = ..., + available_renderers: Sequence[BaseRenderer] | None = ..., ) -> None: ... class UnsupportedMediaType(APIException): - def __init__(self, media_type: str, detail: Optional[_Detail] = ..., code: Optional[str] = ...) -> None: ... + def __init__(self, media_type: str, detail: _Detail | None = ..., code: str | None = ...) -> None: ... class Throttled(APIException): - extra_detail_singular: str = ... - extra_detail_plural: str = ... - def __init__(self, wait: Optional[float] = ..., detail: Optional[_Detail] = ..., code: Optional[str] = ...): ... - -def server_error(request: Union[HttpRequest, Request], *args: Any, **kwargs: Any) -> JsonResponse: ... -def bad_request( - request: Union[HttpRequest, Request], exception: Exception, *args: Any, **kwargs: Any -) -> JsonResponse: ... + extra_detail_singular: str + extra_detail_plural: str + def __init__(self, wait: float | None = ..., detail: _Detail | None = ..., code: str | None = ...): ... + +def server_error(request: HttpRequest | Request, *args: Any, **kwargs: Any) -> JsonResponse: ... +def bad_request(request: HttpRequest | Request, exception: Exception, *args: Any, **kwargs: Any) -> JsonResponse: ... diff --git a/rest_framework-stubs/fields.pyi b/rest_framework-stubs/fields.pyi index 9c3c0ae80..1da8f37ff 100644 --- a/rest_framework-stubs/fields.pyi +++ b/rest_framework-stubs/fields.pyi @@ -4,69 +4,52 @@ from collections import OrderedDict from decimal import Decimal from enum import Enum from json import JSONDecoder, JSONEncoder -from typing import ( - Any, - Callable, - Dict, - Generator, - Generic, - Iterable, - List, - Mapping, - MutableMapping, - NoReturn, - Optional, - Pattern, - Protocol, - Sequence, - Set, - Tuple, - Type, - TypeVar, - Union, -) +from collections.abc import Callable, Generator, Iterable, Mapping, MutableMapping, Sequence +from re import Pattern +from typing import Any, Generic, NoReturn, Protocol, TypeVar +from _typeshed import Self from django.core.files.base import File from django.db import models from django.forms import ImageField as DjangoImageField # noqa: F401 -from typing_extensions import Final +from typing_extensions import Final, TypeAlias from rest_framework.serializers import BaseSerializer from rest_framework.validators import Validator class _Empty(Enum): - sentinel = 0 + sentinel = 0 # noqa: Y015 empty: Final = _Empty.sentinel class BuiltinSignatureError(Exception): ... class CreateOnlyDefault: - requires_context: bool = ... - default: Any = ... + requires_context: bool + default: Any def __init__(self, default: Any) -> None: ... def __call__(self, serializer_field: Field): ... class CurrentUserDefault: - requires_context: bool = ... + requires_context: bool def __call__(self, serializer_field: Field): ... class SkipField(Exception): ... class Option(Protocol): - start_option_group: bool = ... - end_option_group: bool = ... + start_option_group: bool + end_option_group: bool label: str value: str display_text: str def is_simple_callable(obj: Callable) -> bool: ... -def get_attribute(instance: Any, attrs: Optional[List[str]]) -> Any: ... +def get_attribute(instance: Any, attrs: list[str] | None) -> Any: ... def set_value(dictionary: MutableMapping[str, Any], keys: Sequence[str], value: Any) -> None: ... def to_choices_dict(choices: Iterable[Any]) -> OrderedDict: ... -def flatten_choices_dict(choices: Dict[Any, Any]) -> OrderedDict: ... +def flatten_choices_dict(choices: dict[Any, Any]) -> OrderedDict: ... def iter_options( - grouped_choices: OrderedDict, cutoff: Optional[int] = ..., cutoff_text: Optional[str] = ... + grouped_choices: OrderedDict, cutoff: int | None = ..., cutoff_text: str | None = ... ) -> Generator[Option, None, None]: ... def get_error_detail(exc_info: Any) -> Any: ... @@ -85,25 +68,25 @@ _RP = TypeVar("_RP") # Representation Type class SupportsToPython(Protocol): def to_python(self, value: Any) -> Any: ... -_DefaultInitial = Union[_VT, Callable[[], _VT], None, _Empty] +_DefaultInitial: TypeAlias = _VT | Callable[[], _VT] | None | _Empty class Field(Generic[_VT, _DT, _RP, _IN]): - allow_null: bool = ... - default: Optional[_VT] = ... - default_empty_html: Any = ... - default_error_messages: Dict[str, str] = ... - default_validators: List[Validator[_VT]] = ... - error_messages: Dict[str, str] = ... - field_name: Optional[str] = ... - help_text: Optional[str] = ... - initial: Optional[Union[_VT, Callable[[], _VT]]] = ... - label: Optional[str] + allow_null: bool + default: _VT | None + default_empty_html: Any + default_error_messages: dict[str, str] + default_validators: list[Validator[_VT]] + error_messages: dict[str, str] + field_name: str | None + help_text: str | None + initial: _VT | Callable[[], _VT] | None + label: str | None parent: BaseSerializer read_only: bool required: bool - source: Optional[Union[Callable, str]] - source_attrs: List[str] = ... - style: Dict[str, Any] + source: Callable | str | None + source_attrs: list[str] + style: dict[str, Any] write_only: bool def __init__( self, @@ -115,22 +98,22 @@ class Field(Generic[_VT, _DT, _RP, _IN]): source: str = ..., label: str = ..., help_text: str = ..., - style: Dict[str, Any] = ..., - error_messages: Dict[str, str] = ..., - validators: Optional[Sequence[Validator[_VT]]] = ..., + style: dict[str, Any] = ..., + error_messages: dict[str, str] = ..., + validators: Sequence[Validator[_VT]] | None = ..., allow_null: bool = ..., ): ... def bind(self, field_name: str, parent: BaseSerializer) -> None: ... @property - def validators(self) -> List[Validator[_VT]]: ... + def validators(self) -> list[Validator[_VT]]: ... @validators.setter - def validators(self, validators: List[Validator[_VT]]) -> None: ... - def get_validators(self) -> List[Validator[_VT]]: ... - def get_initial(self) -> Optional[_VT]: ... + def validators(self, validators: list[Validator[_VT]]) -> None: ... + def get_validators(self) -> list[Validator[_VT]]: ... + def get_initial(self) -> _VT | None: ... def get_value(self, dictionary: Mapping[Any, Any]) -> Any: ... - def get_attribute(self, instance: _IN) -> Optional[_RP]: ... - def get_default(self) -> Optional[_VT]: ... - def validate_empty_values(self, data: Any) -> Tuple[bool, Any]: ... + def get_attribute(self, instance: _IN) -> _RP | None: ... + def get_default(self) -> _VT | None: ... + def validate_empty_values(self, data: Any) -> tuple[bool, Any]: ... def run_validation(self, data: Any = ...) -> Any: ... def run_validators(self, value: Any) -> None: ... def to_internal_value(self, data: _DT) -> _VT: ... @@ -139,39 +122,39 @@ class Field(Generic[_VT, _DT, _RP, _IN]): @property def root(self) -> BaseSerializer: ... @property - def context(self) -> Dict[str, Any]: ... - def __new__(cls, *args: Any, **kwargs: Any) -> Field: ... + def context(self) -> dict[str, Any]: ... + def __new__(cls: type[Self], *args: Any, **kwargs: Any) -> Self: ... def __deepcopy__(self, memo: Mapping[Any, Any]) -> Field: ... class BooleanField( Field[ bool, - Union[str, bool, int], + str | bool | int, bool, Any, ] ): - TRUE_VALUES: Set[Union[str, bool, int]] = ... - FALSE_VALUES: Set[Union[str, bool, int, float]] = ... - NULL_VALUES: Set[Union[str, None]] = ... + TRUE_VALUES: set[str | bool | int] + FALSE_VALUES: set[str | bool | int | float] + NULL_VALUES: set[str | None] class NullBooleanField( Field[ - Union[bool, None], - Optional[Union[str, bool, int]], + bool | None, + str | bool | int | None, bool, Any, ] ): - TRUE_VALUES: Set[Union[str, bool, int]] = ... - FALSE_VALUES: Set[Union[str, bool, int, float]] = ... - NULL_VALUES: Set[Union[str, None]] = ... + TRUE_VALUES: set[str | bool | int] + FALSE_VALUES: set[str | bool | int | float] + NULL_VALUES: set[str | None] class CharField(Field[str, str, str, Any]): - allow_blank: bool = ... - trim_whitespace: bool = ... - max_length: Optional[int] = ... - min_length: Optional[int] = ... + allow_blank: bool + trim_whitespace: bool + max_length: int | None + min_length: int | None def __init__( self, *, @@ -183,14 +166,14 @@ class CharField(Field[str, str, str, Any]): source: str = ..., label: str = ..., help_text: str = ..., - style: Dict[str, Any] = ..., - error_messages: Dict[str, str] = ..., - validators: Optional[Sequence[Validator[str]]] = ..., + style: dict[str, Any] = ..., + error_messages: dict[str, str] = ..., + validators: Sequence[Validator[str]] | None = ..., allow_null: bool = ..., allow_blank: bool = ..., trim_whitespace: bool = ..., max_length: int = ..., - min_length: Optional[int] = ..., + min_length: int | None = ..., ): ... class EmailField(CharField): ... @@ -198,7 +181,7 @@ class EmailField(CharField): ... class RegexField(CharField): def __init__( self, - regex: Union[str, Pattern], + regex: str | Pattern, *, read_only: bool = ..., write_only: bool = ..., @@ -208,18 +191,18 @@ class RegexField(CharField): source: str = ..., label: str = ..., help_text: str = ..., - style: Dict[str, Any] = ..., - error_messages: Dict[str, str] = ..., - validators: Optional[Sequence[Validator[str]]] = ..., + style: dict[str, Any] = ..., + error_messages: dict[str, str] = ..., + validators: Sequence[Validator[str]] | None = ..., allow_null: bool = ..., allow_blank: bool = ..., trim_whitespace: bool = ..., max_length: int = ..., - min_length: Optional[int] = ..., + min_length: int | None = ..., ): ... class SlugField(CharField): - allow_unicode: bool = ... + allow_unicode: bool def __init__( self, allow_unicode: bool = ..., @@ -232,25 +215,25 @@ class SlugField(CharField): source: str = ..., label: str = ..., help_text: str = ..., - style: Dict[str, Any] = ..., - error_messages: Dict[str, str] = ..., - validators: Optional[Sequence[Validator[str]]] = ..., + style: dict[str, Any] = ..., + error_messages: dict[str, str] = ..., + validators: Sequence[Validator[str]] | None = ..., allow_null: bool = ..., allow_blank: bool = ..., trim_whitespace: bool = ..., max_length: int = ..., - min_length: Optional[int] = ..., + min_length: int | None = ..., ): ... class URLField(CharField): ... -class UUIDField(Field[uuid.UUID, Union[uuid.UUID, str, int], str, Any]): - valid_formats: Sequence[str] = ... +class UUIDField(Field[uuid.UUID, uuid.UUID | str | int, str, Any]): + valid_formats: Sequence[str] uuid_format: str def __init__( self, *, - format: Optional[str] = ..., + format: str | None = ..., read_only: bool = ..., write_only: bool = ..., required: bool = ..., @@ -259,9 +242,9 @@ class UUIDField(Field[uuid.UUID, Union[uuid.UUID, str, int], str, Any]): source: str = ..., label: str = ..., help_text: str = ..., - style: Dict[str, Any] = ..., - error_messages: Dict[str, str] = ..., - validators: Optional[Sequence[Validator[uuid.UUID]]] = ..., + style: dict[str, Any] = ..., + error_messages: dict[str, str] = ..., + validators: Sequence[Validator[uuid.UUID]] | None = ..., allow_null: bool = ..., ): ... @@ -280,21 +263,21 @@ class IPAddressField(CharField): source: str = ..., label: str = ..., help_text: str = ..., - style: Dict[str, Any] = ..., - error_messages: Dict[str, str] = ..., - validators: Optional[Sequence[Validator[str]]] = ..., + style: dict[str, Any] = ..., + error_messages: dict[str, str] = ..., + validators: Sequence[Validator[str]] | None = ..., allow_null: bool = ..., allow_blank: bool = ..., trim_whitespace: bool = ..., max_length: int = ..., - min_length: Optional[int] = ..., + min_length: int | None = ..., ): ... -class IntegerField(Field[int, Union[float, int, str], int, Any]): - MAX_STRING_LENGTH: int = ... - re_decimal: Pattern = ... - max_value: Optional[int] = ... - min_value: Optional[int] = ... +class IntegerField(Field[int, float | int | str, int, Any]): + MAX_STRING_LENGTH: int + re_decimal: Pattern + max_value: int | None + min_value: int | None def __init__( self, *, @@ -308,17 +291,17 @@ class IntegerField(Field[int, Union[float, int, str], int, Any]): source: str = ..., label: str = ..., help_text: str = ..., - style: Dict[str, Any] = ..., - error_messages: Dict[str, str] = ..., - validators: Optional[Sequence[Validator[int]]] = ..., + style: dict[str, Any] = ..., + error_messages: dict[str, str] = ..., + validators: Sequence[Validator[int]] | None = ..., allow_null: bool = ..., ): ... -class FloatField(Field[float, Union[float, int, str], str, Any]): - MAX_STRING_LENGTH: int = ... - re_decimal: Pattern = ... - max_value: Optional[float] = ... - min_value: Optional[float] = ... +class FloatField(Field[float, float | int | str, str, Any]): + MAX_STRING_LENGTH: int + re_decimal: Pattern + max_value: float | None + min_value: float | None def __init__( self, *, @@ -332,31 +315,31 @@ class FloatField(Field[float, Union[float, int, str], str, Any]): source: str = ..., label: str = ..., help_text: str = ..., - style: Dict[str, Any] = ..., - error_messages: Dict[str, str] = ..., - validators: Optional[Sequence[Validator[float]]] = ..., + style: dict[str, Any] = ..., + error_messages: dict[str, str] = ..., + validators: Sequence[Validator[float]] | None = ..., allow_null: bool = ..., ): ... -class DecimalField(Field[Decimal, Union[int, float, str, Decimal], str, Any]): - MAX_STRING_LENGTH: int = ... - max_digits: Optional[int] - decimal_places: Optional[int] - coerce_to_string: Optional[bool] - max_value: Optional[Union[Decimal, int, float]] - min_value: Optional[Union[Decimal, int, float]] +class DecimalField(Field[Decimal, int | float | str | Decimal, str, Any]): + MAX_STRING_LENGTH: int + max_digits: int | None + decimal_places: int | None + coerce_to_string: bool | None + max_value: Decimal | int | float | None + min_value: Decimal | int | float | None localize: bool - rounding: Optional[str] - max_whole_digits = Optional[int] + rounding: str | None + max_whole_digits = int | None # noqa: Y026 def __init__( self, - max_digits: Optional[int], - decimal_places: Optional[int], + max_digits: int | None, + decimal_places: int | None, coerce_to_string: bool = ..., - max_value: Union[Decimal, int, float] = ..., - min_value: Union[Decimal, int, float] = ..., + max_value: Decimal | int | float = ..., + min_value: Decimal | int | float = ..., localize: bool = ..., - rounding: Optional[str] = ..., + rounding: str | None = ..., *, read_only: bool = ..., write_only: bool = ..., @@ -366,24 +349,24 @@ class DecimalField(Field[Decimal, Union[int, float, str, Decimal], str, Any]): source: str = ..., label: str = ..., help_text: str = ..., - style: Dict[str, Any] = ..., - error_messages: Dict[str, str] = ..., - validators: Optional[Sequence[Validator[Decimal]]] = ..., + style: dict[str, Any] = ..., + error_messages: dict[str, str] = ..., + validators: Sequence[Validator[Decimal]] | None = ..., allow_null: bool = ..., ): ... def validate_precision(self, value: Decimal) -> Decimal: ... def quantize(self, value: Decimal) -> Decimal: ... -class DateTimeField(Field[datetime.datetime, Union[datetime.datetime, str], str, Any]): - datetime_parser: Callable[[str, str], datetime.datetime] = ... - format: Optional[str] = ... - input_formats: Sequence[str] = ... - timezone: datetime.tzinfo = ... +class DateTimeField(Field[datetime.datetime, datetime.datetime | str, str, Any]): + datetime_parser: Callable[[str, str], datetime.datetime] + format: str | None + input_formats: Sequence[str] + timezone: datetime.tzinfo def __init__( self, - format: Optional[str] = ..., + format: str | None = ..., input_formats: Sequence[str] = ..., - default_timezone: Optional[datetime.tzinfo] = ..., + default_timezone: datetime.tzinfo | None = ..., read_only: bool = ..., write_only: bool = ..., required: bool = ..., @@ -392,21 +375,21 @@ class DateTimeField(Field[datetime.datetime, Union[datetime.datetime, str], str, source: str = ..., label: str = ..., help_text: str = ..., - style: Dict[str, Any] = ..., - error_messages: Dict[str, str] = ..., - validators: Optional[Sequence[Validator[datetime.datetime]]] = ..., + style: dict[str, Any] = ..., + error_messages: dict[str, str] = ..., + validators: Sequence[Validator[datetime.datetime]] | None = ..., allow_null: bool = ..., ): ... def enforce_timezone(self, value: datetime.datetime) -> datetime.datetime: ... - def default_timezone(self) -> Optional[str]: ... + def default_timezone(self) -> str | None: ... -class DateField(Field[datetime.date, Union[datetime.date, str], str, Any]): - datetime_parser: Callable[[str, str], datetime.datetime] = ... - format: Optional[str] = ... - input_formats: Sequence[str] = ... +class DateField(Field[datetime.date, datetime.date | str, str, Any]): + datetime_parser: Callable[[str, str], datetime.datetime] + format: str | None + input_formats: Sequence[str] def __init__( self, - format: Optional[str] = ..., + format: str | None = ..., input_formats: Sequence[str] = ..., read_only: bool = ..., write_only: bool = ..., @@ -416,19 +399,19 @@ class DateField(Field[datetime.date, Union[datetime.date, str], str, Any]): source: str = ..., label: str = ..., help_text: str = ..., - style: Dict[str, Any] = ..., - error_messages: Dict[str, str] = ..., - validators: Optional[Sequence[Validator[datetime.date]]] = ..., + style: dict[str, Any] = ..., + error_messages: dict[str, str] = ..., + validators: Sequence[Validator[datetime.date]] | None = ..., allow_null: bool = ..., ): ... -class TimeField(Field[datetime.time, Union[datetime.time, str], str, Any]): - datetime_parser: Callable[[str, str], datetime.datetime] = ... - format: Optional[str] = ... - input_formats: Sequence[str] = ... +class TimeField(Field[datetime.time, datetime.time | str, str, Any]): + datetime_parser: Callable[[str, str], datetime.datetime] + format: str | None + input_formats: Sequence[str] def __init__( self, - format: Optional[str] = ..., + format: str | None = ..., input_formats: Sequence[str] = ..., read_only: bool = ..., write_only: bool = ..., @@ -438,20 +421,20 @@ class TimeField(Field[datetime.time, Union[datetime.time, str], str, Any]): source: str = ..., label: str = ..., help_text: str = ..., - style: Dict[str, Any] = ..., - error_messages: Dict[str, str] = ..., - validators: Optional[Sequence[Validator[datetime.time]]] = ..., + style: dict[str, Any] = ..., + error_messages: dict[str, str] = ..., + validators: Sequence[Validator[datetime.time]] | None = ..., allow_null: bool = ..., ): ... -class DurationField(Field[datetime.timedelta, Union[datetime.timedelta, str], str, Any]): - max_value: Optional[datetime.timedelta] = ... - min_value: Optional[datetime.timedelta] = ... +class DurationField(Field[datetime.timedelta, datetime.timedelta | str, str, Any]): + max_value: datetime.timedelta | None + min_value: datetime.timedelta | None def __init__( self, *, - max_value: Union[datetime.timedelta, int, float] = ..., - min_value: Union[datetime.timedelta, int, float] = ..., + max_value: datetime.timedelta | int | float = ..., + min_value: datetime.timedelta | int | float = ..., read_only: bool = ..., write_only: bool = ..., required: bool = ..., @@ -460,19 +443,19 @@ class DurationField(Field[datetime.timedelta, Union[datetime.timedelta, str], st source: str = ..., label: str = ..., help_text: str = ..., - style: Dict[str, Any] = ..., - error_messages: Dict[str, str] = ..., - validators: Optional[Sequence[Validator[datetime.timedelta]]] = ..., + style: dict[str, Any] = ..., + error_messages: dict[str, str] = ..., + validators: Sequence[Validator[datetime.timedelta]] | None = ..., allow_null: bool = ..., ): ... -class ChoiceField(Field[str, Union[str, int, Tuple[Union[str, int], Union[str, int, tuple]]], str, Any]): - html_cutoff: Optional[int] = ... - html_cutoff_text: Optional[str] = ... - allow_blank: bool = ... - grouped_choices: OrderedDict = ... - choice_strings_to_values: Dict[str, Any] = ... - _choices: OrderedDict = ... +class ChoiceField(Field[str, str | int | tuple[str | int, str | int | tuple], str, Any]): + html_cutoff: int | None + html_cutoff_text: str | None + allow_blank: bool + grouped_choices: OrderedDict + choice_strings_to_values: dict[str, Any] + _choices: OrderedDict def __init__( self, choices: Iterable[Any], @@ -480,21 +463,21 @@ class ChoiceField(Field[str, Union[str, int, Tuple[Union[str, int], Union[str, i read_only: bool = ..., write_only: bool = ..., required: bool = ..., - default: _DefaultInitial[Union[str, int]] = ..., - initial: _DefaultInitial[Union[str, int]] = ..., + default: _DefaultInitial[str | int] = ..., + initial: _DefaultInitial[str | int] = ..., source: str = ..., label: str = ..., help_text: str = ..., - style: Dict[str, Any] = ..., - error_messages: Dict[str, str] = ..., - validators: Optional[Sequence[Validator[Any]]] = ..., + style: dict[str, Any] = ..., + error_messages: dict[str, str] = ..., + validators: Sequence[Validator[Any]] | None = ..., allow_null: bool = ..., html_cutoff: int = ..., html_cutoff_text: str = ..., allow_blank: bool = ..., ): ... def iter_options(self) -> Iterable[Option]: ... - def _get_choices(self) -> Dict[Any, Any]: ... + def _get_choices(self) -> dict[Any, Any]: ... def _set_choices(self, choices: Iterable[Any]) -> None: ... choices = property(_get_choices, _set_choices) @@ -502,26 +485,26 @@ class MultipleChoiceField( ChoiceField, Field[ str, - Sequence[Union[str, int, Tuple[Union[str, int], Union[str, int]]]], - Sequence[Union[str, Tuple[Union[str, int], Union[str, int]]]], + Sequence[str | int | tuple[str | int, str | int]], + Sequence[str | tuple[str | int, str | int]], Any, ], ): - allow_empty: bool = ... + allow_empty: bool def __init__( self, choices: Iterable[Any], read_only: bool = ..., write_only: bool = ..., required: bool = ..., - default: _DefaultInitial[Union[Set[Union[str, int]], Set[str], Set[int]]] = ..., - initial: _DefaultInitial[Union[Set[Union[str, int]], Set[str], Set[int]]] = ..., + default: _DefaultInitial[set[str | int] | set[str] | set[int]] = ..., + initial: _DefaultInitial[set[str | int] | set[str] | set[int]] = ..., source: str = ..., label: str = ..., help_text: str = ..., - style: Dict[str, Any] = ..., - error_messages: Dict[str, str] = ..., - validators: Optional[Sequence[Validator[Any]]] = ..., + style: dict[str, Any] = ..., + error_messages: dict[str, str] = ..., + validators: Sequence[Validator[Any]] | None = ..., allow_null: bool = ..., html_cutoff: int = ..., html_cutoff_text: str = ..., @@ -545,19 +528,19 @@ class FilePathField(ChoiceField): source: str = ..., label: str = ..., help_text: str = ..., - style: Dict[str, Any] = ..., - error_messages: Dict[str, str] = ..., - validators: Optional[Sequence[Validator[Any]]] = ..., + style: dict[str, Any] = ..., + error_messages: dict[str, str] = ..., + validators: Sequence[Validator[Any]] | None = ..., allow_null: bool = ..., html_cutoff: int = ..., html_cutoff_text: str = ..., allow_blank: bool = ..., ): ... -class FileField(Field[File, File, Union[str, None], Any]): # this field can return None without raising! - max_length: int = ... - allow_empty_file: bool = ... - use_url: bool = ... +class FileField(Field[File, File, str | None, Any]): # this field can return None without raising! + max_length: int + allow_empty_file: bool + use_url: bool def __init__( self, *, @@ -569,9 +552,9 @@ class FileField(Field[File, File, Union[str, None], Any]): # this field can ret source: str = ..., label: str = ..., help_text: str = ..., - style: Dict[str, Any] = ..., - error_messages: Dict[str, str] = ..., - validators: Optional[Sequence[Validator[File]]] = ..., + style: dict[str, Any] = ..., + error_messages: dict[str, str] = ..., + validators: Sequence[Validator[File]] | None = ..., allow_null: bool = ..., max_length: int = ..., allow_empty_file: bool = ..., @@ -579,7 +562,7 @@ class FileField(Field[File, File, Union[str, None], Any]): # this field can ret ): ... class ImageField(FileField): - _DjangoImageField: SupportsToPython = ... + _DjangoImageField: SupportsToPython def __init__( self, *, @@ -591,36 +574,36 @@ class ImageField(FileField): source: str = ..., label: str = ..., help_text: str = ..., - style: Dict[str, Any] = ..., - error_messages: Dict[str, str] = ..., - validators: Optional[Sequence[Validator[File]]] = ..., + style: dict[str, Any] = ..., + error_messages: dict[str, str] = ..., + validators: Sequence[Validator[File]] | None = ..., allow_null: bool = ..., max_length: int = ..., allow_empty_file: bool = ..., use_url: bool = ..., - _DjangoImageField: Type[SupportsToPython] = ..., + _DjangoImageField: type[SupportsToPython] = ..., ): ... class _UnvalidatedField(Field): ... -class ListField(Field[List[Any], List[Any], List[Any], Any]): - child: Field = ... - allow_empty: bool = ... - max_length: Optional[int] = ... - min_length: Optional[int] = ... +class ListField(Field[list[Any], list[Any], list[Any], Any]): + child: Field + allow_empty: bool + max_length: int | None + min_length: int | None def __init__( self, read_only: bool = ..., write_only: bool = ..., required: bool = ..., - default: _DefaultInitial[List[Any]] = ..., - initial: _DefaultInitial[List[Any]] = ..., + default: _DefaultInitial[list[Any]] = ..., + initial: _DefaultInitial[list[Any]] = ..., source: str = ..., label: str = ..., help_text: str = ..., - style: Dict[str, Any] = ..., - error_messages: Dict[str, str] = ..., - validators: Optional[Sequence[Validator[List[Any]]]] = ..., + style: dict[str, Any] = ..., + error_messages: dict[str, str] = ..., + validators: Sequence[Validator[list[Any]]] | None = ..., allow_null: bool = ..., *, child: Field = ..., @@ -628,24 +611,24 @@ class ListField(Field[List[Any], List[Any], List[Any], Any]): max_length: int = ..., min_length: int = ..., ): ... - def run_child_validation(self, data: List[Mapping[Any, Any]]) -> Any: ... + def run_child_validation(self, data: list[Mapping[Any, Any]]) -> Any: ... -class DictField(Field[Dict[Any, Any], Dict[Any, Any], Dict[Any, Any], Any]): - child: Field = ... - allow_empty: bool = ... +class DictField(Field[dict[Any, Any], dict[Any, Any], dict[Any, Any], Any]): + child: Field + allow_empty: bool def __init__( self, read_only: bool = ..., write_only: bool = ..., required: bool = ..., - default: _DefaultInitial[Dict[Any, Any]] = ..., - initial: _DefaultInitial[Dict[Any, Any]] = ..., + default: _DefaultInitial[dict[Any, Any]] = ..., + initial: _DefaultInitial[dict[Any, Any]] = ..., source: str = ..., label: str = ..., help_text: str = ..., - style: Dict[str, Any] = ..., - error_messages: Dict[str, str] = ..., - validators: Optional[Sequence[Validator[Dict[Any, Any]]]] = ..., + style: dict[str, Any] = ..., + error_messages: dict[str, str] = ..., + validators: Sequence[Validator[dict[Any, Any]]] | None = ..., allow_null: bool = ..., *, child: Field = ..., @@ -654,14 +637,12 @@ class DictField(Field[Dict[Any, Any], Dict[Any, Any], Dict[Any, Any], Any]): def run_child_validation(self, data: Any) -> Any: ... class HStoreField(DictField): - child: CharField = ... + child: CharField -class JSONField( - Field[Union[Dict[str, Any], List[Dict[str, Any]]], Union[Dict[str, Any], List[Dict[str, Any]]], str, Any] -): - binary: bool = ... - encoder: Optional[JSONEncoder] = ... - decoder: Optional[JSONDecoder] = ... +class JSONField(Field[dict[str, Any] | list[dict[str, Any]], dict[str, Any] | list[dict[str, Any]], str, Any]): + binary: bool + encoder: JSONEncoder | None + decoder: JSONDecoder | None def __init__( self, read_only: bool = ..., @@ -672,24 +653,24 @@ class JSONField( source: str = ..., label: str = ..., help_text: str = ..., - style: Dict[str, Any] = ..., - error_messages: Dict[str, str] = ..., - validators: Optional[Sequence[Validator[Any]]] = ..., + style: dict[str, Any] = ..., + error_messages: dict[str, str] = ..., + validators: Sequence[Validator[Any]] | None = ..., allow_null: bool = ..., *, binary: bool = ..., - encoder: Optional[JSONEncoder] = ..., - decoder: Optional[JSONDecoder] = ..., + encoder: JSONEncoder | None = ..., + decoder: JSONDecoder | None = ..., ): ... class ReadOnlyField(Field): ... class HiddenField(Field): ... class SerializerMethodField(Field): - method_name: str = ... + method_name: str def __init__( self, - method_name: Optional[str] = ..., + method_name: str | None = ..., *, read_only: bool = ..., write_only: bool = ..., @@ -699,15 +680,15 @@ class SerializerMethodField(Field): source: str = ..., label: str = ..., help_text: str = ..., - style: Dict[str, Any] = ..., - error_messages: Dict[str, str] = ..., - validators: Optional[Sequence[Validator[Any]]] = ..., + style: dict[str, Any] = ..., + error_messages: dict[str, str] = ..., + validators: Sequence[Validator[Any]] | None = ..., allow_null: bool = ..., ): ... class ModelField(Field): - model_field: models.Field = ... - max_length: int = ... + model_field: models.Field + max_length: int def __init__( self, model_field: models.Field, @@ -720,9 +701,9 @@ class ModelField(Field): source: str = ..., label: str = ..., help_text: str = ..., - style: Dict[str, Any] = ..., - error_messages: Dict[str, str] = ..., - validators: Optional[Sequence[Validator[Any]]] = ..., + style: dict[str, Any] = ..., + error_messages: dict[str, str] = ..., + validators: Sequence[Validator[Any]] | None = ..., allow_null: bool = ..., max_length: int = ..., ): ... diff --git a/rest_framework-stubs/filters.pyi b/rest_framework-stubs/filters.pyi index 5a1f74492..c9591c65b 100644 --- a/rest_framework-stubs/filters.pyi +++ b/rest_framework-stubs/filters.pyi @@ -1,4 +1,5 @@ -from typing import Any, Dict, Iterable, List, Mapping, Optional, Sequence, Tuple, TypeVar +from collections.abc import Iterable, Mapping, Sequence +from typing import Any, TypeVar from django.db.models import Model, QuerySet from rest_framework.request import Request @@ -8,33 +9,33 @@ _MT = TypeVar("_MT", bound=Model) class BaseFilterBackend: def filter_queryset(self, request: Request, queryset: QuerySet[_MT], view: APIView) -> QuerySet[_MT]: ... - def get_schema_fields(self, view: APIView) -> List[Any]: ... + def get_schema_fields(self, view: APIView) -> list[Any]: ... def get_schema_operation_parameters(self, view: APIView): ... class SearchFilter(BaseFilterBackend): - search_param: str = ... - template: str = ... - lookup_prefixes: Dict[str, str] = ... - search_title: str = ... - search_description: str = ... + search_param: str + template: str + lookup_prefixes: dict[str, str] + search_title: str + search_description: str def get_search_fields(self, view: APIView, request: Request): ... - def get_search_terms(self, request: Request) -> List[str]: ... + def get_search_terms(self, request: Request) -> list[str]: ... def construct_search(self, field_name: str) -> str: ... def must_call_distinct(self, queryset: QuerySet, search_fields) -> bool: ... def to_html(self, request: Request, queryset: QuerySet, view: APIView) -> str: ... class OrderingFilter(BaseFilterBackend): - ordering_param: str = ... - ordering_fields: Optional[Sequence[str]] = ... - ordering_title: str = ... - ordering_description: str = ... - template: str = ... + ordering_param: str + ordering_fields: Sequence[str] | None + ordering_title: str + ordering_description: str + template: str def get_ordering(self, request: Request, queryset: QuerySet, view: APIView) -> Sequence[str]: ... def get_default_ordering(self, view: APIView) -> Sequence[str]: ... def get_default_valid_fields( self, queryset: QuerySet, view, context: Mapping[str, Any] = ... - ) -> List[Tuple[str, str]]: ... - def get_valid_fields(self, queryset: QuerySet, view, context: Mapping[str, Any] = ...) -> List[Tuple[str, str]]: ... - def remove_invalid_fields(self, queryset: QuerySet, fields: Iterable[str], view, request: Request) -> List[str]: ... - def get_template_context(self, request: Request, queryset: QuerySet, view: APIView) -> Dict[str, Any]: ... + ) -> list[tuple[str, str]]: ... + def get_valid_fields(self, queryset: QuerySet, view, context: Mapping[str, Any] = ...) -> list[tuple[str, str]]: ... + def remove_invalid_fields(self, queryset: QuerySet, fields: Iterable[str], view, request: Request) -> list[str]: ... + def get_template_context(self, request: Request, queryset: QuerySet, view: APIView) -> dict[str, Any]: ... def to_html(self, request: Request, queryset: QuerySet, view: APIView) -> str: ... diff --git a/rest_framework-stubs/generics.pyi b/rest_framework-stubs/generics.pyi index 9efc6ced0..c9fd65631 100644 --- a/rest_framework-stubs/generics.pyi +++ b/rest_framework-stubs/generics.pyi @@ -1,4 +1,5 @@ -from typing import Any, Dict, List, Optional, Protocol, Sequence, Type, TypeVar, Union +from collections.abc import Sequence +from typing import Any, Protocol, TypeVar from django.db.models import Manager, Model from django.db.models.query import QuerySet @@ -14,7 +15,7 @@ _MT_co = TypeVar("_MT_co", bound=Model, covariant=True) _MT_inv = TypeVar("_MT_inv", bound=Model) def get_object_or_404( - queryset: Union[Type[_MT_co], Manager[_MT_co], QuerySet[_MT_co]], *filter_args: Any, **filter_kwargs: Any + queryset: type[_MT_co] | Manager[_MT_co] | QuerySet[_MT_co], *filter_args: Any, **filter_kwargs: Any ) -> _MT_co: ... class UsesQuerySet(Protocol[_MT_co]): @@ -26,24 +27,24 @@ class BaseFilterProtocol(Protocol[_MT_inv]): def filter_queryset( self, request: Request, queryset: QuerySet[_MT_inv], view: views.APIView ) -> QuerySet[_MT_inv]: ... - def get_schema_fields(self, view: views.APIView) -> List[Any]: ... + def get_schema_fields(self, view: views.APIView) -> list[Any]: ... def get_schema_operation_parameters(self, view: views.APIView): ... class GenericAPIView(views.APIView, UsesQuerySet[_MT_co]): - queryset: Optional[Union[QuerySet[_MT_co], Manager[_MT_co]]] = ... - serializer_class: Optional[Type[BaseSerializer]] = ... - lookup_field: str = ... - lookup_url_kwarg: Optional[str] = ... - filter_backends: Sequence[Union[Type[BaseFilterBackend], Type[BaseFilterProtocol[_MT_co]]]] = ... - pagination_class: Optional[Type[BasePagination]] = ... + queryset: QuerySet[_MT_co] | Manager[_MT_co] | None + serializer_class: type[BaseSerializer] | None + lookup_field: str + lookup_url_kwarg: str | None + filter_backends: Sequence[type[BaseFilterBackend] | type[BaseFilterProtocol[_MT_co]]] + pagination_class: type[BasePagination] | None def get_object(self) -> _MT_co: ... def get_serializer(self, *args: Any, **kwargs: Any) -> BaseSerializer[_MT_co]: ... - def get_serializer_class(self) -> Type[BaseSerializer[_MT_co]]: ... - def get_serializer_context(self) -> Dict[str, Any]: ... + def get_serializer_class(self) -> type[BaseSerializer[_MT_co]]: ... + def get_serializer_context(self) -> dict[str, Any]: ... def filter_queryset(self, queryset: QuerySet[_MT_co]) -> QuerySet[_MT_co]: ... @property - def paginator(self) -> Optional[BasePagination]: ... - def paginate_queryset(self, queryset: Union[QuerySet[_MT_co], Sequence[Any]]) -> Optional[Sequence[Any]]: ... + def paginator(self) -> BasePagination | None: ... + def paginate_queryset(self, queryset: QuerySet[_MT_co] | Sequence[Any]) -> Sequence[Any] | None: ... def get_paginated_response(self, data: Any) -> Response: ... class CreateAPIView(mixins.CreateModelMixin, GenericAPIView[_MT_co]): diff --git a/rest_framework-stubs/management/commands/generateschema.pyi b/rest_framework-stubs/management/commands/generateschema.pyi index 9633fbad6..975ddc156 100644 --- a/rest_framework-stubs/management/commands/generateschema.pyi +++ b/rest_framework-stubs/management/commands/generateschema.pyi @@ -6,7 +6,7 @@ OPENAPI_MODE: str COREAPI_MODE: str class Command(BaseCommand): - help: str = ... + help: str def get_mode(self): ... def add_arguments(self, parser: Any) -> None: ... def handle(self, *args: Any, **options: Any) -> None: ... diff --git a/rest_framework-stubs/metadata.pyi b/rest_framework-stubs/metadata.pyi index fb1f87b68..8eccfe810 100644 --- a/rest_framework-stubs/metadata.pyi +++ b/rest_framework-stubs/metadata.pyi @@ -1,4 +1,4 @@ -from typing import Any, Dict, Type +from typing import Any from rest_framework import serializers from rest_framework.request import Request @@ -7,10 +7,10 @@ from rest_framework.utils.field_mapping import ClassLookupDict from rest_framework.views import APIView class BaseMetadata: - def determine_metadata(self, request: Request, view: APIView) -> Dict[str, Any]: ... + def determine_metadata(self, request: Request, view: APIView) -> dict[str, Any]: ... class SimpleMetadata(BaseMetadata): - label_lookup: ClassLookupDict[Type[serializers.Field], str] - def determine_actions(self, request: Request, view: APIView) -> Dict[str, Any]: ... - def get_serializer_info(self, serializer: BaseSerializer) -> Dict[str, Dict[str, Any]]: ... - def get_field_info(self, field: serializers.Field) -> Dict[str, Any]: ... + label_lookup: ClassLookupDict[type[serializers.Field], str] + def determine_actions(self, request: Request, view: APIView) -> dict[str, Any]: ... + def get_serializer_info(self, serializer: BaseSerializer) -> dict[str, dict[str, Any]]: ... + def get_field_info(self, field: serializers.Field) -> dict[str, Any]: ... diff --git a/rest_framework-stubs/mixins.pyi b/rest_framework-stubs/mixins.pyi index 140fee384..842999f7f 100644 --- a/rest_framework-stubs/mixins.pyi +++ b/rest_framework-stubs/mixins.pyi @@ -1,4 +1,4 @@ -from typing import Any, Dict, TypeVar +from typing import Any, TypeVar from django.db.models import Model @@ -12,7 +12,7 @@ _MT = TypeVar("_MT", bound=Model) class CreateModelMixin: def create(self, request: Request, *args: Any, **kwargs: Any) -> Response: ... def perform_create(self: UsesQuerySet[_MT], serializer: BaseSerializer[_MT]) -> None: ... - def get_success_headers(self, data: Any) -> Dict[str, str]: ... + def get_success_headers(self, data: Any) -> dict[str, str]: ... class ListModelMixin: def list(self, request: Request, *args: Any, **kwargs: Any) -> Response: ... diff --git a/rest_framework-stubs/negotiation.pyi b/rest_framework-stubs/negotiation.pyi index 3b6e132a7..d2b932384 100644 --- a/rest_framework-stubs/negotiation.pyi +++ b/rest_framework-stubs/negotiation.pyi @@ -1,4 +1,4 @@ -from typing import Iterable, List, Optional +from collections.abc import Iterable from rest_framework.parsers import BaseParser from rest_framework.renderers import BaseRenderer @@ -6,12 +6,10 @@ from rest_framework.request import Request from rest_framework.settings import api_settings class BaseContentNegotiation: - def select_parser(self, request: Request, parsers: Iterable[BaseParser]) -> Optional[BaseParser]: ... - def select_renderer( - self, request: Request, renderers: Iterable[BaseRenderer], format_suffix: Optional[str] = ... - ): ... + def select_parser(self, request: Request, parsers: Iterable[BaseParser]) -> BaseParser | None: ... + def select_renderer(self, request: Request, renderers: Iterable[BaseRenderer], format_suffix: str | None = ...): ... class DefaultContentNegotiation(BaseContentNegotiation): settings = api_settings - def filter_renderers(self, renderers: Iterable[BaseRenderer], format: str) -> List[BaseRenderer]: ... - def get_accept_list(self, request: Request) -> List[str]: ... + def filter_renderers(self, renderers: Iterable[BaseRenderer], format: str) -> list[BaseRenderer]: ... + def get_accept_list(self, request: Request) -> list[str]: ... diff --git a/rest_framework-stubs/pagination.pyi b/rest_framework-stubs/pagination.pyi index 2b97c7d05..51130ce47 100644 --- a/rest_framework-stubs/pagination.pyi +++ b/rest_framework-stubs/pagination.pyi @@ -1,4 +1,5 @@ -from typing import Any, Callable, Dict, List, NamedTuple, Optional, Sequence, Tuple, Type, TypeVar, Union +from collections.abc import Callable, Sequence +from typing import Any, NamedTuple, TypeVar from coreapi import Field as CoreAPIField from django.core.paginator import Page, Paginator @@ -8,22 +9,22 @@ from rest_framework.response import Response from rest_framework.views import APIView from typing_extensions import TypedDict -def _positive_int(integer_string: str, strict: bool = ..., cutoff: Optional[int] = ...) -> int: ... +def _positive_int(integer_string: str, strict: bool = ..., cutoff: int | None = ...) -> int: ... def _divide_with_ceil(a: int, b: int) -> int: ... -def _get_displayed_page_numbers(current: int, final: int) -> List[Optional[int]]: ... +def _get_displayed_page_numbers(current: int, final: int) -> list[int | None]: ... def _get_page_links( - page_numbers: Sequence[Optional[int]], current: int, url_func: Callable[[int], str] -) -> List[PageLink]: ... -def _reverse_ordering(ordering_tuple: Sequence[str]) -> Tuple[str, ...]: ... + page_numbers: Sequence[int | None], current: int, url_func: Callable[[int], str] +) -> list[PageLink]: ... +def _reverse_ordering(ordering_tuple: Sequence[str]) -> tuple[str, ...]: ... class Cursor(NamedTuple): offset: int reverse: bool - position: Optional[int] + position: int | None class PageLink(NamedTuple): - url: Optional[str] - number: Optional[int] + url: str | None + number: int | None is_active: bool is_break: bool @@ -32,96 +33,96 @@ class HtmlContext(TypedDict): next_url: str class HtmlContextWithPageLinks(HtmlContext): - page_links: List[PageLink] + page_links: list[PageLink] -PAGE_BREAK: PageLink = ... +PAGE_BREAK: PageLink _MT = TypeVar("_MT", bound=Model) class BasePagination: - display_page_controls: bool = ... + display_page_controls: bool def get_paginated_response_schema(self, schema: Any): ... def get_paginated_response(self, data: Any) -> Response: ... - def get_results(self, data: Dict[str, Any]) -> Any: ... + def get_results(self, data: dict[str, Any]) -> Any: ... def get_schema_fields(self, view: APIView) -> list: ... def get_schema_operation_parameters(self, view: APIView) -> list: ... - def paginate_queryset(self, queryset: QuerySet, request: Request, view: Optional[APIView] = ...): ... + def paginate_queryset(self, queryset: QuerySet, request: Request, view: APIView | None = ...): ... def to_html(self) -> str: ... class PageNumberPagination(BasePagination): - display_page_controls: bool = ... - django_paginator_class: Type[Paginator] = ... - invalid_page_message: str = ... - last_page_strings: Sequence[str] = ... - max_page_size: Optional[int] = ... - page_query_description: str = ... - page_query_param: str = ... - page_size_query_description: str = ... - page_size_query_param: Optional[str] = ... - page_size: Optional[int] = ... - page: Optional[Page] = ... - request: Optional[Request] = ... - template: str = ... + display_page_controls: bool + django_paginator_class: type[Paginator] + invalid_page_message: str + last_page_strings: Sequence[str] + max_page_size: int | None + page_query_description: str + page_query_param: str + page_size_query_description: str + page_size_query_param: str | None + page_size: int | None + page: Page | None + request: Request | None + template: str def paginate_queryset( - self, queryset: QuerySet[_MT], request: Request, view: Optional[APIView] = ... - ) -> Optional[List[_MT]]: ... - def get_paginated_response_schema(self, schema: Dict[str, Any]) -> Dict[str, Any]: ... - def get_schema_fields(self, view: APIView) -> List[CoreAPIField]: ... - def get_schema_operation_parameters(self, view: APIView) -> List[Dict[str, Any]]: ... - def get_page_number(self, request: Request, paginator: Paginator) -> Union[int, str]: ... - def get_page_size(self, request: Request) -> Optional[int]: ... - def get_next_link(self) -> Optional[str]: ... - def get_previous_link(self) -> Optional[str]: ... + self, queryset: QuerySet[_MT], request: Request, view: APIView | None = ... + ) -> list[_MT] | None: ... + def get_paginated_response_schema(self, schema: dict[str, Any]) -> dict[str, Any]: ... + def get_schema_fields(self, view: APIView) -> list[CoreAPIField]: ... + def get_schema_operation_parameters(self, view: APIView) -> list[dict[str, Any]]: ... + def get_page_number(self, request: Request, paginator: Paginator) -> int | str: ... + def get_page_size(self, request: Request) -> int | None: ... + def get_next_link(self) -> str | None: ... + def get_previous_link(self) -> str | None: ... def get_html_context(self) -> HtmlContextWithPageLinks: ... class LimitOffsetPagination(BasePagination): - count: Optional[int] = ... - default_limit: Optional[int] = ... - limit_query_description: str = ... - limit_query_param: str = ... - limit: Optional[int] = ... - max_limit: Optional[int] = ... - offset_query_description: str = ... - offset_query_param: str = ... - offset: Optional[int] = ... - request: Optional[Request] = ... - template: str = ... + count: int | None + default_limit: int | None + limit_query_description: str + limit_query_param: str + limit: int | None + max_limit: int | None + offset_query_description: str + offset_query_param: str + offset: int | None + request: Request | None + template: str def paginate_queryset( - self, queryset: QuerySet[_MT], request: Request, view: Optional[APIView] = ... - ) -> Optional[List[_MT]]: ... - def get_limit(self, request: Request) -> Optional[int]: ... + self, queryset: QuerySet[_MT], request: Request, view: APIView | None = ... + ) -> list[_MT] | None: ... + def get_limit(self, request: Request) -> int | None: ... def get_offset(self, request: Request) -> int: ... - def get_next_link(self) -> Optional[str]: ... - def get_previous_link(self) -> Optional[str]: ... + def get_next_link(self) -> str | None: ... + def get_previous_link(self) -> str | None: ... def get_html_context(self) -> HtmlContextWithPageLinks: ... - def get_count(self, queryset: Union[QuerySet, Sequence]) -> int: ... + def get_count(self, queryset: QuerySet | Sequence) -> int: ... class CursorPagination(BasePagination): - base_url: Optional[str] = ... - cursor_query_description: str = ... - cursor_query_param: str = ... - cursor: Optional[Cursor] = ... - has_next: Optional[bool] = ... - has_previous: Optional[bool] = ... - invalid_cursor_message: str = ... - max_page_size: Optional[int] = ... - next_position: Optional[str] = ... - offset_cutoff: int = ... - ordering: Union[str, List[str], Tuple[str, ...]] = ... - page_size_query_description: str = ... - page_size_query_param: Optional[str] = ... - page_size: Optional[int] = ... - page: Optional[List[Any]] = ... - previous_position: Optional[str] = ... - template: str = ... + base_url: str | None + cursor_query_description: str + cursor_query_param: str + cursor: Cursor | None + has_next: bool | None + has_previous: bool | None + invalid_cursor_message: str + max_page_size: int | None + next_position: str | None + offset_cutoff: int + ordering: str | list[str] | tuple[str, ...] + page_size_query_description: str + page_size_query_param: str | None + page_size: int | None + page: list[Any] | None + previous_position: str | None + template: str def paginate_queryset( - self, queryset: QuerySet[_MT], request: Request, view: Optional[APIView] = ... - ) -> Optional[List[_MT]]: ... - def get_page_size(self, request: Request) -> Optional[int]: ... - def get_next_link(self) -> Optional[str]: ... - def get_previous_link(self) -> Optional[str]: ... + self, queryset: QuerySet[_MT], request: Request, view: APIView | None = ... + ) -> list[_MT] | None: ... + def get_page_size(self, request: Request) -> int | None: ... + def get_next_link(self) -> str | None: ... + def get_previous_link(self) -> str | None: ... def get_html_context(self) -> HtmlContext: ... - def get_ordering(self, request: Request, queryset: QuerySet, view: APIView) -> Tuple[str, ...]: ... - def decode_cursor(self, request: Request) -> Optional[Cursor]: ... + def get_ordering(self, request: Request, queryset: QuerySet, view: APIView) -> tuple[str, ...]: ... + def decode_cursor(self, request: Request) -> Cursor | None: ... def encode_cursor(self, cursor: Cursor) -> str: ... def _get_position_from_instance(self, instance: Any, ordering: Sequence[str]) -> str: ... diff --git a/rest_framework-stubs/parsers.pyi b/rest_framework-stubs/parsers.pyi index b3b0b779b..4e77df304 100644 --- a/rest_framework-stubs/parsers.pyi +++ b/rest_framework-stubs/parsers.pyi @@ -1,4 +1,5 @@ -from typing import IO, Any, Dict, Generic, Mapping, Optional, Type, TypeVar, Union +from collections.abc import Mapping +from typing import IO, Any, Generic, TypeVar from django.core.files.uploadedfile import UploadedFile from django.http.request import _ImmutableQueryDict @@ -14,32 +15,32 @@ class DataAndFiles(Generic[_Data, _Files]): def __init__(self, data: _Data, files: _Files) -> None: ... class BaseParser: - media_type: str = ... + media_type: str def parse( - self, stream: IO[Any], media_type: Optional[str] = ..., parser_context: Optional[Mapping[str, Any]] = ... - ) -> Union[Mapping[Any, Any], DataAndFiles]: ... + self, stream: IO[Any], media_type: str | None = ..., parser_context: Mapping[str, Any] | None = ... + ) -> Mapping[Any, Any] | DataAndFiles: ... class JSONParser(BaseParser): - renderer_class: Type[JSONRenderer] = ... - strict: bool = ... + renderer_class: type[JSONRenderer] + strict: bool def parse( - self, stream: IO[Any], media_type: Optional[str] = ..., parser_context: Optional[Mapping[str, Any]] = ... - ) -> Dict[str, Any]: ... + self, stream: IO[Any], media_type: str | None = ..., parser_context: Mapping[str, Any] | None = ... + ) -> dict[str, Any]: ... class FormParser(BaseParser): def parse( - self, stream: IO[Any], media_type: Optional[str] = ..., parser_context: Optional[Mapping[str, Any]] = ... + self, stream: IO[Any], media_type: str | None = ..., parser_context: Mapping[str, Any] | None = ... ) -> _ImmutableQueryDict: ... class MultiPartParser(BaseParser): def parse( - self, stream: IO[Any], media_type: Optional[str] = ..., parser_context: Optional[Mapping[str, Any]] = ... + self, stream: IO[Any], media_type: str | None = ..., parser_context: Mapping[str, Any] | None = ... ) -> DataAndFiles[_ImmutableQueryDict, MultiValueDict]: ... class FileUploadParser(BaseParser): - errors: Dict[str, str] = ... + errors: dict[str, str] def parse( - self, stream: IO[Any], media_type: Optional[str] = ..., parser_context: Optional[Mapping[str, Any]] = ... + self, stream: IO[Any], media_type: str | None = ..., parser_context: Mapping[str, Any] | None = ... ) -> DataAndFiles[None, Mapping[str, UploadedFile]]: ... - def get_filename(self, stream: IO[Any], media_type: Optional[str], parser_context: Mapping[str, Any]) -> str: ... + def get_filename(self, stream: IO[Any], media_type: str | None, parser_context: Mapping[str, Any]) -> str: ... def get_encoded_filename(self, filename_parm: Mapping[str, Any]) -> str: ... diff --git a/rest_framework-stubs/permissions.pyi b/rest_framework-stubs/permissions.pyi index 1a5c17650..ddd10f1a8 100644 --- a/rest_framework-stubs/permissions.pyi +++ b/rest_framework-stubs/permissions.pyi @@ -1,16 +1,19 @@ -from typing import Any, Dict, List, Protocol, Sequence, Type, Union +from collections.abc import Sequence +from typing import Any, Protocol, Union # noqa: Y037 # https://github.com/python/mypy/issues/12392 +from typing_extensions import TypeAlias from django.db.models import Model, QuerySet from rest_framework.request import Request from rest_framework.views import APIView -SAFE_METHODS: Sequence[str] = ("GET", "HEAD", "OPTIONS") +SAFE_METHODS: Sequence[str] class _SupportsHasPermission(Protocol): def has_permission(self, request: Request, view: APIView) -> bool: ... def has_object_permission(self, request: Request, view: APIView, obj: Any) -> bool: ... -_PermissionClass = Union[Type[BasePermission], OperandHolder, SingleOperandHolder] +# https://github.com/python/mypy/issues/12392 +_PermissionClass: TypeAlias = Union[type[BasePermission], OperandHolder, SingleOperandHolder] class OperationHolderMixin: def __and__(self, other: _PermissionClass) -> OperandHolder: ... @@ -55,12 +58,12 @@ class IsAdminUser(BasePermission): ... class IsAuthenticatedOrReadOnly(BasePermission): ... class DjangoModelPermissions(BasePermission): - perms_map: Dict[str, List[str]] = ... - authenticated_users_only: bool = ... - def get_required_permissions(self, method: str, model_cls: Type[Model]) -> List[str]: ... + perms_map: dict[str, list[str]] + authenticated_users_only: bool + def get_required_permissions(self, method: str, model_cls: type[Model]) -> list[str]: ... def _queryset(self, view: APIView) -> QuerySet: ... class DjangoModelPermissionsOrAnonReadOnly(DjangoModelPermissions): ... class DjangoObjectPermissions(DjangoModelPermissions): - def get_required_object_permissions(self, method: str, model_cls: Type[Model]) -> List[str]: ... + def get_required_object_permissions(self, method: str, model_cls: type[Model]) -> list[str]: ... diff --git a/rest_framework-stubs/relations.pyi b/rest_framework-stubs/relations.pyi index eb02ef9e3..a430932e4 100644 --- a/rest_framework-stubs/relations.pyi +++ b/rest_framework-stubs/relations.pyi @@ -1,5 +1,7 @@ from collections import OrderedDict -from typing import Any, Callable, Dict, Generic, Iterable, List, Mapping, Optional, Sequence, TypeVar, Union +from collections.abc import Callable, Iterable, Mapping, Sequence +from typing import Any, Generic, TypeVar +from _typeshed import Self from django.db.models import Manager, Model, QuerySet from rest_framework.fields import Field, Option @@ -12,15 +14,15 @@ class ObjectValueError(ValueError): ... class ObjectTypeError(TypeError): ... class Hyperlink(str): - def __new__(cls, url: str, obj: Any) -> Hyperlink: ... + def __new__(cls: type[Self], url: str, obj: Any) -> Self: ... def __getnewargs__(self): ... @property def name(self) -> str: ... - is_hyperlink: bool = ... + is_hyperlink: bool obj: Any class PKOnlyObject: - pk: Any = ... + pk: Any def __init__(self, pk: Any) -> None: ... MANY_RELATION_KWARGS: Sequence[str] @@ -30,155 +32,155 @@ _DT = TypeVar("_DT") # Data Type _PT = TypeVar("_PT") # Primitive Type class RelatedField(Generic[_MT, _DT, _PT], Field[_MT, _DT, _PT, Any]): - queryset: Optional[Union[QuerySet[_MT], Manager[_MT]]] = ... - html_cutoff: Optional[int] = ... - html_cutoff_text: Optional[str] = ... + queryset: QuerySet[_MT] | Manager[_MT] | None + html_cutoff: int | None + html_cutoff_text: str | None def __init__( self, many: bool = ..., allow_empty: bool = ..., - queryset: Optional[Union[QuerySet[_MT], Manager[_MT]]] = ..., - html_cutoff: Optional[int] = ..., + queryset: QuerySet[_MT] | Manager[_MT] | None = ..., + html_cutoff: int | None = ..., html_cutoff_text: str = ..., read_only: bool = ..., write_only: bool = ..., required: bool = ..., default: Any = ..., initial: Any = ..., - source: Union[Callable, str] = ..., - label: Optional[str] = ..., + source: Callable | str = ..., + label: str | None = ..., help_text: str = ..., allow_null: bool = ..., - validators: Optional[Sequence[Validator[_MT]]] = ..., - error_messages: Optional[Dict[str, str]] = ..., - style: Optional[Dict[str, str]] = ..., + validators: Sequence[Validator[_MT]] | None = ..., + error_messages: dict[str, str] | None = ..., + style: dict[str, str] | None = ..., ): ... # mypy doesn't accept the typing below, although its accurate to what this class is doing, hence the ignore - def __new__(cls, *args: Any, **kwargs: Any) -> Union[RelatedField[_MT, _DT, _PT], ManyRelatedField]: ... # type: ignore + def __new__(cls, *args: Any, **kwargs: Any) -> RelatedField[_MT, _DT, _PT] | ManyRelatedField: ... # type: ignore @classmethod def many_init(cls, *args: Any, **kwargs: Any) -> ManyRelatedField: ... def get_queryset(self) -> QuerySet[_MT]: ... def use_pk_only_optimization(self) -> bool: ... - def get_choices(self, cutoff: Optional[int] = ...) -> OrderedDict: ... + def get_choices(self, cutoff: int | None = ...) -> OrderedDict: ... @property def choices(self) -> OrderedDict: ... @property def grouped_choices(self) -> OrderedDict: ... def iter_options(self) -> Iterable[Option]: ... - def get_attribute(self, instance: _MT) -> Optional[_PT]: ... # type: ignore[override] + def get_attribute(self, instance: _MT) -> _PT | None: ... # type: ignore[override] def display_value(self, instance: _MT) -> str: ... class StringRelatedField(RelatedField[_MT, _MT, str]): ... class PrimaryKeyRelatedField(RelatedField[_MT, _MT, Any]): - pk_field: Optional[str] = ... + pk_field: str | None def __init__( self, many: bool = ..., allow_empty: bool = ..., - queryset: Optional[Union[QuerySet[_MT], Manager[_MT]]] = ..., - html_cutoff: Optional[int] = ..., + queryset: QuerySet[_MT] | Manager[_MT] | None = ..., + html_cutoff: int | None = ..., html_cutoff_text: str = ..., read_only: bool = ..., write_only: bool = ..., required: bool = ..., default: Any = ..., initial: Any = ..., - source: Union[Callable, str] = ..., - label: Optional[str] = ..., + source: Callable | str = ..., + label: str | None = ..., help_text: str = ..., allow_null: bool = ..., - validators: Optional[Sequence[Validator[_MT]]] = ..., - error_messages: Optional[Dict[str, str]] = ..., - style: Optional[Dict[str, str]] = ..., - pk_field: Optional[Union[str, Field]] = ..., + validators: Sequence[Validator[_MT]] | None = ..., + error_messages: dict[str, str] | None = ..., + style: dict[str, str] | None = ..., + pk_field: str | Field | None = ..., ): ... class HyperlinkedRelatedField(RelatedField[_MT, str, Hyperlink]): - reverse: Callable = ... - lookup_field: str = ... - lookup_url_kwarg: str = ... - format: Optional[str] = ... - view_name: Optional[str] = ... + reverse: Callable + lookup_field: str + lookup_url_kwarg: str + format: str | None + view_name: str | None def __init__( self, many: bool = ..., allow_empty: bool = ..., - queryset: Optional[Union[QuerySet[_MT], Manager[_MT]]] = ..., - html_cutoff: Optional[int] = ..., + queryset: QuerySet[_MT] | Manager[_MT] | None = ..., + html_cutoff: int | None = ..., html_cutoff_text: str = ..., read_only: bool = ..., write_only: bool = ..., required: bool = ..., default: Any = ..., initial: Any = ..., - source: Union[Callable, str] = ..., - label: Optional[str] = ..., + source: Callable | str = ..., + label: str | None = ..., help_text: str = ..., allow_null: bool = ..., - validators: Optional[Sequence[Validator[_MT]]] = ..., - error_messages: Optional[Dict[str, str]] = ..., - style: Optional[Dict[str, str]] = ..., - view_name: Optional[str] = ..., - lookup_field: Optional[str] = ..., - lookup_url_kwarg: Optional[str] = ..., - format: Optional[str] = ..., + validators: Sequence[Validator[_MT]] | None = ..., + error_messages: dict[str, str] | None = ..., + style: dict[str, str] | None = ..., + view_name: str | None = ..., + lookup_field: str | None = ..., + lookup_url_kwarg: str | None = ..., + format: str | None = ..., ): ... def get_object(self, view_name: str, *view_args: Any, **view_kwargs: Any) -> _MT: ... - def get_url(self, obj: Model, view_name: str, request: Request, format: str) -> Optional[str]: ... + def get_url(self, obj: Model, view_name: str, request: Request, format: str) -> str | None: ... class HyperlinkedIdentityField(HyperlinkedRelatedField): ... class SlugRelatedField(RelatedField[_MT, str, str]): - slug_field: Optional[str] = ... + slug_field: str | None def __init__( self, many: bool = ..., allow_empty: bool = ..., - queryset: Optional[Union[QuerySet[_MT], Manager[_MT]]] = ..., - html_cutoff: Optional[int] = ..., + queryset: QuerySet[_MT] | Manager[_MT] | None = ..., + html_cutoff: int | None = ..., html_cutoff_text: str = ..., read_only: bool = ..., write_only: bool = ..., required: bool = ..., default: _DT = ..., - initial: Union[_MT, Callable[[Any], _MT]] = ..., - source: Union[Callable, str] = ..., - label: Optional[str] = ..., + initial: _MT | Callable[[Any], _MT] = ..., + source: Callable | str = ..., + label: str | None = ..., help_text: str = ..., allow_null: bool = ..., - validators: Optional[Sequence[Validator[_MT]]] = ..., - error_messages: Optional[Dict[str, str]] = ..., - style: Optional[Dict[str, str]] = ..., - slug_field: Optional[str] = ..., + validators: Sequence[Validator[_MT]] | None = ..., + error_messages: dict[str, str] | None = ..., + style: dict[str, str] | None = ..., + slug_field: str | None = ..., ): ... def to_internal_value(self, data: Any) -> _MT: ... def to_representation(self, value: _MT) -> str: ... -class ManyRelatedField(Field[Sequence[Any], Sequence[Any], List[Any], Any]): - default_empty_html: List[object] = ... - html_cutoff: Optional[int] = ... - html_cutoff_text: Optional[str] = ... - child_relation: RelatedField = ... - allow_empty: bool = ... +class ManyRelatedField(Field[Sequence[Any], Sequence[Any], list[Any], Any]): + default_empty_html: list[object] + html_cutoff: int | None + html_cutoff_text: str | None + child_relation: RelatedField + allow_empty: bool def __init__( self, read_only: bool = ..., write_only: bool = ..., required: bool = ..., default: Sequence[Any] = ..., - initial: Union[Sequence[Any], Callable[[Any], Sequence[Any]]] = ..., - source: Union[Callable, str] = ..., - label: Optional[str] = ..., - help_text: Optional[str] = ..., - style: Optional[Dict[str, str]] = ..., - error_messages: Optional[Dict[str, str]] = ..., - validators: Optional[Sequence[Validator[Sequence[Any]]]] = ..., + initial: Sequence[Any] | Callable[[Any], Sequence[Any]] = ..., + source: Callable | str = ..., + label: str | None = ..., + help_text: str | None = ..., + style: dict[str, str] | None = ..., + error_messages: dict[str, str] | None = ..., + validators: Sequence[Validator[Sequence[Any]]] | None = ..., allow_null: bool = ..., child_relation: RelatedField = ..., ): ... - def get_value(self, dictionary: Mapping[Any, Any]) -> List[Any]: ... # type: ignore[override] - def get_choices(self, cutoff: Optional[int] = ...) -> OrderedDict: ... + def get_value(self, dictionary: Mapping[Any, Any]) -> list[Any]: ... # type: ignore[override] + def get_choices(self, cutoff: int | None = ...) -> OrderedDict: ... @property def choices(self) -> OrderedDict: ... @property diff --git a/rest_framework-stubs/renderers.pyi b/rest_framework-stubs/renderers.pyi index c97f91d4e..d1f96d518 100644 --- a/rest_framework-stubs/renderers.pyi +++ b/rest_framework-stubs/renderers.pyi @@ -1,5 +1,6 @@ from json import JSONEncoder -from typing import Any, Dict, Iterable, List, Mapping, Optional, Sequence, Tuple, Type +from collections.abc import Iterable, Mapping, Sequence +from typing import Any from django import forms from rest_framework.request import Request @@ -8,39 +9,39 @@ from rest_framework.serializers import BaseSerializer from rest_framework.utils.field_mapping import ClassLookupDict from rest_framework.views import APIView -def zero_as_none(value: Any) -> Optional[Any]: ... +def zero_as_none(value: Any) -> Any | None: ... class BaseRenderer: - media_type: str = ... - format: str = ... - charset: Optional[str] = ... - render_style: str = ... + media_type: str + format: str + charset: str | None + render_style: str def render( - self, data: Any, accepted_media_type: Optional[str] = ..., renderer_context: Optional[Mapping[str, Any]] = ... + self, data: Any, accepted_media_type: str | None = ..., renderer_context: Mapping[str, Any] | None = ... ) -> Any: ... class JSONRenderer(BaseRenderer): - encoder_class: Type[JSONEncoder] = ... - ensure_ascii: bool = ... - compact: bool = ... - strict: bool = ... - def get_indent(self, accepted_media_type: str, renderer_context: Mapping[str, Any]) -> Optional[int]: ... + encoder_class: type[JSONEncoder] + ensure_ascii: bool + compact: bool + strict: bool + def get_indent(self, accepted_media_type: str, renderer_context: Mapping[str, Any]) -> int | None: ... class TemplateHTMLRenderer(BaseRenderer): - template_name: Optional[str] = ... - exception_template_names: Sequence[str] = ... + template_name: str | None + exception_template_names: Sequence[str] def resolve_template(self, template_names: Iterable[str]) -> Any: ... def get_template_context(self, data: Any, renderer_context: Mapping[str, Any]): ... - def get_template_names(self, response: Response, view: APIView) -> List[str]: ... + def get_template_names(self, response: Response, view: APIView) -> list[str]: ... def get_exception_template(self, response: Response) -> Any: ... class StaticHTMLRenderer(TemplateHTMLRenderer): ... class HTMLFormRenderer(BaseRenderer): - template_pack: str = ... - base_template: str = ... + template_pack: str + base_template: str - default_style: ClassLookupDict = ... + default_style: ClassLookupDict def render_field(self, field, parent_style: Mapping[str, Any]) -> str: ... class BrowsableAPIRenderer(BaseRenderer): @@ -48,59 +49,59 @@ class BrowsableAPIRenderer(BaseRenderer): HTML renderer used to self-document the API. """ - template: str = ... - filter_template: str = ... - code_style: str = ... - form_renderer_class: Type[BaseRenderer] = ... + template: str + filter_template: str + code_style: str + form_renderer_class: type[BaseRenderer] def get_default_renderer(self, view: APIView) -> BaseRenderer: ... def get_content( self, renderer: BaseRenderer, data: Any, accepted_media_type: str, renderer_context: Mapping[str, Any] ) -> str: ... def show_form_for_method(self, view: APIView, method: str, request: Request, obj: Any) -> bool: ... def _get_serializer( - self, serializer_class: Type[BaseSerializer], view_instance: APIView, request: Request, *args, **kwargs + self, serializer_class: type[BaseSerializer], view_instance: APIView, request: Request, *args, **kwargs ) -> BaseSerializer: ... def get_rendered_html_form(self, data: Any, view: APIView, method: str, request: Request) -> Any: ... def render_form_for_serializer(self, serializer: BaseSerializer) -> Any: ... - def get_raw_data_form(self, data: Any, view: APIView, method: str, request: Request) -> Optional[forms.Form]: ... + def get_raw_data_form(self, data: Any, view: APIView, method: str, request: Request) -> forms.Form | None: ... def get_name(self, view: APIView) -> str: ... def get_description(self, view: APIView, status_code: int) -> str: ... - def get_breadcrumbs(self, request: Request) -> List[Tuple[str, str]]: ... - def get_extra_actions(self, view: APIView) -> Optional[Dict[str, str]]: ... - def get_filter_form(self, data: Any, view: APIView, request: Request) -> Optional[Any]: ... + def get_breadcrumbs(self, request: Request) -> list[tuple[str, str]]: ... + def get_extra_actions(self, view: APIView) -> dict[str, str] | None: ... + def get_filter_form(self, data: Any, view: APIView, request: Request) -> Any | None: ... def get_context( - self, data: Any, accepted_media_type: Optional[str], renderer_context: Mapping[str, Any] - ) -> Dict[str, Any]: ... + self, data: Any, accepted_media_type: str | None, renderer_context: Mapping[str, Any] + ) -> dict[str, Any]: ... class AdminRenderer(BrowsableAPIRenderer): - def get_result_url(self, result: Mapping[str, Any], view: APIView) -> Optional[str]: ... + def get_result_url(self, result: Mapping[str, Any], view: APIView) -> str | None: ... class DocumentationRenderer(BaseRenderer): - template: str = ... - error_template: str = ... - code_style: str = ... - languages: Sequence[str] = ... - def get_context(self, data: Any, request: Request) -> Dict[str, Any]: ... + template: str + error_template: str + code_style: str + languages: Sequence[str] + def get_context(self, data: Any, request: Request) -> dict[str, Any]: ... class SchemaJSRenderer(BaseRenderer): - template: str = ... + template: str class MultiPartRenderer(BaseRenderer): - BOUNDARY: str = ... + BOUNDARY: str class CoreJSONRenderer(BaseRenderer): ... class _BaseOpenAPIRenderer: - media_type: str = ... - charset: Any = ... - format: str = ... + media_type: str + charset: Any + format: str def __init__(self) -> None: ... - def render(self, data: Any, media_type: Optional[Any] = ..., renderer_context: Optional[Any] = ...): ... - def get_schema(self, instance: Any) -> Dict[str, Any]: ... - def get_parameters(self, link) -> Dict[str, Any]: ... - def get_operation(self, link, name, tag) -> Dict[str, Any]: ... - def get_paths(self, document) -> Dict[str, Any]: ... - def get_structure(self, data: Any) -> Dict[str, Any]: ... + def render(self, data: Any, media_type: Any | None = ..., renderer_context: Any | None = ...): ... + def get_schema(self, instance: Any) -> dict[str, Any]: ... + def get_parameters(self, link) -> dict[str, Any]: ... + def get_operation(self, link, name, tag) -> dict[str, Any]: ... + def get_paths(self, document) -> dict[str, Any]: ... + def get_structure(self, data: Any) -> dict[str, Any]: ... class JSONOpenAPIRenderer(_BaseOpenAPIRenderer): ... class OpenAPIRenderer(_BaseOpenAPIRenderer): ... diff --git a/rest_framework-stubs/request.pyi b/rest_framework-stubs/request.pyi index 3b670f22a..f3e1f7b78 100644 --- a/rest_framework-stubs/request.pyi +++ b/rest_framework-stubs/request.pyi @@ -1,6 +1,8 @@ from contextlib import contextmanager from types import TracebackType -from typing import Any, ContextManager, Dict, Iterator, Optional, Sequence, Tuple, Type, Union +from collections.abc import Iterator, Sequence +from contextlib import AbstractContextManager +from typing import Any from django.contrib.auth.base_user import AbstractBaseUser from django.contrib.auth.models import AnonymousUser @@ -15,15 +17,15 @@ from rest_framework.views import APIView def is_form_media_type(media_type: str) -> bool: ... -class override_method(ContextManager["Request"]): +class override_method(AbstractContextManager[Request]): def __init__(self, view: APIView, request: Request, method: str): ... def __enter__(self) -> Request: ... def __exit__( self, - exc_type: Optional[Type[BaseException]], - exc_value: Optional[BaseException], - traceback: Optional[TracebackType], - ) -> Optional[bool]: ... + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + ) -> bool | None: ... class WrappedAttributeError(Exception): ... @@ -35,30 +37,26 @@ class Empty: ... def clone_request(request: Request, method: str) -> Request: ... class ForcedAuthentication: - force_user: Optional[Union[AnonymousUser, AbstractBaseUser]] = ... - force_token: Optional[str] = ... - def __init__( - self, force_user: Optional[Union[AnonymousUser, AbstractBaseUser]], force_token: Optional[str] - ) -> None: ... - def authenticate( - self, request: Request - ) -> Tuple[Optional[Union[AnonymousUser, AbstractBaseUser]], Optional[Any]]: ... + force_user: AnonymousUser | AbstractBaseUser | None + force_token: str | None + def __init__(self, force_user: AnonymousUser | AbstractBaseUser | None, force_token: str | None) -> None: ... + def authenticate(self, request: Request) -> tuple[AnonymousUser | AbstractBaseUser | None, Any | None]: ... class Request(HttpRequest): - parsers: Optional[Sequence[BaseParser]] = ... - authenticators: Optional[Sequence[Union[BaseAuthentication, ForcedAuthentication]]] = ... - negotiator: Optional[BaseContentNegotiation] = ... - parser_context: Optional[Dict[str, Any]] = ... - version: Optional[str] - versioning_scheme: Optional[BaseVersioning] + parsers: Sequence[BaseParser] | None + authenticators: Sequence[BaseAuthentication | ForcedAuthentication] | None + negotiator: BaseContentNegotiation | None + parser_context: dict[str, Any] | None + version: str | None + versioning_scheme: BaseVersioning | None _request: HttpRequest def __init__( self, request: HttpRequest, - parsers: Optional[Sequence[BaseParser]] = ..., - authenticators: Optional[Sequence[BaseAuthentication]] = ..., - negotiator: Optional[BaseContentNegotiation] = ..., - parser_context: Optional[Dict[str, Any]] = ..., + parsers: Sequence[BaseParser] | None = ..., + authenticators: Sequence[BaseAuthentication] | None = ..., + negotiator: BaseContentNegotiation | None = ..., + parser_context: dict[str, Any] | None = ..., ) -> None: ... @property def content_type(self) -> str: ... # type: ignore[override] @@ -67,17 +65,17 @@ class Request(HttpRequest): @property def query_params(self) -> _ImmutableQueryDict: ... @property - def data(self) -> Dict[str, Any]: ... + def data(self) -> dict[str, Any]: ... @property # type: ignore[override] - def user(self) -> Union[AbstractBaseUser, AnonymousUser]: ... # type: ignore[override] + def user(self) -> AbstractBaseUser | AnonymousUser: ... # type: ignore[override] @user.setter - def user(self, value: Union[AbstractBaseUser, AnonymousUser]) -> None: ... + def user(self, value: AbstractBaseUser | AnonymousUser) -> None: ... @property - def auth(self) -> Union[Token, Any]: ... + def auth(self) -> Token | Any: ... @auth.setter - def auth(self, value: Union[Token, Any]) -> None: ... + def auth(self, value: Token | Any) -> None: ... @property - def successful_authenticator(self) -> Optional[Union[BaseAuthentication, ForcedAuthentication]]: ... + def successful_authenticator(self) -> BaseAuthentication | ForcedAuthentication | None: ... def __getattr__(self, attr: str) -> Any: ... @property def DATA(self) -> None: ... diff --git a/rest_framework-stubs/response.pyi b/rest_framework-stubs/response.pyi index 7a091e60b..1f040e87f 100644 --- a/rest_framework-stubs/response.pyi +++ b/rest_framework-stubs/response.pyi @@ -1,4 +1,5 @@ -from typing import Any, Dict, List, Mapping, Optional, Tuple +from collections.abc import Mapping +from typing import Any from django.template.base import Template from django.test.utils import ContextList @@ -9,18 +10,18 @@ from rest_framework.request import Request from rest_framework.test import APIClient class Response(SimpleTemplateResponse): - data: Any = ... - exception: bool = ... - content_type: Optional[str] = ... + data: Any + exception: bool + content_type: str | None _request: Request def __init__( self, data: Any = ..., - status: Optional[int] = ..., - template_name: Optional[str] = ..., - headers: Optional[Mapping[str, str]] = ..., + status: int | None = ..., + template_name: str | None = ..., + headers: Mapping[str, str] | None = ..., exception: bool = ..., - content_type: Optional[str] = ..., + content_type: str | None = ..., ): ... @property def rendered_content(self) -> Any: ... @@ -30,9 +31,9 @@ class Response(SimpleTemplateResponse): class _MonkeyPatchedResponse(Response): client: APIClient - context: ContextList | Dict[str, Any] - redirect_chain: List[Tuple[str, int]] - request: Dict[str, Any] + context: ContextList | dict[str, Any] + redirect_chain: list[tuple[str, int]] + request: dict[str, Any] resolver_match: ResolverMatch - templates: List[Template] + templates: list[Template] def json(self) -> Any: ... diff --git a/rest_framework-stubs/reverse.pyi b/rest_framework-stubs/reverse.pyi index b09949b98..eda31b60a 100644 --- a/rest_framework-stubs/reverse.pyi +++ b/rest_framework-stubs/reverse.pyi @@ -1,23 +1,24 @@ -from typing import Any, Callable, Mapping, Optional, Sequence +from collections.abc import Callable, Mapping, Sequence +from typing import Any from django.http import HttpRequest -def preserve_builtin_query_params(url: str, request: Optional[HttpRequest] = ...) -> str: ... +def preserve_builtin_query_params(url: str, request: HttpRequest | None = ...) -> str: ... def reverse( viewname: str, - args: Optional[Sequence[Any]] = ..., - kwargs: Optional[Mapping[str, Any]] = ..., - request: Optional[HttpRequest] = ..., - format: Optional[str] = ..., + args: Sequence[Any] | None = ..., + kwargs: Mapping[str, Any] | None = ..., + request: HttpRequest | None = ..., + format: str | None = ..., **extra: Any ) -> str: ... def _reverse( viewname: str, - args: Optional[Sequence[Any]] = ..., - kwargs: Optional[Mapping[str, Any]] = ..., - request: Optional[HttpRequest] = ..., - format: Optional[str] = ..., + args: Sequence[Any] | None = ..., + kwargs: Mapping[str, Any] | None = ..., + request: HttpRequest | None = ..., + format: str | None = ..., **extra: Any ) -> str: ... -reverse_lazy: Callable[..., str] = ... +reverse_lazy: Callable[..., str] diff --git a/rest_framework-stubs/routers.pyi b/rest_framework-stubs/routers.pyi index d092a0523..f29b7db01 100644 --- a/rest_framework-stubs/routers.pyi +++ b/rest_framework-stubs/routers.pyi @@ -1,4 +1,5 @@ -from typing import Any, Callable, Dict, Iterable, List, Mapping, NamedTuple, Optional, Tuple, Type, Union +from collections.abc import Callable, Iterable, Mapping +from typing import Any, NamedTuple from django.utils.deprecation import RenameMethodsBase from rest_framework import views @@ -12,56 +13,56 @@ from rest_framework.viewsets import ViewSetMixin class Route(NamedTuple): url: str - mapping: Dict[str, str] + mapping: dict[str, str] name: str detail: bool - initkwargs: Dict[str, Any] + initkwargs: dict[str, Any] class DynamicRoute(NamedTuple): url: str name: str detail: bool - initkwargs: Dict[str, Any] + initkwargs: dict[str, Any] def escape_curly_brackets(url_path: str) -> str: ... def flatten(list_of_lists: Iterable[Iterable[Any]]) -> Iterable[Any]: ... class RenameRouterMethods(RenameMethodsBase): - renamed_methods: Iterable[Union[str, Callable]] = ... + renamed_methods: Iterable[str | Callable] class BaseRouter(metaclass=RenameRouterMethods): - registry: List[Tuple[str, Type[ViewSetMixin], str]] + registry: list[tuple[str, type[ViewSetMixin], str]] def register( - self, prefix: str, viewset: Type[ViewSetMixin], basename: Optional[str] = ..., base_name: Optional[str] = ... + self, prefix: str, viewset: type[ViewSetMixin], basename: str | None = ..., base_name: str | None = ... ) -> None: ... - def get_default_basename(self, viewset: Type[ViewSetMixin]) -> str: ... - def get_urls(self) -> List[_AnyURL]: ... + def get_default_basename(self, viewset: type[ViewSetMixin]) -> str: ... + def get_urls(self) -> list[_AnyURL]: ... @property - def urls(self) -> List[_AnyURL]: ... + def urls(self) -> list[_AnyURL]: ... class SimpleRouter(BaseRouter): - routes: List[Union[Route, DynamicRoute]] = ... + routes: list[Route | DynamicRoute] trailing_slash: str def __init__(self, trailing_slash: bool = ...) -> None: ... - def get_routes(self, viewset: Type[ViewSetMixin]) -> List[Route]: ... + def get_routes(self, viewset: type[ViewSetMixin]) -> list[Route]: ... def _get_dynamic_route(self, route: DynamicRoute, action: Any) -> Route: ... - def get_method_map(self, viewset: Type[ViewSetMixin], method_map: Mapping[str, str]) -> Dict[str, str]: ... - def get_lookup_regex(self, viewset: Type[ViewSetMixin], lookup_prefix: str = ...) -> str: ... + def get_method_map(self, viewset: type[ViewSetMixin], method_map: Mapping[str, str]) -> dict[str, str]: ... + def get_lookup_regex(self, viewset: type[ViewSetMixin], lookup_prefix: str = ...) -> str: ... class APIRootView(views.APIView): - _ignore_model_permissions: bool = ... - api_root_dict: Optional[Dict[str, str]] = ... + _ignore_model_permissions: bool + api_root_dict: dict[str, str] | None def get(self, request: Request, *args: Any, **kwargs: Any) -> Response: ... class DefaultRouter(SimpleRouter): - include_root_view: bool = ... - include_format_suffixes: bool = ... - root_view_name: str = ... - default_schema_renderers = None + include_root_view: bool + include_format_suffixes: bool + root_view_name: str + default_schema_renderers: Any APIRootView = APIRootView APISchemaView = SchemaView SchemaGenerator = SchemaGenerator - root_renderers: List[Type[BaseRenderer]] + root_renderers: list[type[BaseRenderer]] def __init__(self, *args: Any, **kwargs: Any) -> None: ... - def get_api_root_view(self, api_urls: Optional[Any] = ...) -> Callable: ... + def get_api_root_view(self, api_urls: Any | None = ...) -> Callable: ... diff --git a/rest_framework-stubs/schemas/__init__.pyi b/rest_framework-stubs/schemas/__init__.pyi index b1eb8f165..9a335862e 100644 --- a/rest_framework-stubs/schemas/__init__.pyi +++ b/rest_framework-stubs/schemas/__init__.pyi @@ -1,4 +1,5 @@ -from typing import Any, Callable, Optional, Sequence, Type +from collections.abc import Callable, Sequence +from typing import Any from rest_framework.renderers import BaseRenderer from rest_framework.urlpatterns import _AnyURL @@ -12,15 +13,15 @@ from .generators import BaseSchemaGenerator from .inspectors import DefaultSchema as DefaultSchema def get_schema_view( - title: Optional[str] = ..., - url: Optional[str] = ..., - description: Optional[str] = ..., - urlconf: Optional[str] = ..., - renderer_classes: Optional[Sequence[Type[BaseRenderer]]] = ..., + title: str | None = ..., + url: str | None = ..., + description: str | None = ..., + urlconf: str | None = ..., + renderer_classes: Sequence[type[BaseRenderer]] | None = ..., public: bool = ..., - patterns: Optional[Sequence[_AnyURL]] = ..., - generator_class: Type[BaseSchemaGenerator] = ..., + patterns: Sequence[_AnyURL] | None = ..., + generator_class: type[BaseSchemaGenerator] = ..., authentication_classes: Sequence[str] = ..., permission_classes: Sequence[str] = ..., - version: Optional[str] = ..., + version: str | None = ..., ) -> Callable[..., Any]: ... diff --git a/rest_framework-stubs/schemas/coreapi.pyi b/rest_framework-stubs/schemas/coreapi.pyi index f20737e2e..554b95f4a 100644 --- a/rest_framework-stubs/schemas/coreapi.pyi +++ b/rest_framework-stubs/schemas/coreapi.pyi @@ -1,5 +1,6 @@ from collections import Counter, OrderedDict -from typing import Any, Dict, Iterable, List, Optional, Sequence, Tuple +from collections.abc import Iterable, Sequence +from typing import Any from rest_framework.compat import coreapi from rest_framework.fields import Field @@ -17,47 +18,47 @@ def distribute_links(obj: Any) -> None: ... INSERT_INTO_COLLISION_FMT: str class LinkNode(OrderedDict): - links: List[Any] = ... - methods_counter: Counter = ... + links: list[Any] + methods_counter: Counter def __init__(self) -> None: ... def get_available_key(self, preferred_key: str) -> str: ... def insert_into(target: LinkNode, keys: Sequence[str], value: Any) -> None: ... class SchemaGenerator(BaseSchemaGenerator): - default_mapping: Dict[str, str] = ... - coerce_method_names: Optional[Dict[str, str]] = ... + default_mapping: dict[str, str] + coerce_method_names: dict[str, str] | None def __init__( self, - urlconf: Optional[str] = ..., - title: Optional[str] = ..., - description: Optional[str] = ..., - version: Optional[str] = ..., - patterns: Optional[Sequence[_AnyURL]] = ..., - url: Optional[str] = ..., - endpoints: Optional[Sequence[Tuple[str, str, Any]]] = ..., + urlconf: str | None = ..., + title: str | None = ..., + description: str | None = ..., + version: str | None = ..., + patterns: Sequence[_AnyURL] | None = ..., + url: str | None = ..., + endpoints: Sequence[tuple[str, str, Any]] | None = ..., ) -> None: ... - def get_links(self, request: Optional[Request] = ...) -> Optional[LinkNode]: ... - def get_schema(self, request: Optional[Request] = ..., public: bool = ...) -> Optional[coreapi.Document]: ... - def get_keys(self, subpath: Any, method: Any, view: APIView) -> List[str]: ... - def determine_path_prefix(self, paths: List[str]) -> str: ... + def get_links(self, request: Request | None = ...) -> LinkNode | None: ... + def get_schema(self, request: Request | None = ..., public: bool = ...) -> coreapi.Document | None: ... + def get_keys(self, subpath: Any, method: Any, view: APIView) -> list[str]: ... + def determine_path_prefix(self, paths: list[str]) -> str: ... def field_to_schema(field: Field): ... class AutoSchema(ViewInspector): - def __init__(self, manual_fields: Optional[List[coreapi.Field]] = ...) -> None: ... + def __init__(self, manual_fields: list[coreapi.Field] | None = ...) -> None: ... def get_link(self, path: str, method: str, base_url: str) -> coreapi.Link: ... - def get_path_fields(self, path: str, method: str) -> List[coreapi.Field]: ... - def get_serializer_fields(self, path: str, method: str) -> List[coreapi.Field]: ... - def get_pagination_fields(self, path: str, method: str) -> Dict[str, Any]: ... - def get_filter_fields(self, path: str, method: str) -> List[Dict[str, Any]]: ... - def get_manual_fields(self, path: str, method: str) -> List[coreapi.Field]: ... + def get_path_fields(self, path: str, method: str) -> list[coreapi.Field]: ... + def get_serializer_fields(self, path: str, method: str) -> list[coreapi.Field]: ... + def get_pagination_fields(self, path: str, method: str) -> dict[str, Any]: ... + def get_filter_fields(self, path: str, method: str) -> list[dict[str, Any]]: ... + def get_manual_fields(self, path: str, method: str) -> list[coreapi.Field]: ... @staticmethod - def update_fields(fields: List[coreapi.Field], update_with: List[coreapi.Field]) -> List[coreapi.Field]: ... + def update_fields(fields: list[coreapi.Field], update_with: list[coreapi.Field]) -> list[coreapi.Field]: ... def get_encoding(self, path: str, method: str) -> str: ... class ManualSchema(ViewInspector): - def __init__(self, fields: List[coreapi.Field], description: str = ..., encoding: Optional[str] = ...) -> None: ... + def __init__(self, fields: list[coreapi.Field], description: str = ..., encoding: str | None = ...) -> None: ... def get_link(self, path: str, method: str, base_url: str) -> coreapi.Link: ... def is_enabled() -> bool: ... diff --git a/rest_framework-stubs/schemas/generators.pyi b/rest_framework-stubs/schemas/generators.pyi index 6a71e76ad..006df7d8e 100644 --- a/rest_framework-stubs/schemas/generators.pyi +++ b/rest_framework-stubs/schemas/generators.pyi @@ -1,5 +1,7 @@ from types import ModuleType -from typing import Any, Iterable, List, Optional, Sequence, Tuple, Type, Union +from collections.abc import Iterable, Sequence +from typing import Any +from typing_extensions import TypeAlias from django.db.models.base import Model from rest_framework.compat import coreapi @@ -8,45 +10,43 @@ from rest_framework.urlpatterns import _AnyURL from rest_framework.views import APIView def common_path(paths: Iterable[str]) -> str: ... -def get_pk_name(model: Type[Model]) -> str: ... +def get_pk_name(model: type[Model]) -> str: ... def is_api_view(callback: Any) -> bool: ... -_APIEndpoint = Tuple[str, str, Any] +_APIEndpoint: TypeAlias = tuple[str, str, Any] class EndpointEnumerator: - patterns: Optional[Sequence[_AnyURL]] + patterns: Sequence[_AnyURL] | None def __init__( self, - patterns: Optional[Sequence[_AnyURL]] = ..., - urlconf: Union[str, ModuleType, None] = ..., + patterns: Sequence[_AnyURL] | None = ..., + urlconf: str | ModuleType | None = ..., ) -> None: ... - def get_api_endpoints( - self, patterns: Optional[Iterable[_AnyURL]] = ..., prefix: str = ... - ) -> List[_APIEndpoint]: ... + def get_api_endpoints(self, patterns: Iterable[_AnyURL] | None = ..., prefix: str = ...) -> list[_APIEndpoint]: ... def get_path_from_regex(self, path_regex: str) -> str: ... def should_include_endpoint(self, path: str, callback: Any) -> bool: ... - def get_allowed_methods(self, callback: Any) -> List[str]: ... + def get_allowed_methods(self, callback: Any) -> list[str]: ... class BaseSchemaGenerator: - endpoint_inspector_cls: Type[EndpointEnumerator] = ... - coerce_path_pk: Optional[bool] = ... - patterns: Optional[Sequence[_AnyURL]] = ... - urlconf: Optional[str] = ... - title: Optional[str] = ... - description: Optional[str] = ... - version: Optional[str] = ... - url: Optional[str] = ... - endpoints: Optional[Sequence[_APIEndpoint]] = ... + endpoint_inspector_cls: type[EndpointEnumerator] + coerce_path_pk: bool | None + patterns: Sequence[_AnyURL] | None + urlconf: str | None + title: str | None + description: str | None + version: str | None + url: str | None + endpoints: Sequence[_APIEndpoint] | None def __init__( self, - title: Optional[str] = ..., - url: Optional[str] = ..., - description: Optional[str] = ..., - patterns: Optional[Sequence[_AnyURL]] = ..., - urlconf: Optional[str] = ..., - version: Optional[str] = ..., + title: str | None = ..., + url: str | None = ..., + description: str | None = ..., + patterns: Sequence[_AnyURL] | None = ..., + urlconf: str | None = ..., + version: str | None = ..., ) -> None: ... - def create_view(self, callback: Any, method: str, request: Optional[Request] = ...) -> Any: ... + def create_view(self, callback: Any, method: str, request: Request | None = ...) -> Any: ... def coerce_path(self, path: str, method: str, view: APIView) -> str: ... - def get_schema(self, request: Optional[Request] = ..., public: bool = ...) -> Optional[coreapi.Document]: ... + def get_schema(self, request: Request | None = ..., public: bool = ...) -> coreapi.Document | None: ... def has_view_permissions(self, path: str, method: str, view: APIView) -> bool: ... diff --git a/rest_framework-stubs/schemas/inspectors.pyi b/rest_framework-stubs/schemas/inspectors.pyi index a4a00c25f..444a82c84 100644 --- a/rest_framework-stubs/schemas/inspectors.pyi +++ b/rest_framework-stubs/schemas/inspectors.pyi @@ -1,8 +1,10 @@ -from typing import Any, Mapping, Pattern +from collections.abc import Mapping +from re import Pattern +from typing import Any class ViewInspector: - header_regex: Pattern = ... - instance_schemas: Mapping[str, Any] = ... + header_regex: Pattern + instance_schemas: Mapping[str, Any] def __init__(self) -> None: ... def __get__(self, instance: Any, owner: Any): ... def __set__(self, instance: Any, other: Any) -> None: ... diff --git a/rest_framework-stubs/schemas/openapi.pyi b/rest_framework-stubs/schemas/openapi.pyi index bb709eb5a..f02a90404 100644 --- a/rest_framework-stubs/schemas/openapi.pyi +++ b/rest_framework-stubs/schemas/openapi.pyi @@ -1,4 +1,5 @@ -from typing import Any, Dict, List, Optional, Sequence, Type +from collections.abc import Sequence +from typing import Any from rest_framework.fields import Field from rest_framework.pagination import BasePagination @@ -24,44 +25,44 @@ class ExternalDocumentationObject(TypedDict, total=False): class DRFOpenAPISchema(TypedDict, total=False): openapi: str info: DRFOpenAPIInfo - paths: Dict[str, Dict[str, Any]] - components: Dict[str, Dict[str, Any]] - security: List[Dict[str, List[Any]]] - tags: List[Dict[str, Any]] + paths: dict[str, dict[str, Any]] + components: dict[str, dict[str, Any]] + security: list[dict[str, list[Any]]] + tags: list[dict[str, Any]] externalDocs: ExternalDocumentationObject - servers: List[Dict[str, Any]] + servers: list[dict[str, Any]] class SchemaGenerator(BaseSchemaGenerator): def get_info(self) -> DRFOpenAPIInfo: ... - def check_duplicate_operation_id(self, paths: Dict[str, Dict[str, Any]]) -> None: ... + def check_duplicate_operation_id(self, paths: dict[str, dict[str, Any]]) -> None: ... def get_schema(self, request: Request = ..., public: bool = ...) -> DRFOpenAPISchema: ... # type: ignore[override] class AutoSchema(ViewInspector): - operation_id_base: Optional[str] = ... - component_name: Optional[str] = ... - request_media_types: List[str] = ... - response_media_types: List[str] = ... - method_mapping: Dict[str, str] = ... + operation_id_base: str | None + component_name: str | None + request_media_types: list[str] + response_media_types: list[str] + method_mapping: dict[str, str] def __init__( - self, tags: Sequence[str] = ..., operation_id_base: Optional[str] = ..., component_name: Optional[str] = ... + self, tags: Sequence[str] = ..., operation_id_base: str | None = ..., component_name: str | None = ... ) -> None: ... - def get_operation(self, path: str, method: str) -> Dict[str, Any]: ... + def get_operation(self, path: str, method: str) -> dict[str, Any]: ... def get_component_name(self, serializer: BaseSerializer) -> str: ... - def get_components(self, path: str, method: str) -> Dict[str, Any]: ... + def get_components(self, path: str, method: str) -> dict[str, Any]: ... def get_operation_id_base(self, path: str, method: str, action: Any) -> str: ... def get_operation_id(self, path: str, method: str) -> str: ... - def get_path_parameters(self, path: str, method: str) -> List[Dict[str, Any]]: ... - def get_filter_parameters(self, path: str, method: str) -> List[Dict[str, Any]]: ... + def get_path_parameters(self, path: str, method: str) -> list[dict[str, Any]]: ... + def get_filter_parameters(self, path: str, method: str) -> list[dict[str, Any]]: ... def allows_filters(self, path: str, method: str) -> bool: ... - def get_pagination_parameters(self, path: str, method: str) -> List[Dict[str, Any]]: ... - def map_choicefield(self, field: Field) -> Dict[str, Any]: ... - def map_field(self, field: Field) -> Dict[str, Any]: ... - def map_serializer(self, serializer: BaseSerializer) -> Dict[str, Any]: ... + def get_pagination_parameters(self, path: str, method: str) -> list[dict[str, Any]]: ... + def map_choicefield(self, field: Field) -> dict[str, Any]: ... + def map_field(self, field: Field) -> dict[str, Any]: ... + def map_serializer(self, serializer: BaseSerializer) -> dict[str, Any]: ... def map_field_validators(self, field: Any, schema: Any) -> None: ... - def get_paginator(self) -> Optional[Type[BasePagination]]: ... - def map_parsers(self, path: str, method: str) -> List[str]: ... - def map_renderers(self, path: str, method: str) -> List[str]: ... - def get_serializer(self, path: str, method: str) -> Optional[BaseSerializer]: ... - def get_request_body(self, path: str, method: str) -> Dict[str, Any]: ... - def get_responses(self, path: str, method: str) -> Dict[str, Any]: ... - def get_tags(self, path: str, method: str) -> List[str]: ... + def get_paginator(self) -> type[BasePagination] | None: ... + def map_parsers(self, path: str, method: str) -> list[str]: ... + def map_renderers(self, path: str, method: str) -> list[str]: ... + def get_serializer(self, path: str, method: str) -> BaseSerializer | None: ... + def get_request_body(self, path: str, method: str) -> dict[str, Any]: ... + def get_responses(self, path: str, method: str) -> dict[str, Any]: ... + def get_tags(self, path: str, method: str) -> list[str]: ... diff --git a/rest_framework-stubs/schemas/utils.pyi b/rest_framework-stubs/schemas/utils.pyi index e8a1326c5..cc7a77576 100644 --- a/rest_framework-stubs/schemas/utils.pyi +++ b/rest_framework-stubs/schemas/utils.pyi @@ -1,8 +1,6 @@ -from typing import Type - from django.db.models import Model from rest_framework.fields import Field from rest_framework.views import APIView def is_list_view(path: str, method: str, view: APIView) -> bool: ... -def get_pk_description(model: Type[Model], model_field: Field) -> str: ... +def get_pk_description(model: type[Model], model_field: Field) -> str: ... diff --git a/rest_framework-stubs/schemas/views.pyi b/rest_framework-stubs/schemas/views.pyi index e9865729b..288d20485 100644 --- a/rest_framework-stubs/schemas/views.pyi +++ b/rest_framework-stubs/schemas/views.pyi @@ -1,9 +1,7 @@ -from typing import Optional - from rest_framework.schemas import SchemaGenerator from rest_framework.views import APIView class SchemaView(APIView): - _ignore_model_permissions: bool = ... - public: bool = ... - schema_generator: Optional[SchemaGenerator] = ... + _ignore_model_permissions: bool + public: bool + schema_generator: SchemaGenerator | None diff --git a/rest_framework-stubs/serializers.pyi b/rest_framework-stubs/serializers.pyi index 838d656e1..d17daccc3 100644 --- a/rest_framework-stubs/serializers.pyi +++ b/rest_framework-stubs/serializers.pyi @@ -1,21 +1,6 @@ -from typing import ( - Any, - Callable, - Dict, - Generic, - Iterable, - Iterator, - List, - Mapping, - MutableMapping, - NoReturn, - Optional, - Sequence, - Tuple, - Type, - TypeVar, - Union, -) +from collections.abc import Callable, Iterable, Iterator, Mapping, MutableMapping, Sequence +from typing import Any, Generic, NoReturn, TypeVar +from _typeshed import Self from django.core.exceptions import ValidationError as DjangoValidationError from django.db import models @@ -84,8 +69,8 @@ from rest_framework.utils.model_meta import FieldInfo, RelationInfo from rest_framework.utils.serializer_helpers import BindingDict, BoundField, ReturnDict, ReturnList from rest_framework.validators import Validator, UniqueTogetherValidator, BaseUniqueForValidator -LIST_SERIALIZER_KWARGS: Sequence[str] = ... -ALL_FIELDS: str = ... +LIST_SERIALIZER_KWARGS: Sequence[str] +ALL_FIELDS: str _MT = TypeVar("_MT", bound=Model) # Model Type _IN = TypeVar("_IN") # Instance Type @@ -93,19 +78,19 @@ _IN = TypeVar("_IN") # Instance Type class BaseSerializer(Generic[_IN], Field[Any, Any, Any, _IN]): partial: bool many: bool - instance: Optional[_IN] + instance: _IN | None initial_data: Any - _context: Dict[str, Any] - def __new__(cls, *args: Any, **kwargs: Any) -> BaseSerializer: ... + _context: dict[str, Any] + def __new__(cls: type[Self], *args: Any, **kwargs: Any) -> Self: ... def __class_getitem__(cls, *args, **kwargs): ... def __init__( self, - instance: Optional[_IN] = ..., + instance: _IN | None = ..., data: Any = ..., partial: bool = ..., many: bool = ..., allow_empty: bool = ..., - context: Dict[str, Any] = ..., + context: dict[str, Any] = ..., read_only: bool = ..., write_only: bool = ..., required: bool = ..., @@ -114,9 +99,9 @@ class BaseSerializer(Generic[_IN], Field[Any, Any, Any, _IN]): source: str = ..., label: str = ..., help_text: str = ..., - style: Dict[str, Any] = ..., - error_messages: Dict[str, str] = ..., - validators: Optional[Sequence[Validator[Any]]] = ..., + style: dict[str, Any] = ..., + error_messages: dict[str, str] = ..., + validators: Sequence[Validator[Any]] | None = ..., allow_null: bool = ..., ): ... @classmethod @@ -136,9 +121,9 @@ class BaseSerializer(Generic[_IN], Field[Any, Any, Any, _IN]): class SerializerMetaclass(type): def __new__(cls, name: Any, bases: Any, attrs: Any): ... @classmethod - def _get_declared_fields(cls, bases: Sequence[type], attrs: Dict[str, Any]) -> Dict[str, Field]: ... + def _get_declared_fields(cls, bases: Sequence[type], attrs: dict[str, Any]) -> dict[str, Field]: ... -def as_serializer_error(exc: Exception) -> Dict[str, List[ErrorDetail]]: ... +def as_serializer_error(exc: Exception) -> dict[str, list[ErrorDetail]]: ... class Serializer( BaseSerializer[ @@ -146,20 +131,20 @@ class Serializer( ], metaclass=SerializerMetaclass, ): - _declared_fields: Dict[str, Field] - default_error_messages: Dict[str, Any] = ... + _declared_fields: dict[str, Field] + default_error_messages: dict[str, Any] def get_initial(self) -> Any: ... @cached_property def fields(self) -> BindingDict: ... - def get_fields(self) -> Dict[str, Field]: ... + def get_fields(self) -> dict[str, Field]: ... def validate(self, attrs: Any) -> Any: ... def __iter__(self) -> Iterator[BoundField]: ... def __getitem__(self, key: str) -> BoundField: ... - def _read_only_defaults(self) -> Dict[str, Any]: ... + def _read_only_defaults(self) -> dict[str, Any]: ... @property - def _writable_fields(self) -> List[Field]: ... + def _writable_fields(self) -> list[Field]: ... @property - def _readable_fields(self) -> List[Field]: ... + def _readable_fields(self) -> list[Field]: ... @property def data(self) -> ReturnDict: ... @property @@ -168,28 +153,18 @@ class Serializer( class ListSerializer( BaseSerializer[_IN], ): - child: Optional[ - Union[ - Field, - BaseSerializer, - ] - ] = ... - many: bool = ... - default_error_messages: Dict[str, Any] = ... - allow_empty: Optional[bool] = ... + child: Field | BaseSerializer | None + many: bool + default_error_messages: dict[str, Any] + allow_empty: bool | None def __init__( self, - instance: Optional[_IN] = ..., + instance: _IN | None = ..., data: Any = ..., partial: bool = ..., - context: Dict[str, Any] = ..., + context: dict[str, Any] = ..., allow_empty: bool = ..., - child: Optional[ - Union[ - Field, - BaseSerializer, - ] - ] = ..., + child: Field | BaseSerializer | None = ..., read_only: bool = ..., write_only: bool = ..., required: bool = ..., @@ -198,12 +173,12 @@ class ListSerializer( source: str = ..., label: str = ..., help_text: str = ..., - style: Dict[str, Any] = ..., - error_messages: Dict[str, str] = ..., - validators: Optional[Sequence[Validator[List[Any]]]] = ..., + style: dict[str, Any] = ..., + error_messages: dict[str, str] = ..., + validators: Sequence[Validator[list[Any]]] | None = ..., allow_null: bool = ..., ): ... - def get_initial(self) -> List[Mapping[Any, Any]]: ... + def get_initial(self) -> list[Mapping[Any, Any]]: ... def validate(self, attrs: Any) -> Any: ... @property def data(self) -> ReturnList: ... @@ -213,39 +188,39 @@ class ListSerializer( def raise_errors_on_nested_writes(method_name: str, serializer: BaseSerializer, validated_data: Any) -> None: ... class ModelSerializer(Serializer, BaseSerializer[_MT]): - serializer_field_mapping: Dict[Type[models.Field], Type[Field]] = ... - serializer_related_field: Type[RelatedField] = ... - serializer_related_to_field: Type[RelatedField] = ... - serializer_url_field: Type[RelatedField] = ... - serializer_choice_field: Type[Field] = ... - url_field_name: Optional[str] = ... - instance: Optional[Union[_MT, Sequence[_MT]]] # type: ignore[override] + serializer_field_mapping: dict[type[models.Field], type[Field]] + serializer_related_field: type[RelatedField] + serializer_related_to_field: type[RelatedField] + serializer_url_field: type[RelatedField] + serializer_choice_field: type[Field] + url_field_name: str | None + instance: _MT | Sequence[_MT] | None # type: ignore[override] class Meta: - model: Type[_MT] # type: ignore - fields: Union[Sequence[str], Literal["__all__"]] - read_only_fields: Optional[Sequence[str]] - exclude: Optional[Sequence[str]] - depth: Optional[int] - extra_kwargs: Dict[str, Dict[str, Any]] # type: ignore[override] + model: type[_MT] # type: ignore + fields: Sequence[str] | Literal["__all__"] + read_only_fields: Sequence[str] | None + exclude: Sequence[str] | None + depth: int | None + extra_kwargs: dict[str, dict[str, Any]] # type: ignore[override] def __init__( self, - instance: Union[None, _MT, Sequence[_MT], QuerySet[_MT], Manager[_MT]] = ..., + instance: None | _MT | Sequence[_MT] | QuerySet[_MT] | Manager[_MT] = ..., data: Any = ..., partial: bool = ..., many: bool = ..., - context: Dict[str, Any] = ..., + context: dict[str, Any] = ..., read_only: bool = ..., write_only: bool = ..., required: bool = ..., - default: Union[Union[_MT, Sequence[_MT]], Callable[[], Union[_MT, Sequence[_MT]]]] = ..., - initial: Union[Union[_MT, Sequence[_MT]], Callable[[], Union[_MT, Sequence[_MT]]]] = ..., + default: _MT | Sequence[_MT] | Callable[[], _MT | Sequence[_MT]] = ..., + initial: _MT | Sequence[_MT] | Callable[[], _MT | Sequence[_MT]] = ..., source: str = ..., label: str = ..., help_text: str = ..., - style: Dict[str, Any] = ..., - error_messages: Dict[str, str] = ..., - validators: Optional[Sequence[Validator[_MT]]] = ..., + style: dict[str, Any] = ..., + error_messages: dict[str, str] = ..., + validators: Sequence[Validator[_MT]] | None = ..., allow_null: bool = ..., allow_empty: bool = ..., ): ... @@ -253,34 +228,34 @@ class ModelSerializer(Serializer, BaseSerializer[_MT]): def create(self, validated_data: Any) -> _MT: ... # type: ignore[override] def save(self, **kwargs: Any) -> _MT: ... # type: ignore[override] def to_representation(self, instance: _MT) -> Any: ... # type: ignore[override] - def get_field_names(self, declared_fields: Mapping[str, Field], info: FieldInfo) -> List[str]: ... - def get_default_field_names(self, declared_fields: Mapping[str, Field], model_info: FieldInfo) -> List[str]: ... + def get_field_names(self, declared_fields: Mapping[str, Field], info: FieldInfo) -> list[str]: ... + def get_default_field_names(self, declared_fields: Mapping[str, Field], model_info: FieldInfo) -> list[str]: ... def build_field( self, field_name: str, info: FieldInfo, model_class: _MT, nested_depth: int - ) -> Tuple[Type[Field], Dict[str, Any]]: ... + ) -> tuple[type[Field], dict[str, Any]]: ... def build_standard_field( - self, field_name: str, model_field: Type[models.Field] - ) -> Tuple[Type[Field], Dict[str, Any]]: ... + self, field_name: str, model_field: type[models.Field] + ) -> tuple[type[Field], dict[str, Any]]: ... def build_relational_field( self, field_name: str, relation_info: RelationInfo - ) -> Tuple[Type[Field], Dict[str, Any]]: ... + ) -> tuple[type[Field], dict[str, Any]]: ... def build_nested_field( self, field_name: str, relation_info: RelationInfo, nested_depth: int - ) -> Tuple[Type[Field], Dict[str, Any]]: ... - def build_property_field(self, field_name: str, model_class: _MT) -> Tuple[Type[Field], Dict[str, Any]]: ... - def build_url_field(self, field_name: str, model_class: _MT) -> Tuple[Type[Field], Dict[str, Any]]: ... + ) -> tuple[type[Field], dict[str, Any]]: ... + def build_property_field(self, field_name: str, model_class: _MT) -> tuple[type[Field], dict[str, Any]]: ... + def build_url_field(self, field_name: str, model_class: _MT) -> tuple[type[Field], dict[str, Any]]: ... def build_unknown_field(self, field_name: str, model_class: _MT) -> NoReturn: ... def include_extra_kwargs( self, kwargs: MutableMapping[str, Any], extra_kwargs: MutableMapping[str, Any] ) -> MutableMapping[str, Any]: ... - def get_extra_kwargs(self) -> Dict[str, Any]: ... + def get_extra_kwargs(self) -> dict[str, Any]: ... def get_uniqueness_extra_kwargs( - self, field_names: Iterable[str], declared_fields: Mapping[str, Field], extra_kwargs: Dict[str, Any] - ) -> Tuple[Dict[str, Any], Dict[str, HiddenField]]: ... + self, field_names: Iterable[str], declared_fields: Mapping[str, Field], extra_kwargs: dict[str, Any] + ) -> tuple[dict[str, Any], dict[str, HiddenField]]: ... def _get_model_fields( self, field_names: Iterable[str], declared_fields: Mapping[str, Field], extra_kwargs: MutableMapping[str, Any] - ) -> Dict[str, models.Field]: ... - def get_unique_together_validators(self) -> List[UniqueTogetherValidator]: ... - def get_unique_for_date_validators(self) -> List[BaseUniqueForValidator]: ... + ) -> dict[str, models.Field]: ... + def get_unique_together_validators(self) -> list[UniqueTogetherValidator]: ... + def get_unique_for_date_validators(self) -> list[BaseUniqueForValidator]: ... class HyperlinkedModelSerializer(ModelSerializer): ... diff --git a/rest_framework-stubs/settings.pyi b/rest_framework-stubs/settings.pyi index 831626780..a508b5b5b 100644 --- a/rest_framework-stubs/settings.pyi +++ b/rest_framework-stubs/settings.pyi @@ -1,4 +1,5 @@ -from typing import Any, Callable, Dict, Mapping, Optional, Sequence, Union +from collections.abc import Callable, Mapping, Sequence +from typing import Any from typing_extensions import TypedDict @@ -10,23 +11,23 @@ class DefaultsSettings(TypedDict, total=False): DEFAULT_THROTTLE_CLASSES: Sequence[str] DEFAULT_CONTENT_NEGOTIATION_CLASS: str DEFAULT_METADATA_CLASS: str - DEFAULT_VERSIONING_CLASS: Optional[str] - DEFAULT_PAGINATION_CLASS: Optional[str] + DEFAULT_VERSIONING_CLASS: str | None + DEFAULT_PAGINATION_CLASS: str | None DEFAULT_FILTER_BACKENDS: Sequence[str] DEFAULT_SCHEMA_CLASS: str - DEFAULT_THROTTLE_RATES: Dict[str, Optional[Union[float, int]]] - NUM_PROXIES: Optional[int] - PAGE_SIZE: Optional[int] + DEFAULT_THROTTLE_RATES: dict[str, float | int | None] + NUM_PROXIES: int | None + PAGE_SIZE: int | None SEARCH_PARAM: str ORDERING_PARAM: str - DEFAULT_VERSION: Optional[str] - ALLOWED_VERSIONS: Optional[str] + DEFAULT_VERSION: str | None + ALLOWED_VERSIONS: str | None VERSION_PARAM: str UNAUTHENTICATED_USER: str - UNAUTHENTICATED_TOKEN: Optional[str] + UNAUTHENTICATED_TOKEN: str | None VIEW_NAME_FUNCTION: str VIEW_DESCRIPTION_FUNCTION: str - EXCEPTION_HANDLER: Union[str, Callable[[Any, Any], Any]] + EXCEPTION_HANDLER: str | Callable[[Any, Any], Any] NON_FIELD_ERRORS_KEY: str TEST_REQUEST_RENDERER_CLASSES: Sequence[str] TEST_REQUEST_DEFAULT_FORMAT: str @@ -47,23 +48,23 @@ class DefaultsSettings(TypedDict, total=False): HTML_SELECT_CUTOFF: int HTML_SELECT_CUTOFF_TEXT: str SCHEMA_COERCE_PATH_PK: bool - SCHEMA_COERCE_METHOD_NAMES: Dict[str, str] + SCHEMA_COERCE_METHOD_NAMES: dict[str, str] -DEFAULTS: DefaultsSettings = ... -IMPORT_STRINGS: Sequence[str] = ... -REMOVED_SETTINGS: Sequence[str] = ... +DEFAULTS: DefaultsSettings +IMPORT_STRINGS: Sequence[str] +REMOVED_SETTINGS: Sequence[str] -def perform_import(val: Optional[Any], setting_name: str) -> Optional[Any]: ... -def import_from_string(val: Optional[Any], setting_name: str) -> Any: ... +def perform_import(val: Any | None, setting_name: str) -> Any | None: ... +def import_from_string(val: Any | None, setting_name: str) -> Any: ... class APISettings: defaults: DefaultsSettings import_strings: Sequence[str] def __init__( self, - user_settings: Optional[DefaultsSettings] = ..., - defaults: Optional[DefaultsSettings] = ..., - import_strings: Optional[Sequence[str]] = ..., + user_settings: DefaultsSettings | None = ..., + defaults: DefaultsSettings | None = ..., + import_strings: Sequence[str] | None = ..., ): ... @property def user_settings(self) -> Mapping[str, Any]: ... @@ -72,52 +73,52 @@ class APISettings: def reload(self) -> None: ... class _Settings(APISettings): - DEFAULT_RENDERER_CLASSES: Sequence[str] = ... - DEFAULT_PARSER_CLASSES: Sequence[str] = ... - DEFAULT_AUTHENTICATION_CLASSES: Sequence[str] = ... - DEFAULT_PERMISSION_CLASSES: Sequence[str] = ... - DEFAULT_THROTTLE_CLASSES: Sequence[str] = ... - DEFAULT_CONTENT_NEGOTIATION_CLASS: str = ... - DEFAULT_METADATA_CLASS: str = ... - DEFAULT_VERSIONING_CLASS: Optional[str] = ... - DEFAULT_PAGINATION_CLASS: Optional[str] = ... - DEFAULT_FILTER_BACKENDS: Sequence[str] = ... - DEFAULT_SCHEMA_CLASS: str = ... - DEFAULT_THROTTLE_RATES: Dict[str, Optional[Union[float, int]]] = ... - NUM_PROXIES: Optional[int] = ... - PAGE_SIZE: Optional[int] = ... - SEARCH_PARAM: str = ... - ORDERING_PARAM: str = ... - DEFAULT_VERSION: Optional[str] = ... - ALLOWED_VERSIONS: Optional[str] = ... - VERSION_PARAM: str = ... - UNAUTHENTICATED_USER: str = ... - UNAUTHENTICATED_TOKEN: Optional[str] = ... - VIEW_NAME_FUNCTION: str = ... - VIEW_DESCRIPTION_FUNCTION: str = ... - EXCEPTION_HANDLER: Union[str, Callable[[Any, Any], Any]] = ... - NON_FIELD_ERRORS_KEY: str = ... - TEST_REQUEST_RENDERER_CLASSES: Sequence[str] = ... - TEST_REQUEST_DEFAULT_FORMAT: str = ... - URL_FORMAT_OVERRIDE: str = ... - FORMAT_SUFFIX_KWARG: str = ... - URL_FIELD_NAME: str = ... - DATE_FORMAT: str = ... - DATE_INPUT_FORMATS: Sequence[str] = ... - DATETIME_FORMAT: str = ... - DATETIME_INPUT_FORMATS: Sequence[str] = ... - TIME_FORMAT: str = ... - TIME_INPUT_FORMATS: Sequence[str] = ... - UNICODE_JSON: bool = ... - COMPACT_JSON: bool = ... - STRICT_JSON: bool = ... - COERCE_DECIMAL_TO_STRING: bool = ... - UPLOADED_FILES_USE_URL: bool = ... - HTML_SELECT_CUTOFF: int = ... - HTML_SELECT_CUTOFF_TEXT: str = ... - SCHEMA_COERCE_PATH_PK: bool = ... - SCHEMA_COERCE_METHOD_NAMES: Dict[str, str] = ... + DEFAULT_RENDERER_CLASSES: Sequence[str] + DEFAULT_PARSER_CLASSES: Sequence[str] + DEFAULT_AUTHENTICATION_CLASSES: Sequence[str] + DEFAULT_PERMISSION_CLASSES: Sequence[str] + DEFAULT_THROTTLE_CLASSES: Sequence[str] + DEFAULT_CONTENT_NEGOTIATION_CLASS: str + DEFAULT_METADATA_CLASS: str + DEFAULT_VERSIONING_CLASS: str | None + DEFAULT_PAGINATION_CLASS: str | None + DEFAULT_FILTER_BACKENDS: Sequence[str] + DEFAULT_SCHEMA_CLASS: str + DEFAULT_THROTTLE_RATES: dict[str, float | int | None] + NUM_PROXIES: int | None + PAGE_SIZE: int | None + SEARCH_PARAM: str + ORDERING_PARAM: str + DEFAULT_VERSION: str | None + ALLOWED_VERSIONS: str | None + VERSION_PARAM: str + UNAUTHENTICATED_USER: str + UNAUTHENTICATED_TOKEN: str | None + VIEW_NAME_FUNCTION: str + VIEW_DESCRIPTION_FUNCTION: str + EXCEPTION_HANDLER: str | Callable[[Any, Any], Any] + NON_FIELD_ERRORS_KEY: str + TEST_REQUEST_RENDERER_CLASSES: Sequence[str] + TEST_REQUEST_DEFAULT_FORMAT: str + URL_FORMAT_OVERRIDE: str + FORMAT_SUFFIX_KWARG: str + URL_FIELD_NAME: str + DATE_FORMAT: str + DATE_INPUT_FORMATS: Sequence[str] + DATETIME_FORMAT: str + DATETIME_INPUT_FORMATS: Sequence[str] + TIME_FORMAT: str + TIME_INPUT_FORMATS: Sequence[str] + UNICODE_JSON: bool + COMPACT_JSON: bool + STRICT_JSON: bool + COERCE_DECIMAL_TO_STRING: bool + UPLOADED_FILES_USE_URL: bool + HTML_SELECT_CUTOFF: int + HTML_SELECT_CUTOFF_TEXT: str + SCHEMA_COERCE_PATH_PK: bool + SCHEMA_COERCE_METHOD_NAMES: dict[str, str] -api_settings: _Settings = ... +api_settings: _Settings def reload_api_settings(*args: Any, **kwargs: Any) -> None: ... diff --git a/rest_framework-stubs/templatetags/rest_framework.pyi b/rest_framework-stubs/templatetags/rest_framework.pyi index e0ebf7f01..f94b9b0b6 100644 --- a/rest_framework-stubs/templatetags/rest_framework.pyi +++ b/rest_framework-stubs/templatetags/rest_framework.pyi @@ -1,4 +1,4 @@ -from typing import Any, List, Optional, Union +from typing import Any from django import template from django.contrib.auth.base_user import AbstractBaseUser @@ -11,9 +11,9 @@ class_re: Any def highlight_code(parser: Any, token: Any): ... class CodeNode(template.Node): - style: str = ... - lang: Any = ... - nodelist: Any = ... + style: str + lang: Any + nodelist: Any def __init__(self, lang: Any, code: Any) -> None: ... def render(self, context: Any): ... @@ -21,19 +21,19 @@ def with_location(fields: Any, location: Any): ... def form_for_link(link: Any): ... def render_markdown(markdown_text: Any): ... def get_pagination_html(pager: Any): ... -def render_form(serializer: Any, template_pack: Optional[Any] = ...): ... +def render_form(serializer: Any, template_pack: Any | None = ...): ... def render_field(field: Any, style: Any): ... def optional_login(request: Request): ... def optional_docs_login(request: Request): ... -def optional_logout(request: Request, user: Union[AnonymousUser, AbstractBaseUser]): ... +def optional_logout(request: Request, user: AnonymousUser | AbstractBaseUser): ... def add_query_param(request: Request, key: str, val: Any): ... def as_string(value: Any) -> str: ... -def as_list_of_strings(value: Any) -> List[str]: ... +def as_list_of_strings(value: Any) -> list[str]: ... def add_class(value: Any, css_class: Any): ... def format_value(value: Any): ... def items(value: Any): ... def data(value: Any): ... -def schema_links(section: Any, sec_key: Optional[Any] = ...): ... +def schema_links(section: Any, sec_key: Any | None = ...): ... def add_nested_class(value: Any): ... TRAILING_PUNCTUATION: Any @@ -44,7 +44,5 @@ simple_url_2_re: Any simple_email_re: Any def smart_urlquote_wrapper(matched_url: Any): ... -def urlize_quoted_links( - text: Any, trim_url_limit: Optional[Any] = ..., nofollow: bool = ..., autoescape: bool = ... -): ... +def urlize_quoted_links(text: Any, trim_url_limit: Any | None = ..., nofollow: bool = ..., autoescape: bool = ...): ... def break_long_headers(header: Any): ... diff --git a/rest_framework-stubs/test.pyi b/rest_framework-stubs/test.pyi index 97e1130a5..56f30ed95 100644 --- a/rest_framework-stubs/test.pyi +++ b/rest_framework-stubs/test.pyi @@ -1,4 +1,4 @@ -from typing import Any, Dict, Optional, Type, Union +from typing import Any import coreapi import requests @@ -15,22 +15,22 @@ from rest_framework.request import Request from rest_framework.response import _MonkeyPatchedResponse def force_authenticate( - request: HttpRequest, user: Optional[Union[AnonymousUser, AbstractBaseUser]] = ..., token: Optional[Token] = ... + request: HttpRequest, user: AnonymousUser | AbstractBaseUser | None = ..., token: Token | None = ... ) -> None: ... class HeaderDict(urllib3._collections.HTTPHeaderDict): def get_all(self, key: Any, default: Any): ... class MockOriginalResponse: - msg: Any = ... - closed: bool = ... + msg: Any + closed: bool def __init__(self, headers: Any) -> None: ... def isclosed(self): ... def close(self) -> None: ... class DjangoTestAdapter(requests.adapters.HTTPAdapter): - app: Any = ... - factory: Any = ... + app: Any + factory: Any def __init__(self) -> None: ... def get_environ(self, request: Request): ... def send(self, request: Request, *args: Any, **kwargs: Any) -> requests.Response: ... # type: ignore[override] @@ -44,18 +44,18 @@ class CoreAPIClient(coreapi.Client): def session(self): ... class APIRequestFactory(DjangoRequestFactory): - renderer_classes_list: Any = ... - default_format: Any = ... - enforce_csrf_checks: Any = ... - renderer_classes: Any = ... + renderer_classes_list: Any + default_format: Any + enforce_csrf_checks: Any + renderer_classes: Any def __init__(self, enforce_csrf_checks: bool = ..., **defaults: Any) -> None: ... def request(self, **kwargs: Any) -> Request: ... # type: ignore[override] - def get(self, path: str, data: Optional[Union[Dict[str, Any], str]] = ..., follow: bool = ..., **extra: Any): ... # type: ignore[override] - def post(self, path: str, data: Optional[Any] = ..., format: Optional[str] = ..., content_type: Optional[str] = ..., follow: bool = ..., **extra: Any) -> Request: ... # type: ignore[override] - def put(self, path: str, data: Optional[Any] = ..., format: Optional[str] = ..., content_type: Optional[str] = ..., follow: bool = ..., **extra: Any) -> Request: ... # type: ignore[override] - def patch(self, path: str, data: Optional[Any] = ..., format: Optional[str] = ..., content_type: Optional[str] = ..., follow: bool = ..., **extra: Any) -> Request: ... # type: ignore[override] - def delete(self, path: str, data: Optional[Any] = ..., format: Optional[str] = ..., content_type: Optional[str] = ..., follow: bool = ..., **extra: Any) -> Request: ... # type: ignore[override] - def options(self, path: str, data: Union[Dict[str, str], str] = ..., format: Optional[str] = ..., content_type: Optional[Any] = ..., follow: bool = ..., **extra: Any) -> Request: ... # type: ignore[override] + def get(self, path: str, data: dict[str, Any] | str | None = ..., follow: bool = ..., **extra: Any): ... # type: ignore[override] + def post(self, path: str, data: Any | None = ..., format: str | None = ..., content_type: str | None = ..., follow: bool = ..., **extra: Any) -> Request: ... # type: ignore[override] + def put(self, path: str, data: Any | None = ..., format: str | None = ..., content_type: str | None = ..., follow: bool = ..., **extra: Any) -> Request: ... # type: ignore[override] + def patch(self, path: str, data: Any | None = ..., format: str | None = ..., content_type: str | None = ..., follow: bool = ..., **extra: Any) -> Request: ... # type: ignore[override] + def delete(self, path: str, data: Any | None = ..., format: str | None = ..., content_type: str | None = ..., follow: bool = ..., **extra: Any) -> Request: ... # type: ignore[override] + def options(self, path: str, data: dict[str, str] | str = ..., format: str | None = ..., content_type: Any | None = ..., follow: bool = ..., **extra: Any) -> Request: ... # type: ignore[override] def generic( # type: ignore[override] self, method: str, path: str, data: str = ..., content_type: str = ..., secure: bool = ..., **extra: Any ) -> Request: ... @@ -65,34 +65,31 @@ class ForceAuthClientHandler(ClientHandler): def get_response(self, request: Request) -> _MonkeyPatchedResponse: ... # type: ignore[override] class APIClient(APIRequestFactory, DjangoClient): - handler: Any = ... def credentials(self, **kwargs: Any): ... - def force_authenticate( - self, user: Union[AnonymousUser, AbstractBaseUser] = ..., token: Optional[Token] = ... - ) -> None: ... + def force_authenticate(self, user: AnonymousUser | AbstractBaseUser = ..., token: Token | None = ...) -> None: ... def request(self, **kwargs: Any) -> _MonkeyPatchedResponse: ... # type: ignore[override] - def get(self, path: str, data: Optional[Union[Dict[str, Any], str]] = ..., follow: bool = ..., **extra: Any): ... # type: ignore[override] - def post(self, path: str, data: Optional[Any] = ..., format: Optional[str] = ..., content_type: Optional[str] = ..., follow: bool = ..., **extra: Any) -> _MonkeyPatchedResponse: ... # type: ignore[override] - def put(self, path: str, data: Optional[Any] = ..., format: Optional[str] = ..., content_type: Optional[str] = ..., follow: bool = ..., **extra: Any) -> _MonkeyPatchedResponse: ... # type: ignore[override] - def patch(self, path: str, data: Optional[Any] = ..., format: Optional[str] = ..., content_type: Optional[str] = ..., follow: bool = ..., **extra: Any) -> _MonkeyPatchedResponse: ... # type: ignore[override] - def delete(self, path: str, data: Optional[Any] = ..., format: Optional[str] = ..., content_type: Optional[str] = ..., follow: bool = ..., **extra: Any) -> _MonkeyPatchedResponse: ... # type: ignore[override] - def options(self, path: str, data: Union[Dict[str, str], str] = ..., format: Optional[str] = ..., content_type: Optional[Any] = ..., follow: bool = ..., **extra: Any) -> _MonkeyPatchedResponse: ... # type: ignore[override] + def get(self, path: str, data: dict[str, Any] | str | None = ..., follow: bool = ..., **extra: Any): ... # type: ignore[override] + def post(self, path: str, data: Any | None = ..., format: str | None = ..., content_type: str | None = ..., follow: bool = ..., **extra: Any) -> _MonkeyPatchedResponse: ... # type: ignore[override] + def put(self, path: str, data: Any | None = ..., format: str | None = ..., content_type: str | None = ..., follow: bool = ..., **extra: Any) -> _MonkeyPatchedResponse: ... # type: ignore[override] + def patch(self, path: str, data: Any | None = ..., format: str | None = ..., content_type: str | None = ..., follow: bool = ..., **extra: Any) -> _MonkeyPatchedResponse: ... # type: ignore[override] + def delete(self, path: str, data: Any | None = ..., format: str | None = ..., content_type: str | None = ..., follow: bool = ..., **extra: Any) -> _MonkeyPatchedResponse: ... # type: ignore[override] + def options(self, path: str, data: dict[str, str] | str = ..., format: str | None = ..., content_type: Any | None = ..., follow: bool = ..., **extra: Any) -> _MonkeyPatchedResponse: ... # type: ignore[override] def logout(self) -> None: ... class APITransactionTestCase(testcases.TransactionTestCase): - client_class: Type[APIClient] = ... + client_class: type[APIClient] client: APIClient class APITestCase(testcases.TestCase): - client_class: Type[APIClient] = ... + client_class: type[APIClient] client: APIClient class APISimpleTestCase(testcases.SimpleTestCase): - client_class: Type[APIClient] = ... + client_class: type[APIClient] client: APIClient class APILiveServerTestCase(testcases.LiveServerTestCase): - client_class: Type[APIClient] = ... + client_class: type[APIClient] client: APIClient class URLPatternsTestCase(testcases.SimpleTestCase): ... diff --git a/rest_framework-stubs/throttling.pyi b/rest_framework-stubs/throttling.pyi index 3369a4227..b4578737f 100644 --- a/rest_framework-stubs/throttling.pyi +++ b/rest_framework-stubs/throttling.pyi @@ -1,4 +1,5 @@ -from typing import Any, Callable, Dict, List, Optional, Tuple +from collections.abc import Callable +from typing import Any from django.core.cache.backends.base import BaseCache from rest_framework.request import Request @@ -7,22 +8,22 @@ from rest_framework.views import APIView class BaseThrottle: def allow_request(self, request: Request, view: APIView) -> bool: ... def get_ident(self, request: Request) -> str: ... - def wait(self) -> Optional[float]: ... + def wait(self) -> float | None: ... class SimpleRateThrottle(BaseThrottle): - cache: BaseCache = ... - cache_format: str = ... - history: List[Any] - key: Optional[str] = ... + cache: BaseCache + cache_format: str + history: list[Any] + key: str | None now: float - rate: Optional[str] - scope: Optional[str] = ... - THROTTLE_RATES: Dict[str, Optional[str]] = ... - timer: Callable[..., float] = ... + rate: str | None + scope: str | None + THROTTLE_RATES: dict[str, str | None] + timer: Callable[..., float] def __init__(self) -> None: ... - def get_cache_key(self, request: Request, view: APIView) -> Optional[str]: ... - def get_rate(self) -> Optional[str]: ... - def parse_rate(self, rate) -> Tuple[Optional[int], Optional[int]]: ... + def get_cache_key(self, request: Request, view: APIView) -> str | None: ... + def get_rate(self) -> str | None: ... + def parse_rate(self, rate) -> tuple[int | None, int | None]: ... def throttle_failure(self) -> bool: ... def throttle_success(self) -> bool: ... @@ -30,4 +31,4 @@ class AnonRateThrottle(SimpleRateThrottle): ... class UserRateThrottle(SimpleRateThrottle): ... class ScopedRateThrottle(SimpleRateThrottle): - scope_attr: str = ... + scope_attr: str diff --git a/rest_framework-stubs/urlpatterns.pyi b/rest_framework-stubs/urlpatterns.pyi index f27a94d06..eaf9df25b 100644 --- a/rest_framework-stubs/urlpatterns.pyi +++ b/rest_framework-stubs/urlpatterns.pyi @@ -1,17 +1,18 @@ -from typing import Iterable, List, Optional, Sequence, Union +from collections.abc import Iterable, Sequence +from typing_extensions import TypeAlias from django.urls.resolvers import URLPattern, URLResolver -_AnyURL = Union[URLPattern, URLResolver] +_AnyURL: TypeAlias = URLPattern | URLResolver def apply_suffix_patterns( urlpatterns: Iterable[_AnyURL], suffix_pattern: str, suffix_required: bool, - suffix_route: Optional[str] = ..., -) -> List[Union[URLResolver, URLPattern]]: ... + suffix_route: str | None = ..., +) -> list[URLResolver | URLPattern]: ... def format_suffix_patterns( urlpatterns: Iterable[_AnyURL], suffix_required: bool = ..., - allowed: Optional[Sequence[str]] = ..., -) -> List[Union[URLResolver, URLPattern]]: ... + allowed: Sequence[str] | None = ..., +) -> list[URLResolver | URLPattern]: ... diff --git a/rest_framework-stubs/urls.pyi b/rest_framework-stubs/urls.pyi index ea9623146..52ada2775 100644 --- a/rest_framework-stubs/urls.pyi +++ b/rest_framework-stubs/urls.pyi @@ -1,6 +1,4 @@ -from typing import List - from rest_framework.urlpatterns import _AnyURL app_name: str -urlpatterns: List[_AnyURL] +urlpatterns: list[_AnyURL] diff --git a/rest_framework-stubs/utils/breadcrumbs.pyi b/rest_framework-stubs/utils/breadcrumbs.pyi index ba9e887ef..1663c12e9 100644 --- a/rest_framework-stubs/utils/breadcrumbs.pyi +++ b/rest_framework-stubs/utils/breadcrumbs.pyi @@ -1,3 +1,3 @@ -from typing import Any, Optional +from typing import Any -def get_breadcrumbs(url: Any, request: Optional[Any] = ...): ... +def get_breadcrumbs(url: Any, request: Any | None = ...): ... diff --git a/rest_framework-stubs/utils/field_mapping.pyi b/rest_framework-stubs/utils/field_mapping.pyi index 0b716bc1a..b6bb960d3 100644 --- a/rest_framework-stubs/utils/field_mapping.pyi +++ b/rest_framework-stubs/utils/field_mapping.pyi @@ -1,21 +1,22 @@ -from typing import Any, Dict, Generic, MutableMapping, Sequence, Type, TypeVar +from collections.abc import MutableMapping, Sequence +from typing import Any, Generic, TypeVar from django.db import models -NUMERIC_FIELD_TYPES: Sequence[Type[models.Field]] = ... +NUMERIC_FIELD_TYPES: Sequence[type[models.Field]] _K = TypeVar("_K", bound=type) _V = TypeVar("_V") class ClassLookupDict(Generic[_K, _V]): - mapping: MutableMapping[Type[_K], _V] - def __init__(self, mapping: MutableMapping[Type[_K], _V]): ... + mapping: MutableMapping[type[_K], _V] + def __init__(self, mapping: MutableMapping[type[_K], _V]): ... def __getitem__(self, key: _K) -> _V: ... def __setitem__(self, key: _K, value: _V) -> None: ... def needs_label(model_field: models.Field, field_name: str) -> bool: ... def get_detail_view_name(model: models.Model) -> str: ... -def get_field_kwargs(field_name: str, model_field: models.Field) -> Dict[str, Any]: ... -def get_relation_kwargs(field_name: str, relation_info) -> Dict[str, Any]: ... -def get_nested_relation_kwargs(relation_info) -> Dict[str, Any]: ... -def get_url_kwargs(model_field: models.Model) -> Dict[str, Any]: ... +def get_field_kwargs(field_name: str, model_field: models.Field) -> dict[str, Any]: ... +def get_relation_kwargs(field_name: str, relation_info) -> dict[str, Any]: ... +def get_nested_relation_kwargs(relation_info) -> dict[str, Any]: ... +def get_url_kwargs(model_field: models.Model) -> dict[str, Any]: ... diff --git a/rest_framework-stubs/utils/formatting.pyi b/rest_framework-stubs/utils/formatting.pyi index 815fed1cb..a21a2a7d8 100644 --- a/rest_framework-stubs/utils/formatting.pyi +++ b/rest_framework-stubs/utils/formatting.pyi @@ -1,14 +1,13 @@ -from typing import Any, Union +from typing import Any def remove_trailing_string(content: str, trailing: str) -> str: ... -def dedent(content: Union[str, bytes]) -> str: ... +def dedent(content: str | bytes) -> str: ... def camelcase_to_spaces(content: str) -> str: ... def markup_description(description: str) -> str: ... class lazy_format: - format_string: str = ... - result: str = ... + format_string: str + result: str args: Any kwargs: Any def __init__(self, format_string: str, *args: Any, **kwargs: Any): ... - def __str__(self) -> str: ... diff --git a/rest_framework-stubs/utils/html.pyi b/rest_framework-stubs/utils/html.pyi index a9da1659a..1f2a81e40 100644 --- a/rest_framework-stubs/utils/html.pyi +++ b/rest_framework-stubs/utils/html.pyi @@ -1,5 +1,5 @@ -from typing import Any, Optional +from typing import Any def is_html_input(dictionary: Any): ... -def parse_html_list(dictionary: Any, prefix: str = ..., default: Optional[Any] = ...): ... +def parse_html_list(dictionary: Any, prefix: str = ..., default: Any | None = ...): ... def parse_html_dict(dictionary: Any, prefix: str = ...): ... diff --git a/rest_framework-stubs/utils/mediatypes.pyi b/rest_framework-stubs/utils/mediatypes.pyi index 5a41b15d9..6d6fc9e5e 100644 --- a/rest_framework-stubs/utils/mediatypes.pyi +++ b/rest_framework-stubs/utils/mediatypes.pyi @@ -4,7 +4,7 @@ def media_type_matches(lhs: Any, rhs: Any): ... def order_by_precedence(media_type_lst: Any): ... class _MediaType: - orig: Any = ... + orig: Any def __init__(self, media_type_str: Any) -> None: ... def match(self, other: Any): ... @property diff --git a/rest_framework-stubs/utils/model_meta.pyi b/rest_framework-stubs/utils/model_meta.pyi index aa371ded2..885bddd14 100644 --- a/rest_framework-stubs/utils/model_meta.pyi +++ b/rest_framework-stubs/utils/model_meta.pyi @@ -1,12 +1,12 @@ -from typing import Dict, NamedTuple, Optional, Type +from typing import NamedTuple from django.db.models import Model from django.db.models.fields import Field from django.db.models.fields.related import RelatedField class RelationInfo(NamedTuple): - model_field: Optional[RelatedField] - related_model: Type[Model] + model_field: RelatedField | None + related_model: type[Model] to_many: bool to_field: str has_through_model: bool @@ -14,11 +14,11 @@ class RelationInfo(NamedTuple): class FieldInfo(NamedTuple): pk: Field - fields: Dict[str, Field] - forward_relations: Dict[str, RelationInfo] - reverse_relations: Dict[str, RelationInfo] - fields_and_pk: Dict[str, Field] - relations: Dict[str, RelationInfo] + fields: dict[str, Field] + forward_relations: dict[str, RelationInfo] + reverse_relations: dict[str, RelationInfo] + fields_and_pk: dict[str, Field] + relations: dict[str, RelationInfo] -def get_field_info(model: Type[Model]) -> FieldInfo: ... -def is_abstract_model(model: Type[Model]) -> bool: ... +def get_field_info(model: type[Model]) -> FieldInfo: ... +def is_abstract_model(model: type[Model]) -> bool: ... diff --git a/rest_framework-stubs/utils/representation.pyi b/rest_framework-stubs/utils/representation.pyi index a62ecccb1..2cf36324a 100644 --- a/rest_framework-stubs/utils/representation.pyi +++ b/rest_framework-stubs/utils/representation.pyi @@ -1,7 +1,7 @@ -from typing import Any, Optional +from typing import Any def manager_repr(value: Any): ... def smart_repr(value: Any): ... def field_repr(field: Any, force_many: bool = ...): ... -def serializer_repr(serializer: Any, indent: Any, force_many: Optional[Any] = ...): ... +def serializer_repr(serializer: Any, indent: Any, force_many: Any | None = ...): ... def list_repr(serializer: Any, indent: Any): ... diff --git a/rest_framework-stubs/utils/serializer_helpers.pyi b/rest_framework-stubs/utils/serializer_helpers.pyi index 5645f2994..4bde1f3e5 100644 --- a/rest_framework-stubs/utils/serializer_helpers.pyi +++ b/rest_framework-stubs/utils/serializer_helpers.pyi @@ -1,5 +1,6 @@ from collections import OrderedDict -from typing import Any, Dict, Iterator, List, MutableMapping, Tuple, Union +from collections.abc import Iterator, MutableMapping +from typing import Any from rest_framework.exceptions import ErrorDetail from rest_framework.fields import Field @@ -9,12 +10,12 @@ class ReturnDict(OrderedDict): serializer: BaseSerializer def __init__(self, serializer: BaseSerializer = ..., *args, **kwargs): ... def copy(self) -> ReturnDict: ... - def __reduce__(self) -> Tuple[dict, Tuple[dict]]: ... + def __reduce__(self) -> tuple[dict, tuple[dict]]: ... class ReturnList(list): serializer: BaseSerializer def __init__(self, serializer: BaseSerializer = ..., *args, **kwargs): ... - def __reduce__(self) -> Tuple[dict, Tuple[dict]]: ... + def __reduce__(self) -> tuple[dict, tuple[dict]]: ... class BoundField: """ @@ -24,9 +25,9 @@ class BoundField: """ value: Any - fields: Dict[str, Field] - errors: List[ErrorDetail] - def __init__(self, field: Field, value: Any, errors: List[ErrorDetail], prefix: str = ...): ... + fields: dict[str, Field] + errors: list[ErrorDetail] + def __init__(self, field: Field, value: Any, errors: list[ErrorDetail], prefix: str = ...): ... def __getattr__(self, attr_name: str) -> Any: ... def as_form_field(self) -> BoundField: ... @@ -34,7 +35,7 @@ class JSONBoundField(BoundField): ... class NestedBoundField(BoundField): def __iter__(self) -> Iterator[str]: ... - def __getitem__(self, key: str) -> Union[BoundField, NestedBoundField]: ... + def __getitem__(self, key: str) -> BoundField | NestedBoundField: ... class BindingDict(MutableMapping[str, Field]): serializer: BaseSerializer diff --git a/rest_framework-stubs/validators.pyi b/rest_framework-stubs/validators.pyi index b117b89bd..fc8702fe6 100644 --- a/rest_framework-stubs/validators.pyi +++ b/rest_framework-stubs/validators.pyi @@ -1,4 +1,6 @@ -from typing import Any, Container, Iterable, MutableMapping, Optional, TypeVar, Protocol, Union, Callable +from collections.abc import Callable, Container, Iterable, MutableMapping +from typing import Any, TypeVar, Protocol +from typing_extensions import TypeAlias from django.db.models import Model, QuerySet from rest_framework.fields import Field @@ -11,28 +13,28 @@ class ContextValidator(Protocol[_V]): requires_context: bool def __call__(self, __value: _V, __context: Field) -> None: ... -Validator = Union[Callable[[_V], None], ContextValidator[_V]] +Validator: TypeAlias = Callable[[_V], None] | ContextValidator[_V] def qs_exists(queryset: QuerySet) -> bool: ... def qs_filter(queryset: QuerySet[_T], **kwargs: Any) -> QuerySet[_T]: ... class UniqueValidator: - message: str = ... - requires_context: bool = ... + message: str + requires_context: bool queryset: QuerySet lookup: str - def __init__(self, queryset: QuerySet, message: Optional[str] = ..., lookup: str = ...) -> None: ... + def __init__(self, queryset: QuerySet, message: str | None = ..., lookup: str = ...) -> None: ... def filter_queryset(self, value: Any, queryset: QuerySet[_T], field_name: str) -> QuerySet[_T]: ... def exclude_current_instance(self, queryset: QuerySet[_T], instance: _T) -> QuerySet[_T]: ... def __call__(self, value: Any, serializer_field: Field) -> None: ... class UniqueTogetherValidator: - message: str = ... - missing_message: str = ... - requires_context: bool = ... + message: str + missing_message: str + requires_context: bool queryset: QuerySet fields: Iterable[str] - def __init__(self, queryset: QuerySet, fields: Iterable[str], message: Optional[str] = ...) -> None: ... + def __init__(self, queryset: QuerySet, fields: Iterable[str], message: str | None = ...) -> None: ... def enforce_required_fields(self, attrs: Container[str], serializer: BaseSerializer) -> None: ... def filter_queryset( self, attrs: MutableMapping[str, Any], queryset: QuerySet[_T], serializer: BaseSerializer @@ -43,18 +45,18 @@ class UniqueTogetherValidator: def __call__(self, attrs: MutableMapping[str, Any], serializer: BaseSerializer) -> None: ... class ProhibitSurrogateCharactersValidator: - message: str = ... - code: str = ... + message: str + code: str def __call__(self, value: Any) -> None: ... class BaseUniqueForValidator: - message: str = ... - missing_message: str = ... - requires_context: bool = ... + message: str + missing_message: str + requires_context: bool queryset: QuerySet field: str date_field: str - def __init__(self, queryset: QuerySet, field: str, date_field: str, message: Optional[str] = ...) -> None: ... + def __init__(self, queryset: QuerySet, field: str, date_field: str, message: str | None = ...) -> None: ... def enforce_required_fields(self, attrs: Container[str]) -> None: ... def filter_queryset( self, attrs: MutableMapping[str, Any], queryset: QuerySet[_T], field_name: str, date_field_name: str diff --git a/rest_framework-stubs/versioning.pyi b/rest_framework-stubs/versioning.pyi index c905c6ef0..f4cf29093 100644 --- a/rest_framework-stubs/versioning.pyi +++ b/rest_framework-stubs/versioning.pyi @@ -1,36 +1,38 @@ -from typing import Any, Mapping, Optional, Pattern, Sequence +from collections.abc import Mapping, Sequence +from re import Pattern +from typing import Any from rest_framework.request import Request class BaseVersioning: - default_version: Optional[str] = ... - allowed_versions: Optional[Sequence[str]] = ... - version_param: str = ... + default_version: str | None + allowed_versions: Sequence[str] | None + version_param: str def determine_version(self, request: Request, *args: Any, **kwargs: Any) -> str: ... def reverse( self, viewname: str, - args: Optional[Sequence[Any]] = ..., - kwargs: Optional[Mapping[str, Any]] = ..., - request: Optional[Request] = ..., - format: Optional[str] = ..., + args: Sequence[Any] | None = ..., + kwargs: Mapping[str, Any] | None = ..., + request: Request | None = ..., + format: str | None = ..., **extra: Any ) -> str: ... - def is_allowed_version(self, version: Optional[str]) -> bool: ... + def is_allowed_version(self, version: str | None) -> bool: ... class AcceptHeaderVersioning(BaseVersioning): - invalid_version_message: str = ... + invalid_version_message: str class URLPathVersioning(BaseVersioning): - invalid_version_message: str = ... + invalid_version_message: str class NamespaceVersioning(BaseVersioning): - invalid_version_message: str = ... + invalid_version_message: str def get_versioned_viewname(self, viewname: str, request: Request) -> str: ... class HostNameVersioning(BaseVersioning): - hostname_regex: Pattern = ... - invalid_version_message: str = ... + hostname_regex: Pattern + invalid_version_message: str class QueryParameterVersioning(BaseVersioning): - invalid_version_message: str = ... + invalid_version_message: str diff --git a/rest_framework-stubs/views.pyi b/rest_framework-stubs/views.pyi index 31287f2db..951acb807 100644 --- a/rest_framework-stubs/views.pyi +++ b/rest_framework-stubs/views.pyi @@ -1,18 +1,5 @@ -from typing import ( - Any, - Callable, - Dict, - List, - Mapping, - NoReturn, - Optional, - Protocol, - Sequence, - Tuple, - Type, - TypeVar, - Union, -) +from collections.abc import Callable, Mapping, Sequence +from typing import Any, NoReturn, Protocol, TypeVar from django.http import HttpRequest from django.http.response import HttpResponseBase @@ -33,13 +20,13 @@ from rest_framework.versioning import BaseVersioning def get_view_name(view: APIView) -> str: ... def get_view_description(view: APIView, html: bool = ...) -> str: ... def set_rollback() -> None: ... -def exception_handler(exc: Exception, context) -> Optional[Response]: ... +def exception_handler(exc: Exception, context) -> Response | None: ... _View = TypeVar("_View", bound=Callable[..., HttpResponseBase]) class AsView(Protocol[_View]): - cls: Type[APIView] - view_class: Type[APIView] + cls: type[APIView] + view_class: type[APIView] view_initkwargs: Mapping[str, Any] csrf_exempt: bool __call__: _View @@ -49,55 +36,53 @@ class GenericView(Protocol): def __call__(self, request: HttpRequest, *args: Any, **kwargs: Any) -> Response: ... class APIView(View): - args: Any = ... - authentication_classes: Sequence[Type[BaseAuthentication]] = ... - content_negotiation_class: Type[BaseContentNegotiation] = ... - format_kwarg: Any = ... - headers: Dict[str, str] = ... - kwargs: Any = ... - metadata_class: Optional[Union[str, BaseMetadata]] = ... - parser_classes: Sequence[Type[BaseParser]] = ... - permission_classes: Sequence[_PermissionClass] = ... - renderer_classes: Sequence[Type[BaseRenderer]] = ... + args: Any + authentication_classes: Sequence[type[BaseAuthentication]] + content_negotiation_class: type[BaseContentNegotiation] + format_kwarg: Any + headers: dict[str, str] + kwargs: Any + metadata_class: str | BaseMetadata | None + parser_classes: Sequence[type[BaseParser]] + permission_classes: Sequence[_PermissionClass] + renderer_classes: Sequence[type[BaseRenderer]] request: Request - response: Response = ... - schema: Optional[ViewInspector] = ... + response: Response + schema: ViewInspector | None settings: APISettings - throttle_classes: Sequence[Type[BaseThrottle]] = ... - versioning_class: Optional[Type[BaseVersioning]] = ... + throttle_classes: Sequence[type[BaseThrottle]] + versioning_class: type[BaseVersioning] | None @property - def allowed_methods(self) -> List[str]: ... + def allowed_methods(self) -> list[str]: ... @property - def default_response_headers(self) -> Dict[str, str]: ... + def default_response_headers(self) -> dict[str, str]: ... @classmethod def as_view(cls, **initkwargs: Any) -> AsView[GenericView]: ... def http_method_not_allowed(self, request: Request, *args: Any, **kwargs: Any) -> Response: ... # type: ignore[override] - def permission_denied( - self, request: Request, message: Optional[str] = ..., code: Optional[str] = ... - ) -> NoReturn: ... + def permission_denied(self, request: Request, message: str | None = ..., code: str | None = ...) -> NoReturn: ... def throttled(self, request: Request, wait: float) -> NoReturn: ... def get_authenticate_header(self, request: Request) -> str: ... - def get_parser_context(self, http_request: HttpRequest) -> Dict[str, Any]: ... - def get_renderer_context(self) -> Dict[str, Any]: ... - def get_exception_handler_context(self) -> Dict[str, Any]: ... + def get_parser_context(self, http_request: HttpRequest) -> dict[str, Any]: ... + def get_renderer_context(self) -> dict[str, Any]: ... + def get_exception_handler_context(self) -> dict[str, Any]: ... def get_view_name(self) -> str: ... def get_view_description(self, html: bool = ...) -> str: ... - def get_format_suffix(self, **kwargs: Any) -> Optional[str]: ... - def get_renderers(self) -> List[BaseRenderer]: ... - def get_parsers(self) -> List[BaseParser]: ... - def get_authenticators(self) -> List[BaseAuthentication]: ... - def get_permissions(self) -> List[_SupportsHasPermission]: ... - def get_throttles(self) -> List[BaseThrottle]: ... + def get_format_suffix(self, **kwargs: Any) -> str | None: ... + def get_renderers(self) -> list[BaseRenderer]: ... + def get_parsers(self) -> list[BaseParser]: ... + def get_authenticators(self) -> list[BaseAuthentication]: ... + def get_permissions(self) -> list[_SupportsHasPermission]: ... + def get_throttles(self) -> list[BaseThrottle]: ... def get_content_negotiator(self) -> BaseContentNegotiation: ... def get_exception_handler(self) -> Callable: ... - def perform_content_negotiation(self, request: Request, force: bool = ...) -> Tuple[BaseRenderer, str]: ... + def perform_content_negotiation(self, request: Request, force: bool = ...) -> tuple[BaseRenderer, str]: ... def perform_authentication(self, request: Request) -> None: ... def check_permissions(self, request: Request) -> None: ... def check_object_permissions(self, request: Request, obj: Any) -> None: ... def check_throttles(self, request: Request) -> None: ... def determine_version( self, request: Request, *args: Any, **kwargs: Any - ) -> Tuple[Optional[str], Optional[BaseVersioning]]: ... + ) -> tuple[str | None, BaseVersioning | None]: ... def initialize_request(self, request: HttpRequest, *args: Any, **kwargs: Any) -> Request: ... def initial(self, request: Request, *args: Any, **kwargs: Any) -> None: ... def finalize_response(self, request: Request, response: Response, *args: Any, **kwargs: Any) -> Response: ... diff --git a/rest_framework-stubs/viewsets.pyi b/rest_framework-stubs/viewsets.pyi index e02509b68..7fc154c8e 100644 --- a/rest_framework-stubs/viewsets.pyi +++ b/rest_framework-stubs/viewsets.pyi @@ -1,5 +1,7 @@ from collections import OrderedDict -from typing import Any, Callable, Dict, List, Optional, Tuple, Union +from collections.abc import Callable +from typing import Any +from typing_extensions import TypeAlias from django.http.request import HttpRequest from django.http.response import HttpResponseBase @@ -11,29 +13,29 @@ from rest_framework.views import AsView, GenericView def _is_extra_action(attr: Any) -> bool: ... -_ViewFunc = Callable[..., HttpResponseBase] +_ViewFunc: TypeAlias = Callable[..., HttpResponseBase] class ViewSetMixin: # Classvars assigned in as_view() - name: Optional[str] - description: Optional[str] - suffix: Optional[str] + name: str | None + description: str | None + suffix: str | None detail: bool basename: str # Instance attributes assigned in view wrapper - action_map: Dict[str, str] - args: Tuple[Any, ...] - kwargs: Dict[str, Any] + action_map: dict[str, str] + args: tuple[Any, ...] + kwargs: dict[str, Any] # Assigned in initialize_request() action: str @classmethod def as_view( - cls, actions: Optional[Dict[str, Union[str, ViewSetAction]]] = ..., **initkwargs: Any + cls, actions: dict[str, str | ViewSetAction] | None = ..., **initkwargs: Any ) -> AsView[GenericView]: ... def initialize_request(self, request: HttpRequest, *args: Any, **kwargs: Any) -> Request: ... def reverse_action(self, url_name: str, *args: Any, **kwargs: Any) -> str: ... @classmethod - def get_extra_actions(cls) -> List[_ViewFunc]: ... + def get_extra_actions(cls) -> list[_ViewFunc]: ... def get_extra_action_url_map(self) -> OrderedDict[str, str]: ... class ViewSet(ViewSetMixin, views.APIView): ... diff --git a/scripts/typecheck_tests.py b/scripts/typecheck_tests.py index 0bf7979cb..b2a78d3ee 100644 --- a/scripts/typecheck_tests.py +++ b/scripts/typecheck_tests.py @@ -243,7 +243,7 @@ 'Argument "data" to "ValidationSerializer" has incompatible type "str"', ], "test_validation_error.py": [ - 'Argument "detail" to "ValidationError" has incompatible type "Tuple[str, str]"; expected "Union[str, List[Any], Dict[str, Any], None]"', # noqa: E501 + 'Argument "detail" to "ValidationError" has incompatible type "Tuple[str, str]"; expected "Optional[Union[str, List[Any], Dict[str, Any]]]"', # noqa: E501 ], "test_validators.py": [ 'Argument "queryset" to "BaseUniqueForValidator" has incompatible type "object";' diff --git a/setup.cfg b/setup.cfg index 39ca15610..62f37e9c1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -7,14 +7,7 @@ exclude = max_line_length = 120 per-file-ignores = - *__init__.pyi: F401 - rest_framework-stubs/serializers.pyi: F401 - rest_framework-stubs/decorators.pyi: F401 - rest_framework-stubs/fields.pyi: F401 - rest_framework-stubs/authentication.pyi: F401 - rest_framework-stubs/generics.pyi: F401 - rest_framework-stubs/response.pyi: F401 - rest_framework-stubs/utils/serializer_helpers.pyi: F401 - + *.pyi: B, E301, E302, E305, E501, E701, E741, E743, NQA102, F401, F403, F405, F822, Y021, Y024, Y041, Y043 + rest_framework-stubs/compat.pyi: B, E301, E302, E305, E501, E701, E741, E743, NQA102, F401, F403, F405, F822, Y021, Y024, Y041, Y043, Y026, Y002, F811 [metadata] license_file = LICENSE.txt From 56a8915f7540022253d628eca78674ca527c0e64 Mon Sep 17 00:00:00 2001 From: Marti Raudsepp Date: Wed, 16 Nov 2022 16:05:55 +0200 Subject: [PATCH 34/42] CI: Enable testing with Python 3.10 (#292) Also updated pre-commit actions to use Python 3.10. --- .github/workflows/test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4808becdb..0f380e6cc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.9'] + python-version: ['3.10'] steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} @@ -31,7 +31,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.7', '3.8', '3.9'] + python-version: ['3.7', '3.8', '3.9', '3.10'] steps: - uses: actions/checkout@v3 - name: Setup system dependencies @@ -52,7 +52,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.7', '3.8', '3.9'] + python-version: ['3.7', '3.8', '3.9', '3.10'] steps: - uses: actions/checkout@v3 - name: Setup system dependencies From e46bc6e969e6fe702dfaa8120a1a8979d621dfc4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Nov 2022 16:09:43 +0200 Subject: [PATCH 35/42] Bump types-pytz from 2022.1.2 to 2022.6.0.1 (#272) Bumps [types-pytz](https://github.com/python/typeshed) from 2022.1.2 to 2022.6.0.1. - [Release notes](https://github.com/python/typeshed/releases) - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-pytz dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index bd0c99099..71e33571f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ pre-commit==2.20.0 pytest==7.1.2 pytest-mypy-plugins==1.10.1 djangorestframework==3.13.1 -types-pytz==2022.1.2 +types-pytz==2022.6.0.1 django-stubs==1.13.0 django-stubs-ext==0.7.0 -e .[compatible-mypy,coreapi,markdown] From a3022eaa0f70c49f5dfecffc4fc557cd680b06b9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Nov 2022 16:10:47 +0200 Subject: [PATCH 36/42] Bump gitpython from 3.1.27 to 3.1.29 (#266) Bumps [gitpython](https://github.com/gitpython-developers/GitPython) from 3.1.27 to 3.1.29. - [Release notes](https://github.com/gitpython-developers/GitPython/releases) - [Changelog](https://github.com/gitpython-developers/GitPython/blob/main/CHANGES) - [Commits](https://github.com/gitpython-developers/GitPython/compare/3.1.27...3.1.29) --- updated-dependencies: - dependency-name: gitpython dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 71e33571f..295420a74 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ wheel -gitpython==3.1.27 +gitpython==3.1.29 pre-commit==2.20.0 pytest==7.1.2 pytest-mypy-plugins==1.10.1 From b0b3577a2e05b0478bf7ff51a3ef306f9a2154e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Nov 2022 16:11:47 +0200 Subject: [PATCH 37/42] Bump pytest from 7.1.2 to 7.2.0 (#269) Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.1.2 to 7.2.0. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/7.1.2...7.2.0) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 295420a74..8ff5675ad 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ wheel gitpython==3.1.29 pre-commit==2.20.0 -pytest==7.1.2 +pytest==7.2.0 pytest-mypy-plugins==1.10.1 djangorestframework==3.13.1 types-pytz==2022.6.0.1 From 76b55dad0afb5319e9326caa1bca83495c308bde Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Nov 2022 16:23:29 +0200 Subject: [PATCH 38/42] Bump djangorestframework from 3.13.1 to 3.14.0 (#256) Bumps [djangorestframework](https://github.com/encode/django-rest-framework) from 3.13.1 to 3.14.0. - [Release notes](https://github.com/encode/django-rest-framework/releases) - [Commits](https://github.com/encode/django-rest-framework/compare/3.13.1...3.14.0) --- updated-dependencies: - dependency-name: djangorestframework dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 8ff5675ad..52a348589 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ gitpython==3.1.29 pre-commit==2.20.0 pytest==7.2.0 pytest-mypy-plugins==1.10.1 -djangorestframework==3.13.1 +djangorestframework==3.14.0 types-pytz==2022.6.0.1 django-stubs==1.13.0 django-stubs-ext==0.7.0 From 95b370f9116b358391daa88283579e36c478e95a Mon Sep 17 00:00:00 2001 From: Mike VanDenburgh <37340715+mvandenburgh@users.noreply.github.com> Date: Wed, 16 Nov 2022 09:28:07 -0500 Subject: [PATCH 39/42] Add 'HEAD' to accepted HTTP verbs list (#249) * Add 'HEAD' to accepted HTTP verbs list * Fixes after rebase (ec5ecd40c0be07418accbe1f94fda74d4b377c24) HEAD was already added to _MIXED_CASE_HTTP_VERBS in #273, but _LOWER_CASE_HTTP_VERBS was missed. Co-authored-by: Marti Raudsepp --- rest_framework-stubs/decorators.pyi | 1 + 1 file changed, 1 insertion(+) diff --git a/rest_framework-stubs/decorators.pyi b/rest_framework-stubs/decorators.pyi index a1d5288a3..999c3b83c 100644 --- a/rest_framework-stubs/decorators.pyi +++ b/rest_framework-stubs/decorators.pyi @@ -37,6 +37,7 @@ _LOWER_CASE_HTTP_VERBS: TypeAlias = list[ "put", "patch", "trace", + "head", "options", ] ] From 11ecec94683dd6086dbbded180390f86881375f3 Mon Sep 17 00:00:00 2001 From: Marti Raudsepp Date: Wed, 16 Nov 2022 18:11:28 +0200 Subject: [PATCH 40/42] Add DecimalField(normalize_output=) from DRF master (#294) This isn't in any DRF release yet, but fixes typecheck in our CI. Upstream PR: https://github.com/encode/django-rest-framework/pull/6514 --- rest_framework-stubs/fields.pyi | 8 ++++---- tests/typecheck/test_fields.yml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rest_framework-stubs/fields.pyi b/rest_framework-stubs/fields.pyi index 1da8f37ff..7d1b2ffcd 100644 --- a/rest_framework-stubs/fields.pyi +++ b/rest_framework-stubs/fields.pyi @@ -1,21 +1,20 @@ import datetime import uuid from collections import OrderedDict +from collections.abc import Callable, Generator, Iterable, Mapping, MutableMapping, Sequence from decimal import Decimal from enum import Enum from json import JSONDecoder, JSONEncoder -from collections.abc import Callable, Generator, Iterable, Mapping, MutableMapping, Sequence from re import Pattern from typing import Any, Generic, NoReturn, Protocol, TypeVar -from _typeshed import Self +from _typeshed import Self from django.core.files.base import File from django.db import models from django.forms import ImageField as DjangoImageField # noqa: F401 -from typing_extensions import Final, TypeAlias - from rest_framework.serializers import BaseSerializer from rest_framework.validators import Validator +from typing_extensions import Final, TypeAlias class _Empty(Enum): sentinel = 0 # noqa: Y015 @@ -340,6 +339,7 @@ class DecimalField(Field[Decimal, int | float | str | Decimal, str, Any]): min_value: Decimal | int | float = ..., localize: bool = ..., rounding: str | None = ..., + normalize_output: bool = ..., *, read_only: bool = ..., write_only: bool = ..., diff --git a/tests/typecheck/test_fields.yml b/tests/typecheck/test_fields.yml index 7447e036c..3f542a3a2 100644 --- a/tests/typecheck/test_fields.yml +++ b/tests/typecheck/test_fields.yml @@ -12,8 +12,8 @@ from django.db import models from rest_framework.fields import DecimalField, IPAddressField, SlugField, RegexField, ModelField, SerializerMethodField, ChoiceField - DecimalField(1, 1, False, 1, 1, False, None) - DecimalField(1, 1, False, 1, 1, False, None, True) # E: Too many positional arguments for "DecimalField" + DecimalField(1, 1, False, 1, 1, False, None, True) + DecimalField(1, 1, False, 1, 1, False, None, True, True) # E: Too many positional arguments for "DecimalField" IPAddressField('both') IPAddressField('both', True) # E: Too many positional arguments for "IPAddressField" From d3067ddf4d2415a8dae94e75c5b326a20b731451 Mon Sep 17 00:00:00 2001 From: Marti Raudsepp Date: Wed, 16 Nov 2022 23:22:22 +0200 Subject: [PATCH 41/42] CI: Remove unused typecheck ignores (#295) typecheck_tests.py contains lots of ignores that are now obsolete. Instead of using IGNORED_MODULES for some files, now added the remaining issues in these files to IGNORED_ERRORS --- scripts/typecheck_tests.py | 47 +++++++------------------------------- 1 file changed, 8 insertions(+), 39 deletions(-) diff --git a/scripts/typecheck_tests.py b/scripts/typecheck_tests.py index b2a78d3ee..6d32c3048 100644 --- a/scripts/typecheck_tests.py +++ b/scripts/typecheck_tests.py @@ -10,7 +10,7 @@ from scripts.git_helpers import checkout_target_tag from scripts.paths import DRF_SOURCE_DIRECTORY, PROJECT_DIRECTORY, STUBS_DIRECTORY -IGNORED_MODULES = ["utils.py", "test_testing.py"] +IGNORED_MODULES = [] MOCK_OBJECTS = [ "MockQueryset", "MockRequest", @@ -40,12 +40,11 @@ EXTERNAL_MODULES = ["requests"] IGNORED_ERRORS = { "__common__": [ - "already defined", + "already defined on line", "Need type annotation for", "Cannot assign to a method", "Cannot determine type of", 'has no attribute "initkwargs"', - 'has no attribute "mapping"', 'Response" has no attribute "view"', "Cannot infer type", ' has no attribute "_context', @@ -74,7 +73,6 @@ 'Value of type "Optional[Any]" is not indexable', 'Item "None" of "Optional[Any]" has no attribute', 'List item 0 has incompatible type "Type[', - 'error: Module has no attribute "coreapi"', 'Value of type "Optional[str]" is not indexable', 'Incompatible types in assignment (expression has type "AsView[GenericView]", variable has type "AsView[Callable[[HttpRequest], Any]]")', # noqa: E501 'Argument "patterns" to "SchemaGenerator" has incompatible type "List[object]"', @@ -83,11 +81,8 @@ '"Module rest_framework.schemas.coreapi" does not explicitly export attribute "coreapi"', ], "browsable_api": [ - '(expression has type "List[Dict[str, Dict[str, int]]]", base class "GenericAPIView" defined the type as "Union[QuerySet[_MT?], Manager[_MT?], None]")', # noqa: E501 'expression has type "List[Dict[str, Dict[str, int]]]"', - 'List item 0 has incompatible type "Type[IsAuthenticated]', ], - "conftest.py": ["Unsupported operand types for"], "models.py": ['"ForeignKeyTarget" has no attribute "sources"'], "serializers.pyi": [ 'note: "IntegerSerializer" defined here', @@ -100,7 +95,6 @@ "test_bound_fields.py": ['Value of type "BoundField" is not indexable'], "test_decorators.py": [ 'Argument 1 to "api_view" has incompatible type "Callable[[Any], Any]"; expected "Optional[Sequence[str]]"', - '"AsView[Callable[[Any], Any]]" has no attribute "cls"', ], "test_encoders.py": ['Argument "serializer" to "ReturnList" has incompatible type "None'], "test_fields.py": [ @@ -116,14 +110,9 @@ '"Field[Any, Any, Any, Any]" has no attribute "method_name"', 'Argument 1 to "ModelField" has incompatible type "None"', 'Argument "params" to "ValidationError" has incompatible type "Tuple[str]"', - '"MultipleChoiceField[Model]" has no attribute "partial"', 'Argument 1 to "to_internal_value" of "Field" has incompatible type "Dict[str, str]"; expected "List[Any]"', 'Module "rest_framework.fields" does not explicitly export attribute "DjangoImageField"', 'Argument 1 to "ListField" has incompatible type "CharField"; expected "bool"', - "Possible overload variants:", - "def __init__(self, *, mutable: Literal[True], query_string: Union[str, bytes, None] = ..., encoding: Optional[str] = ...) -> QueryDict", # noqa: E501 - "def __init__(self, query_string: Union[str, bytes, None] = ..., mutable: bool = ..., encoding: Optional[str] = ...) -> _ImmutableQueryDict", # noqa: E501 - "def __init__(self, query_string: Union[str, bytes, None], mutable: Literal[True], encoding: Optional[str] = ...) -> QueryDict", # noqa: E501 ], "test_filters.py": [ 'Module has no attribute "coreapi"', @@ -143,17 +132,11 @@ "test_middleware.py": ['"is_form_media_type" has incompatible type "Optional[str]"; expected "str"'], "test_model_serializer.py": [ '"Field[Any, Any, Any, Any]" has no attribute', - 'Module has no attribute "JSONField"', - 'expected "OrderedDict[Any, Any]"', 'base class "Meta" defined the type as', - '"Field" has no attribute', - '"Dict[str, Any]" has no attribute "name"', ], "test_negotiation.py": ['has incompatible type "None"'], "test_pagination.py": [ - 'Incompatible types in assignment (expression has type "None", base class "LimitOffsetPagination" defined the type as "int")', # noqa: E501 "(not iterable)", - '(expression has type "None", variable has type "List[Any]")', 'has incompatible type "range"', 'expected "Iterable[Any]"', ], @@ -172,17 +155,14 @@ 'Argument 2 to "re_path" has incompatible type "Callable[[], None]"; expected "Callable[..., HttpResponseBase]"', # noqa: E501 ], "test_relations_pk.py": [ - '"Field" has no attribute "get_queryset"', '"OneToOneTarget" has no attribute "id"', '"Field[Any, Any, Any, Any]" has no attribute "get_queryset', - 'Argument "queryset" to "HyperlinkedRelatedField" has incompatible type', ], "test_renderers.py": [ '(expression has type "Callable[[], str]", variable has type "Callable[[Optional[str]], str]")' ], "test_request.py": [ '"Request" has no attribute "inner_property"', - 'Argument 2 to "login" has incompatible type "Optional[AbstractBaseUser]"; expected "AbstractBaseUser"', 'expression has type "Optional[AbstractBaseUser]', ], "test_response.py": [ @@ -194,22 +174,13 @@ '"None" not callable', ], "test_serializer.py": [ - 'of "BaseSerializer" has incompatible type "None"', "base class", - '(expression has type "IntegerField", base class "Base" defined the type as "CharField")', '"CharField" has incompatible type "Collection[Any]"', 'Name "foo" is not defined', - 'Argument "data" has incompatible type "None"', 'Unsupported left operand type for | ("ReturnDict")', 'Unsupported left operand type for | ("Dict[str, str]")', ], - "test_serializer_bulk_update.py": [ - 'Argument "data" has incompatible type "int"', - 'Argument "data" has incompatible type "List[object]"', - 'Argument "data" has incompatible type "List[str]"', - ], "test_serializer_lists.py": [ - 'The type "Type[ListSerializer]" is not generic and not indexable', 'Name "foo" is not defined', 'Unexpected keyword argument "max_length" for "IntegerSerializer"', 'Unexpected keyword argument "min_length" for "IntegerSerializer"', @@ -218,18 +189,20 @@ '(expression has type "NestedSerializer", base class "Field" defined the type as "bool")', "self.Serializer", '(expression has type "NonRelationalPersonDataSerializer", base class "Serializer" defined the type as "ReturnDict")', # noqa: E501 - 'Argument "data" has incompatible type "None"; expected "Mapping[str, Any]"', - 'Argument "data" has incompatible type "None"', ], "test_settings.py": [ 'Argument 1 to "APISettings" has incompatible type "Dict[str, int]"; expected "Optional[DefaultsSettings]' ], "test_templatetags.py": ['Module has no attribute "smart_urlquote"'], + "test_testing.py": [ + '"Client" has no attribute "force_authenticate"', + '"Client" has no attribute "credentials"', + 'has no attribute "addClassCleanup"', + ], "test_throttling.py": [ 'has incompatible type "Dict[, ]"', '"SimpleRateThrottle" has no attribute "num_requests', '"SimpleRateThrottle" has no attribute "duration"', - "Cannot assign to a method", 'Type[NonTimeThrottle]" has no attribute "called"', ], "test_utils.py": [ @@ -237,10 +210,7 @@ 'incompatible type "List[Union[URLPattern, URLResolver]]"; expected "Iterable[URLPattern]"', ], "test_validation.py": [ - 'Value of type "object" is not indexable', 'Argument 1 to "to_internal_value" of "Field" has incompatible type "object"', - 'Argument "data" to "ValidationSerializer" has incompatible type "str"; expected "Mapping[str, Any]"', - 'Argument "data" to "ValidationSerializer" has incompatible type "str"', ], "test_validation_error.py": [ 'Argument "detail" to "ValidationError" has incompatible type "Tuple[str, str]"; expected "Optional[Union[str, List[Any], Dict[str, Any]]]"', # noqa: E501 @@ -253,14 +223,13 @@ 'Item "GenericForeignKey" of "Union[Field[Any, Any], ForeignObjectRel, GenericForeignKey]" has no attribute "validators"', # noqa: E501 ], "test_versioning.py": [ - '(expression has type "Type[FakeResolverMatch]", variable has type "ResolverMatch")', "rest_framework.decorators", 'Argument 1 to "include" has incompatible type "Tuple[List[object], str]"', ], "test_viewsets.py": [ - '(expression has type "None", variable has type "HttpRequest")', '(expression has type "None", variable has type "Request")', ], + "utils.py": ['Invalid signature "Callable[[BadType], Any]"'], } From 2584ad31edde5350215c10d0821c81303402d22f Mon Sep 17 00:00:00 2001 From: Marti Raudsepp Date: Fri, 18 Nov 2022 10:35:04 +0200 Subject: [PATCH 42/42] Version 1.8.0 release (#293) Also: * Updated Python compatibility in setup.py and README. * Removed DRF version from README -- it has been out of date for a while. * Added link to typeshed coding conventions that's now enforced by `flake8-pyi` --- CONTRIBUTING.md | 3 +++ README.md | 4 ++-- setup.py | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 95cf49d7d..5d4c191bd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,6 +8,9 @@ This project is open source and community driven. As such we encourage code cont 4. Write tests 5. Update dependencies +Type stubs in `.pyi` files should follow +[coding conventions from typeshed project](https://github.com/python/typeshed/blob/main/CONTRIBUTING.md#conventions). + ## Tutorials If you want to start working on this project, you will need to get familiar with python typings. diff --git a/README.md b/README.md index c081734b6..d394ac561 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,8 @@ [![Gitter](https://badges.gitter.im/mypy-django/Lobby.svg)](https://gitter.im/mypy-django/Lobby) -Mypy stubs for [DRF 3.12.x](https://pypi.org/project/djangorestframework/). -Supports Python 3.6, 3.7, 3.8 and 3.9. +Mypy stubs for [Django REST Framework](https://pypi.org/project/djangorestframework/). +Supports Python 3.7 and up. ## Installation diff --git a/setup.py b/setup.py index 8d2304b92..13bec7e45 100644 --- a/setup.py +++ b/setup.py @@ -35,7 +35,7 @@ def find_stub_files(name): setup( name="djangorestframework-stubs", - version="1.7.0", + version="1.8.0", description="PEP-484 stubs for django-rest-framework", long_description=readme, long_description_content_type="text/markdown", @@ -54,6 +54,7 @@ def find_stub_files(name): "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", "Typing :: Typed", ], )