From 493d58ebccdfeb1a4d9b5ad669deb080d314ed96 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Wed, 4 Dec 2024 22:09:35 +0300 Subject: [PATCH 1/5] Update ruff --- .github/workflows/test.yml | 8 +- .pre-commit-config.yaml | 7 +- pyproject.toml | 14 +--- requirements.txt | 3 +- rest_framework-stubs/test.pyi | 75 ++++++++++++++++--- .../utils/serializer_helpers.pyi | 15 ++-- rest_framework-stubs/validators.pyi | 2 +- setup.py | 4 +- 8 files changed, 84 insertions(+), 44 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3c1085b93..985459182 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,7 +24,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} @@ -48,7 +48,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] steps: - uses: actions/checkout@v4 - name: Setup system dependencies @@ -73,7 +73,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.12'] + python-version: ['3.13'] fail-fast: false steps: - uses: actions/checkout@v4 @@ -101,7 +101,7 @@ jobs: fetch-tags: true - uses: actions/setup-python@v5 with: - python-version: '3.12' + python-version: '3.13' - name: Install dependencies run: python3 -m pip install --upgrade build twine - name: Build diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cca9f6145..1b247e84e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,14 +13,11 @@ repos: - id: check-merge-conflict - id: end-of-file-fixer - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.7.4 + rev: v0.8.1 hooks: - id: ruff args: ["--fix", "--exit-non-zero-on-fix"] - - repo: https://github.com/psf/black - rev: 24.10.0 - hooks: - - id: black + - id: ruff-format ci: autofix_commit_msg: '[pre-commit.ci] auto fixes from pre-commit.com hooks' diff --git a/pyproject.toml b/pyproject.toml index cf697ceec..7df812df7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,18 +1,6 @@ -[tool.black] -line-length = 120 -include = '\.pyi?$' -target-version = ["py38", "py39", "py310", "py311", "py312"] - [tool.ruff] -# Adds to default excludes: https://docs.astral.sh/ruff/settings/#exclude -extend-exclude = [ - ".*/", - "drf_source", - "stubgen", - "out", -] line-length = 120 -target-version = "py38" +target-version = "py39" # See Rules in Ruff documentation: https://docs.astral.sh/ruff/rules/ [tool.ruff.lint] select = [ diff --git a/requirements.txt b/requirements.txt index 2c87a0012..98ad5152f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,5 @@ wheel -pre-commit==3.5.0; python_version < '3.9' -pre-commit==4.0.1; python_version >= '3.9' +pre-commit==4.0.1 pytest==8.3.4 pytest-mypy-plugins==3.1.2 djangorestframework==3.15.2 diff --git a/rest_framework-stubs/test.pyi b/rest_framework-stubs/test.pyi index ceaf3b0bf..6a163c97f 100644 --- a/rest_framework-stubs/test.pyi +++ b/rest_framework-stubs/test.pyi @@ -60,11 +60,26 @@ class APIRequestFactory(DjangoRequestFactory): 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: _GetDataType = ..., **extra: Any) -> Request: ... # type: ignore[override] - def post(self, path: str, data: Any | None = ..., format: str | None = ..., content_type: str | None = ..., **extra: Any) -> Request: ... # type: ignore[override] - def put(self, path: str, data: Any | None = ..., format: str | None = ..., content_type: str | None = ..., **extra: Any) -> Request: ... # type: ignore[override] - def patch(self, path: str, data: Any | None = ..., format: str | None = ..., content_type: str | None = ..., **extra: Any) -> Request: ... # type: ignore[override] - def delete(self, path: str, data: Any | None = ..., format: str | None = ..., content_type: str | None = ..., **extra: Any) -> Request: ... # type: ignore[override] - def options(self, path: str, data: dict[str, str] | str | None = ..., format: str | None = ..., content_type: Any | None = ..., **extra: Any) -> Request: ... # type: ignore[override] + def post( + self, path: str, data: Any | None = ..., format: str | None = ..., content_type: str | None = ..., **extra: Any + ) -> Request: ... # type: ignore[override] + def put( + self, path: str, data: Any | None = ..., format: str | None = ..., content_type: str | None = ..., **extra: Any + ) -> Request: ... # type: ignore[override] + def patch( + self, path: str, data: Any | None = ..., format: str | None = ..., content_type: str | None = ..., **extra: Any + ) -> Request: ... # type: ignore[override] + def delete( + self, path: str, data: Any | None = ..., format: str | None = ..., content_type: str | None = ..., **extra: Any + ) -> Request: ... # type: ignore[override] + def options( + self, + path: str, + data: dict[str, str] | str | None = ..., + format: str | None = ..., + content_type: Any | None = ..., + **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: ... @@ -80,11 +95,51 @@ class APIClient(APIRequestFactory, DjangoClient): ) -> None: ... def request(self, **kwargs: Any) -> _MonkeyPatchedResponse: ... # type: ignore[override] def get(self, path: str, data: _GetDataType = ..., follow: bool = ..., **extra: Any) -> _MonkeyPatchedResponse: ... # 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 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): diff --git a/rest_framework-stubs/utils/serializer_helpers.pyi b/rest_framework-stubs/utils/serializer_helpers.pyi index ff7c877e1..cca75885e 100644 --- a/rest_framework-stubs/utils/serializer_helpers.pyi +++ b/rest_framework-stubs/utils/serializer_helpers.pyi @@ -18,30 +18,31 @@ class ReturnDict(dict[_KT, _VT], Generic[_KT, _VT]): @overload def __init__(self: ReturnDict[str, _VT], *, serializer: BaseSerializer, **kwargs: _VT) -> None: ... @overload - def __init__(self, __map: SupportsKeysAndGetItem[_KT, _VT], *, serializer: BaseSerializer) -> None: ... + def __init__(self, map: SupportsKeysAndGetItem[_KT, _VT], /, *, serializer: BaseSerializer) -> None: ... @overload def __init__( self: ReturnDict[str, _VT], - __map: SupportsKeysAndGetItem[str, _VT], + map: SupportsKeysAndGetItem[str, _VT], + /, *, serializer: BaseSerializer, **kwargs: _VT, ) -> None: ... @overload - def __init__(self, __iterable: Iterable[tuple[_KT, _VT]], *, serializer: BaseSerializer) -> None: ... + def __init__(self, iterable: Iterable[tuple[_KT, _VT]], /, *, serializer: BaseSerializer) -> None: ... @overload def __init__( - self: ReturnDict[str, _VT], __iterable: Iterable[tuple[str, _VT]], *, serializer: BaseSerializer, **kwargs: _VT + self: ReturnDict[str, _VT], iterable: Iterable[tuple[str, _VT]], /, *, serializer: BaseSerializer, **kwargs: _VT ) -> None: ... # Next two overloads are for dict(string.split(sep) for string in iterable) # Cannot be Iterable[Sequence[_T]] or otherwise dict(["foo", "bar", "baz"]) is not an error @overload def __init__( - self: ReturnDict[str, str], __iterable: Iterable[list[str]], *, serializer: BaseSerializer + self: ReturnDict[str, str], iterable: Iterable[list[str]], /, *, serializer: BaseSerializer ) -> None: ... @overload def __init__( - self: ReturnDict[bytes, bytes], __iterable: Iterable[list[bytes]], *, serializer: BaseSerializer + self: ReturnDict[bytes, bytes], iterable: Iterable[list[bytes]], /, *, serializer: BaseSerializer ) -> None: ... def copy(self) -> ReturnDict[_KT, _VT]: ... def __reduce__(self) -> tuple[type[dict[_KT, _VT]], tuple[dict[_KT, _VT]]]: ... @@ -52,7 +53,7 @@ class ReturnList(list[_T], Generic[_T]): @overload def __init__(self, *, serializer: BaseSerializer) -> None: ... @overload - def __init__(self, __iterable: Iterable[_T], *, serializer: BaseSerializer) -> None: ... + def __init__(self, iterable: Iterable[_T], /, *, serializer: BaseSerializer) -> None: ... def __reduce__(self) -> tuple[type[list[_T]], tuple[list[_T]]]: ... class BoundField: diff --git a/rest_framework-stubs/validators.pyi b/rest_framework-stubs/validators.pyi index 5cf4cd228..918f88134 100644 --- a/rest_framework-stubs/validators.pyi +++ b/rest_framework-stubs/validators.pyi @@ -12,7 +12,7 @@ _V = TypeVar("_V", contravariant=True) class ContextValidator(Protocol[_V]): requires_context: bool - def __call__(self, __value: _V, __context: Field) -> None: ... + def __call__(self, value: _V, context: Field, /) -> None: ... Validator: TypeAlias = Callable[[_V], None] | ContextValidator[_V] diff --git a/setup.py b/setup.py index 3a9b1a62e..ea58bf833 100644 --- a/setup.py +++ b/setup.py @@ -50,15 +50,15 @@ def find_stub_files(name: str) -> List[str]: 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.8", + python_requires=">=3.9", classifiers=[ "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Typing :: Typed", "Framework :: Django", ], From adfda3536db534e02b77a6c0263acdf0823bcc89 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Wed, 4 Dec 2024 22:14:59 +0300 Subject: [PATCH 2/5] Fix mypy --- rest_framework-stubs/test.pyi | 40 +++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/rest_framework-stubs/test.pyi b/rest_framework-stubs/test.pyi index 6a163c97f..adc3b9ba1 100644 --- a/rest_framework-stubs/test.pyi +++ b/rest_framework-stubs/test.pyi @@ -60,26 +60,26 @@ class APIRequestFactory(DjangoRequestFactory): 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: _GetDataType = ..., **extra: Any) -> Request: ... # type: ignore[override] - def post( + def post( # type: ignore[override] self, path: str, data: Any | None = ..., format: str | None = ..., content_type: str | None = ..., **extra: Any - ) -> Request: ... # type: ignore[override] - def put( + ) -> Request: ... + def put( # type: ignore[override] self, path: str, data: Any | None = ..., format: str | None = ..., content_type: str | None = ..., **extra: Any - ) -> Request: ... # type: ignore[override] - def patch( + ) -> Request: ... + def patch( # type: ignore[override] self, path: str, data: Any | None = ..., format: str | None = ..., content_type: str | None = ..., **extra: Any - ) -> Request: ... # type: ignore[override] - def delete( + ) -> Request: ... + def delete( # type: ignore[override] self, path: str, data: Any | None = ..., format: str | None = ..., content_type: str | None = ..., **extra: Any - ) -> Request: ... # type: ignore[override] - def options( + ) -> Request: ... + def options( # type: ignore[override] self, path: str, data: dict[str, str] | str | None = ..., format: str | None = ..., content_type: Any | None = ..., **extra: Any, - ) -> Request: ... # type: ignore[override] + ) -> Request: ... def generic( # type: ignore[override] self, method: str, path: str, data: str = ..., content_type: str = ..., secure: bool = ..., **extra: Any ) -> Request: ... @@ -95,7 +95,7 @@ class APIClient(APIRequestFactory, DjangoClient): ) -> None: ... def request(self, **kwargs: Any) -> _MonkeyPatchedResponse: ... # type: ignore[override] def get(self, path: str, data: _GetDataType = ..., follow: bool = ..., **extra: Any) -> _MonkeyPatchedResponse: ... # type: ignore[override] - def post( + def post( # type: ignore[override] self, path: str, data: Any | None = ..., @@ -103,8 +103,8 @@ class APIClient(APIRequestFactory, DjangoClient): content_type: str | None = ..., follow: bool = ..., **extra: Any, - ) -> _MonkeyPatchedResponse: ... # type: ignore[override] - def put( + ) -> _MonkeyPatchedResponse: ... + def put( # type: ignore[override] self, path: str, data: Any | None = ..., @@ -112,8 +112,8 @@ class APIClient(APIRequestFactory, DjangoClient): content_type: str | None = ..., follow: bool = ..., **extra: Any, - ) -> _MonkeyPatchedResponse: ... # type: ignore[override] - def patch( + ) -> _MonkeyPatchedResponse: ... + def patch( # type: ignore[override] self, path: str, data: Any | None = ..., @@ -121,8 +121,8 @@ class APIClient(APIRequestFactory, DjangoClient): content_type: str | None = ..., follow: bool = ..., **extra: Any, - ) -> _MonkeyPatchedResponse: ... # type: ignore[override] - def delete( + ) -> _MonkeyPatchedResponse: ... + def delete( # type: ignore[override] self, path: str, data: Any | None = ..., @@ -130,8 +130,8 @@ class APIClient(APIRequestFactory, DjangoClient): content_type: str | None = ..., follow: bool = ..., **extra: Any, - ) -> _MonkeyPatchedResponse: ... # type: ignore[override] - def options( + ) -> _MonkeyPatchedResponse: ... + def options( # type: ignore[override] self, path: str, data: dict[str, str] | str = ..., @@ -139,7 +139,7 @@ class APIClient(APIRequestFactory, DjangoClient): content_type: Any | None = ..., follow: bool = ..., **extra: Any, - ) -> _MonkeyPatchedResponse: ... # type: ignore[override] + ) -> _MonkeyPatchedResponse: ... def logout(self) -> None: ... class APITransactionTestCase(testcases.TransactionTestCase): From 1977776d8a04a57b036702a98aff06b1cedac5e4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 4 Dec 2024 19:15:14 +0000 Subject: [PATCH 3/5] [pre-commit.ci] auto fixes from pre-commit.com hooks --- rest_framework-stubs/utils/field_mapping.pyi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rest_framework-stubs/utils/field_mapping.pyi b/rest_framework-stubs/utils/field_mapping.pyi index ea46f5672..a7c7e1093 100644 --- a/rest_framework-stubs/utils/field_mapping.pyi +++ b/rest_framework-stubs/utils/field_mapping.pyi @@ -1,6 +1,6 @@ from _typeshed import Incomplete -from collections.abc import MutableMapping, Sequence -from typing import Any, Generic, Iterator, TypeVar +from collections.abc import Iterator, MutableMapping, Sequence +from typing import Any, Generic, TypeVar from django.db import models from rest_framework.validators import UniqueValidator From a4aee61310747437b515c32a2f14db92aa7254d4 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Wed, 4 Dec 2024 22:23:24 +0300 Subject: [PATCH 4/5] Fix lint --- mypy_drf_plugin/lib/helpers.py | 2 +- mypy_drf_plugin/main.py | 6 +++--- scripts/stubtest/allowlist_todo.txt | 1 + setup.py | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/mypy_drf_plugin/lib/helpers.py b/mypy_drf_plugin/lib/helpers.py index 1a043dc43..9b235fe39 100644 --- a/mypy_drf_plugin/lib/helpers.py +++ b/mypy_drf_plugin/lib/helpers.py @@ -3,5 +3,5 @@ from mypy.nodes import TypeInfo -def get_drf_metadata(info: TypeInfo) -> Dict[str, Any]: +def get_drf_metadata(info: TypeInfo) -> dict[str, Any]: return info.metadata.setdefault("drf", {}) diff --git a/mypy_drf_plugin/main.py b/mypy_drf_plugin/main.py index 614bd322b..c12d97796 100644 --- a/mypy_drf_plugin/main.py +++ b/mypy_drf_plugin/main.py @@ -16,10 +16,10 @@ def transform_serializer_class(ctx: ClassDefContext) -> None: class NewSemanalDRFPlugin(Plugin): - def _get_currently_defined_serializers(self) -> Dict[str, int]: + def _get_currently_defined_serializers(self) -> dict[str, int]: base_serializer_sym = self.lookup_fully_qualified(fullnames.BASE_SERIALIZER_FULLNAME) if base_serializer_sym is not None and isinstance(base_serializer_sym.node, TypeInfo): - serializer_bases: Dict[str, int] = base_serializer_sym.node.metadata.setdefault("drf", {}).setdefault( + serializer_bases: dict[str, int] = base_serializer_sym.node.metadata.setdefault("drf", {}).setdefault( "serializer_bases", {fullnames.BASE_SERIALIZER_FULLNAME: 1} ) return serializer_bases @@ -32,5 +32,5 @@ def get_base_class_hook(self, fullname: str) -> Optional[Callable[[ClassDefConte return None -def plugin(version: str) -> Type[NewSemanalDRFPlugin]: +def plugin(version: str) -> type[NewSemanalDRFPlugin]: return NewSemanalDRFPlugin diff --git a/scripts/stubtest/allowlist_todo.txt b/scripts/stubtest/allowlist_todo.txt index 9b407de32..39773be13 100644 --- a/scripts/stubtest/allowlist_todo.txt +++ b/scripts/stubtest/allowlist_todo.txt @@ -102,6 +102,7 @@ rest_framework.serializers.empty rest_framework.settings.DefaultsSettings rest_framework.settings.api_settings rest_framework.templatetags.rest_framework.urlize_quoted_links +rest_framework.test.CoreAPIClient rest_framework.test.APIClient.options rest_framework.test.RequestsClient.__init__ rest_framework.throttling.SimpleRateThrottle.cache diff --git a/setup.py b/setup.py index ea58bf833..36dac4217 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ from setuptools import find_packages, setup -def find_stub_files(name: str) -> List[str]: +def find_stub_files(name: str) -> list[str]: result = [] for root, _dirs, files in os.walk(name): for file in files: From 1b49181343a06c012271fb1e87c887abae98f225 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 4 Dec 2024 19:25:20 +0000 Subject: [PATCH 5/5] [pre-commit.ci] auto fixes from pre-commit.com hooks --- mypy_drf_plugin/lib/helpers.py | 2 +- mypy_drf_plugin/main.py | 2 +- setup.py | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/mypy_drf_plugin/lib/helpers.py b/mypy_drf_plugin/lib/helpers.py index 9b235fe39..94e07c987 100644 --- a/mypy_drf_plugin/lib/helpers.py +++ b/mypy_drf_plugin/lib/helpers.py @@ -1,4 +1,4 @@ -from typing import Any, Dict +from typing import Any from mypy.nodes import TypeInfo diff --git a/mypy_drf_plugin/main.py b/mypy_drf_plugin/main.py index c12d97796..7905f61cc 100644 --- a/mypy_drf_plugin/main.py +++ b/mypy_drf_plugin/main.py @@ -1,4 +1,4 @@ -from typing import Callable, Dict, Optional, Type +from typing import Callable, Optional from mypy.nodes import TypeInfo from mypy.plugin import ClassDefContext, Plugin diff --git a/setup.py b/setup.py index 36dac4217..a70a3533f 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,4 @@ import os -from typing import List from setuptools import find_packages, setup