diff --git a/docs/conf.py b/docs/conf.py index 83487358..9292d849 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -8,7 +8,6 @@ import re import sys -import sphinx_rtd_theme from docutils import nodes, utils from docutils.parsers.rst import roles from docutils.parsers.rst.roles import set_classes diff --git a/pyproject.toml b/pyproject.toml index 81fdad32..74d7821c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,75 @@ [build-system] -requires = ["setuptools >= 68.0.0", "wheel", "setuptools-scm >= 3.0.3"] build-backend = "setuptools.build_meta" + +requires = [ "setuptools>=68", "setuptools-scm>=3.0.3", "wheel" ] + +[tool.ruff] +exclude = [ "**/migrations/*" ] +line-length = 169 +lint.select = [ + "AIR", # Airflow + "ASYNC", # flake8-async + "C4", # flake8-comprehensions + "C90", # mccabe + "E", # pycodestyle errors + "F", # Pyflakes + "FA", # flake8-future-annotations + "FLY", # flynt + "I", # isort + "ICN", # flake8-import-conventions + "INT", # flake8-gettext + "LOG", # flake8-logging + "NPY", # NumPy-specific rules + "PD", # pandas-vet + "PLE", # Pylint errors + "PYI", # flake8-pyi + "SLOT", # flake8-slots + "T10", # flake8-debugger + "TCH", # flake8-type-checking + "W", # pycodestyle warnings + "YTT", # flake8-2020 + # "A", # flake8-builtins + # "ANN", # flake8-annotations + # "ARG", # flake8-unused-arguments + # "B", # flake8-bugbear + # "BLE", # flake8-blind-except + # "COM", # flake8-commas + # "CPY", # flake8-copyright + # "D", # pydocstyle + # "DJ", # flake8-django + # "DOC", # pydoclint + # "DTZ", # flake8-datetimez + # "EM", # flake8-errmsg + # "ERA", # eradicate + # "EXE", # flake8-executable + # "FAST", # FastAPI + # "FBT", # flake8-boolean-trap + # "FIX", # flake8-fixme + # "FURB", # refurb + # "G", # flake8-logging-format + # "INP", # flake8-no-pep420 + # "ISC", # flake8-implicit-str-concat + # "N", # pep8-naming + # "PERF", # Perflint + # "PGH", # pygrep-hooks + # "PIE", # flake8-pie + # "PLC", # Pylint conventions + # "PLR", # Pylint refactorings + # "PLW", # Pylint warnings + # "PT", # flake8-pytest-style + # "PTH", # flake8-use-pathlib + # "Q", # flake8-quotes + # "RET", # flake8-return + # "RSE", # flake8-raise + # "RUF", # Ruff-specific rules + # "S", # flake8-bandit + # "SIM", # flake8-simplify + # "SLF", # flake8-self + # "T20", # flake8-print + # "TD", # flake8-todos + # "TID", # flake8-tidy-imports + # "TRY", # tryceratops + # "UP", # pyupgrade +] +lint.isort.known-first-party = [ "drf_yasg", "testproj", "articles", "people", "snippets", "todo", "users", "urlconfs" ] +lint.mccabe.max-complexity = 13 diff --git a/requirements/lint.txt b/requirements/lint.txt index 62505c5d..5784c72b 100644 --- a/requirements/lint.txt +++ b/requirements/lint.txt @@ -1,4 +1,2 @@ -# used by the 'lint' tox env for linting via flake8 -isort>=5.12 -flake8>=6.0.0 -flake8-isort>=6.0.0 +# used by the 'lint' tox env for linting via ruff +ruff>=0.70.0 diff --git a/src/drf_yasg/codecs.py b/src/drf_yasg/codecs.py index fd989cb5..78442af7 100644 --- a/src/drf_yasg/codecs.py +++ b/src/drf_yasg/codecs.py @@ -3,8 +3,8 @@ import logging from collections import OrderedDict -from django.utils.encoding import force_bytes import yaml +from django.utils.encoding import force_bytes try: from swagger_spec_validator.common import SwaggerValidationError as SSVErr diff --git a/src/drf_yasg/generators.py b/src/drf_yasg/generators.py index 80489dee..6f821755 100644 --- a/src/drf_yasg/generators.py +++ b/src/drf_yasg/generators.py @@ -7,9 +7,9 @@ import uritemplate from django.urls import URLPattern, URLResolver from rest_framework import versioning -from rest_framework.schemas.openapi import SchemaGenerator from rest_framework.schemas.generators import EndpointEnumerator as _EndpointEnumerator from rest_framework.schemas.generators import endpoint_ordering, get_pk_name +from rest_framework.schemas.openapi import SchemaGenerator from rest_framework.schemas.utils import get_pk_description, is_list_view from rest_framework.settings import api_settings diff --git a/src/drf_yasg/inspectors/__init__.py b/src/drf_yasg/inspectors/__init__.py index 70bde798..1030d157 100644 --- a/src/drf_yasg/inspectors/__init__.py +++ b/src/drf_yasg/inspectors/__init__.py @@ -1,13 +1,21 @@ from ..app_settings import swagger_settings -from .base import ( - BaseInspector, FieldInspector, FilterInspector, NotHandled, PaginatorInspector, SerializerInspector, ViewInspector -) +from .base import BaseInspector, FieldInspector, FilterInspector, NotHandled, PaginatorInspector, SerializerInspector, ViewInspector from .field import ( - CamelCaseJSONFilter, ChoiceFieldInspector, DictFieldInspector, FileFieldInspector, HiddenFieldInspector, - InlineSerializerInspector, JSONFieldInspector, RecursiveFieldInspector, ReferencingSerializerInspector, - RelatedFieldInspector, SerializerMethodFieldInspector, SimpleFieldInspector, StringDefaultFieldInspector + CamelCaseJSONFilter, + ChoiceFieldInspector, + DictFieldInspector, + FileFieldInspector, + HiddenFieldInspector, + InlineSerializerInspector, + JSONFieldInspector, + RecursiveFieldInspector, + ReferencingSerializerInspector, + RelatedFieldInspector, + SerializerMethodFieldInspector, + SimpleFieldInspector, + StringDefaultFieldInspector, ) -from .query import DrfAPICompatInspector, CoreAPICompatInspector, DjangoRestResponsePagination +from .query import CoreAPICompatInspector, DjangoRestResponsePagination, DrfAPICompatInspector from .view import SwaggerAutoSchema # these settings must be accessed only after defining/importing all the classes in this module to avoid ImportErrors diff --git a/src/drf_yasg/inspectors/field.py b/src/drf_yasg/inspectors/field.py index 4d456fbf..64740b45 100644 --- a/src/drf_yasg/inspectors/field.py +++ b/src/drf_yasg/inspectors/field.py @@ -2,25 +2,23 @@ import inspect import logging import operator +import typing import uuid -from contextlib import suppress from collections import OrderedDict +from contextlib import suppress from decimal import Decimal from inspect import signature as inspect_signature -import typing from django.core import validators from django.db import models from packaging import version from rest_framework import serializers from rest_framework.settings import api_settings as rest_framework_settings -from .base import call_view_method, FieldInspector, NotHandled, SerializerInspector from .. import openapi from ..errors import SwaggerGenerationError -from ..utils import ( - decimal_as_float, field_value_to_representation, filter_none, get_serializer_class, get_serializer_ref_name -) +from ..utils import decimal_as_float, field_value_to_representation, filter_none, get_serializer_class, get_serializer_ref_name +from .base import FieldInspector, NotHandled, SerializerInspector, call_view_method try: from importlib import metadata @@ -191,9 +189,9 @@ def get_queryset_from_view(view, serializer=None): try: queryset = call_view_method(view, 'get_queryset', 'queryset') - if queryset is not None and serializer is not None: + if queryset and serializer: # make sure the view is actually using *this* serializer - assert type(serializer) == call_view_method(view, 'get_serializer_class', 'serializer_class') + assert isinstance(call_view_method(view, 'get_serializer_class', 'serializer_class'), serializer) return queryset except Exception: # pragma: no cover diff --git a/src/drf_yasg/inspectors/query.py b/src/drf_yasg/inspectors/query.py index fafcb02d..c20984af 100644 --- a/src/drf_yasg/inspectors/query.py +++ b/src/drf_yasg/inspectors/query.py @@ -8,7 +8,7 @@ from .. import openapi from ..utils import force_real_str -from .base import FilterInspector, PaginatorInspector, NotHandled +from .base import FilterInspector, NotHandled, PaginatorInspector def ignore_assert_decorator(func): diff --git a/src/drf_yasg/inspectors/view.py b/src/drf_yasg/inspectors/view.py index 71bfbf35..4100b6f6 100644 --- a/src/drf_yasg/inspectors/view.py +++ b/src/drf_yasg/inspectors/view.py @@ -7,10 +7,7 @@ from .. import openapi from ..errors import SwaggerGenerationError -from ..utils import ( - filter_none, force_real_str, force_serializer_instance, get_consumes, get_produces, guess_response_status, - merge_params, no_body, param_list_to_odict -) +from ..utils import filter_none, force_real_str, force_serializer_instance, get_consumes, get_produces, guess_response_status, merge_params, no_body, param_list_to_odict from .base import ViewInspector, call_view_method logger = logging.getLogger(__name__) diff --git a/src/drf_yasg/openapi.py b/src/drf_yasg/openapi.py index 0a2cfb8f..6927780c 100644 --- a/src/drf_yasg/openapi.py +++ b/src/drf_yasg/openapi.py @@ -2,7 +2,8 @@ import logging import re import urllib.parse as urlparse -from collections import OrderedDict, abc as collections_abc +from collections import OrderedDict +from collections import abc as collections_abc from django.urls import get_script_prefix from django.utils.functional import Promise @@ -88,7 +89,7 @@ class SwaggerDict(OrderedDict): def __init__(self, **attrs): super(SwaggerDict, self).__init__() self._extras__ = attrs - if type(self) == SwaggerDict: + if isinstance(self, SwaggerDict): self._insert_extras__() def __setattr__(self, key, value): @@ -516,7 +517,7 @@ def __init__(self, resolver, name, scope, expected_type, ignore_unresolved=False :param bool ignore_unresolved: do not throw if the referenced object does not exist """ super(_Ref, self).__init__() - assert not type(self) == _Ref, "do not instantiate _Ref directly" + assert not isinstance(self, _Ref), "do not instantiate _Ref directly" ref_name = "#/{scope}/{name}".format(scope=scope, name=name) if not ignore_unresolved: obj = resolver.get(name, scope) diff --git a/src/drf_yasg/utils.py b/src/drf_yasg/utils.py index 494ce48c..fe0ec472 100644 --- a/src/drf_yasg/utils.py +++ b/src/drf_yasg/utils.py @@ -442,7 +442,7 @@ def force_real_str(s, encoding='utf-8', strings_only=False, errors='strict'): """ if s is not None: s = force_str(s, encoding, strings_only, errors) - if type(s) != str: + if not isinstance(s, str): s = '' + s # Remove common indentation to get the correct Markdown rendering diff --git a/testproj/testproj/settings/heroku.py b/testproj/testproj/settings/heroku.py index ccdcb342..31c9f276 100644 --- a/testproj/testproj/settings/heroku.py +++ b/testproj/testproj/settings/heroku.py @@ -1,6 +1,8 @@ +import os + import dj_database_url -from .base import * # noqa: F403 +from .base import ALLOWED_HOSTS, MIDDLEWARE DEBUG = True diff --git a/testproj/testproj/settings/local.py b/testproj/testproj/settings/local.py index 342912a8..ce695d50 100644 --- a/testproj/testproj/settings/local.py +++ b/testproj/testproj/settings/local.py @@ -2,7 +2,7 @@ import dj_database_url -from .base import * # noqa: F403 +from .base import BASE_DIR, SWAGGER_SETTINGS SWAGGER_SETTINGS.update({'VALIDATOR_URL': 'http://localhost:8189'}) diff --git a/testproj/todo/views.py b/testproj/todo/views.py index e351b221..ccfe30d3 100644 --- a/testproj/todo/views.py +++ b/testproj/todo/views.py @@ -5,10 +5,7 @@ from drf_yasg.utils import swagger_auto_schema from .models import Pack, Todo, TodoAnother, TodoTree, TodoYetAnother -from .serializer import ( - HarvestSerializer, TodoAnotherSerializer, TodoRecursiveSerializer, TodoSerializer, TodoTreeSerializer, - TodoYetAnotherSerializer -) +from .serializer import HarvestSerializer, TodoAnotherSerializer, TodoRecursiveSerializer, TodoSerializer, TodoTreeSerializer, TodoYetAnotherSerializer class TodoViewSet(viewsets.ReadOnlyModelViewSet): diff --git a/tests/test_versioning.py b/tests/test_versioning.py index 3e77f1f5..a107280c 100644 --- a/tests/test_versioning.py +++ b/tests/test_versioning.py @@ -1,7 +1,7 @@ import pytest -from drf_yasg.errors import SwaggerGenerationError from drf_yasg.codecs import yaml_sane_load +from drf_yasg.errors import SwaggerGenerationError def _get_versioned_schema(prefix, client, validate_schema, path='/snippets/'): diff --git a/tests/urlconfs/additional_fields_checks.py b/tests/urlconfs/additional_fields_checks.py index c7cea8e6..141a77c6 100644 --- a/tests/urlconfs/additional_fields_checks.py +++ b/tests/urlconfs/additional_fields_checks.py @@ -3,7 +3,7 @@ from testproj.urls import required_urlpatterns -from .url_versioning import SnippetList, SnippetSerializer, VersionedSchemaView, VERSION_PREFIX_URL +from .url_versioning import VERSION_PREFIX_URL, SnippetList, SnippetSerializer, VersionedSchemaView class SnippetsSerializer(serializers.HyperlinkedModelSerializer, SnippetSerializer): diff --git a/tests/urlconfs/coreschema.py b/tests/urlconfs/coreschema.py index bb55c8c9..7096bab0 100644 --- a/tests/urlconfs/coreschema.py +++ b/tests/urlconfs/coreschema.py @@ -1,11 +1,11 @@ -from django.urls import re_path import coreapi import coreschema +from django.urls import re_path from rest_framework import pagination from testproj.urls import required_urlpatterns -from .url_versioning import SnippetList, VersionedSchemaView, VERSION_PREFIX_URL +from .url_versioning import VERSION_PREFIX_URL, SnippetList, VersionedSchemaView class FilterBackendWithoutParams: diff --git a/tests/urlconfs/url_versioning_extra.py b/tests/urlconfs/url_versioning_extra.py index 25bb67f9..d52bd628 100644 --- a/tests/urlconfs/url_versioning_extra.py +++ b/tests/urlconfs/url_versioning_extra.py @@ -2,7 +2,7 @@ from testproj.urls import required_urlpatterns -from .url_versioning import SnippetList, VERSION_PREFIX_URL, VersionedSchemaView +from .url_versioning import VERSION_PREFIX_URL, SnippetList, VersionedSchemaView urlpatterns = required_urlpatterns + [ re_path(VERSION_PREFIX_URL + r"extra/snippets/$", SnippetList.as_view()), diff --git a/tox.ini b/tox.ini index 3d088b96..77f1a567 100644 --- a/tox.ini +++ b/tox.ini @@ -62,7 +62,7 @@ skip_install = true deps = -r requirements/lint.txt commands = - flake8 src/drf_yasg testproj tests setup.py + ruff check [testenv:py38-docs] deps =