diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 91c091bc6..5c78db366 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,15 +21,6 @@ repos: rev: 23.9.1 hooks: - id: black - - repo: https://github.com/PyCQA/flake8 - rev: 6.1.0 - hooks: - - id: flake8 - additional_dependencies: - - flake8-no-pep420==2.6.0 - - flake8-pyi==23.5.0 - types: [] - files: ^.*.pyi?$ - repo: https://github.com/codespell-project/codespell rev: v2.2.6 hooks: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4d4089ea1..580d7bc34 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -55,7 +55,7 @@ pre-commit install ### Testing and Linting -We use `mypy`, `pytest`, `flake8`, and `black` for quality control. All tools except pytest are executed using pre-commit when you make a commit. +We use `mypy`, `pytest`, `ruff`, and `black` for quality control. `ruff` and `black` are executed using pre-commit when you make a commit. To ensure there are not formatting or typing issues in the entire repository you can run: ```bash diff --git a/django-stubs/contrib/admin/decorators.pyi b/django-stubs/contrib/admin/decorators.pyi index 7155aa271..4d4895c03 100644 --- a/django-stubs/contrib/admin/decorators.pyi +++ b/django-stubs/contrib/admin/decorators.pyi @@ -1,5 +1,5 @@ from collections.abc import Callable, Sequence -from typing import Any, TypeVar, overload # noqa: Y037 +from typing import Any, TypeVar, overload from django.contrib.admin import ModelAdmin from django.contrib.admin.sites import AdminSite @@ -15,7 +15,7 @@ _ModelAdmin = TypeVar("_ModelAdmin", bound=ModelAdmin) _Request = TypeVar("_Request", bound=HttpRequest) _QuerySet = TypeVar("_QuerySet", bound=QuerySet) # This is deliberately different from _DisplayT defined in contrib.admin.options -_DisplayCallable: TypeAlias = Callable[[_ModelAdmin, _Model], Any] | Callable[[_Model], Any] # noqa: Y037 +_DisplayCallable: TypeAlias = Callable[[_ModelAdmin, _Model], Any] | Callable[[_Model], Any] _DisplayCallableT = TypeVar("_DisplayCallableT", bound=_DisplayCallable) _ActionReturn = TypeVar("_ActionReturn", bound=HttpResponseBase | None) diff --git a/django-stubs/contrib/admin/options.pyi b/django-stubs/contrib/admin/options.pyi index ad959e3e5..76ac20f0d 100644 --- a/django-stubs/contrib/admin/options.pyi +++ b/django-stubs/contrib/admin/options.pyi @@ -1,5 +1,5 @@ from collections.abc import Callable, Iterable, Iterator, Mapping, Sequence -from typing import Any, Generic, Literal, Optional, TypeVar # noqa: Y037 # https://github.com/python/mypy/issues/12211 +from typing import Any, Generic, Literal, TypeVar from django import forms from django.contrib.admin.filters import FieldListFilter, ListFilter @@ -63,7 +63,6 @@ class _FieldOpts(_OptionalFieldOpts, total=True): # https://github.com/python/mypy/issues/8921 # _FieldsetSpec = Sequence[Tuple[Optional[str], _FieldOpts]] _FieldsetSpec: TypeAlias = _ListOrTuple[tuple[_StrOrPromise | None, _FieldOpts]] -# https://github.com/python/mypy/issues/12211 _ListFilterT: TypeAlias = ( type[ListFilter] | Field @@ -81,7 +80,7 @@ class BaseModelAdmin(Generic[_ModelT]): raw_id_fields: Sequence[str] fields: _FieldGroups | None exclude: Sequence[str] | None - fieldsets: Optional[_FieldsetSpec] # noqa: UP007 + fieldsets: _FieldsetSpec | None form: type[forms.ModelForm[_ModelT]] filter_vertical: Sequence[str] filter_horizontal: Sequence[str] diff --git a/django-stubs/contrib/auth/management/commands/createsuperuser.pyi b/django-stubs/contrib/auth/management/commands/createsuperuser.pyi index efc0752a0..57d205de2 100644 --- a/django-stubs/contrib/auth/management/commands/createsuperuser.pyi +++ b/django-stubs/contrib/auth/management/commands/createsuperuser.pyi @@ -1,4 +1,4 @@ -import getpass as getpass # noqa: F401 +import getpass as getpass from typing import Any from django.core.management.base import BaseCommand diff --git a/django-stubs/contrib/gis/db/models/__init__.pyi b/django-stubs/contrib/gis/db/models/__init__.pyi index 47d6738a8..bc6770aae 100644 --- a/django-stubs/contrib/gis/db/models/__init__.pyi +++ b/django-stubs/contrib/gis/db/models/__init__.pyi @@ -1,4 +1,3 @@ -# noqa: F401 from django.contrib.gis.db.models.aggregates import * from django.contrib.gis.db.models.fields import GeometryCollectionField as GeometryCollectionField from django.contrib.gis.db.models.fields import GeometryField as GeometryField diff --git a/django-stubs/contrib/gis/geos/io.pyi b/django-stubs/contrib/gis/geos/io.pyi index fb65ab711..21528286e 100644 --- a/django-stubs/contrib/gis/geos/io.pyi +++ b/django-stubs/contrib/gis/geos/io.pyi @@ -1,5 +1,5 @@ from django.contrib.gis.geos.geometry import GEOSGeometry -from django.contrib.gis.geos.prototypes.io import WKBWriter as WKBWriter # noqa: F401 +from django.contrib.gis.geos.prototypes.io import WKBWriter as WKBWriter from django.contrib.gis.geos.prototypes.io import WKTWriter as WKTWriter from django.contrib.gis.geos.prototypes.io import _WKBReader, _WKTReader diff --git a/django-stubs/core/validators.pyi b/django-stubs/core/validators.pyi index 5c6c97c8d..4a6dc7396 100644 --- a/django-stubs/core/validators.pyi +++ b/django-stubs/core/validators.pyi @@ -11,7 +11,7 @@ EMPTY_VALUES: Any _Regex: TypeAlias = str | Pattern[str] -_ValidatorCallable: TypeAlias = Callable[[Any], None] # noqa: Y047 +_ValidatorCallable: TypeAlias = Callable[[Any], None] # noqa: PYI047 class RegexValidator: regex: _Regex # Pattern[str] on instance, but may be str on class definition diff --git a/django-stubs/db/models/fields/__init__.pyi b/django-stubs/db/models/fields/__init__.pyi index b1383e593..5917eef88 100644 --- a/django-stubs/db/models/fields/__init__.pyi +++ b/django-stubs/db/models/fields/__init__.pyi @@ -45,7 +45,7 @@ class _FieldDescriptor(Protocol[_F]): @property def field(self) -> _F: ... -_AllLimitChoicesTo: TypeAlias = _LimitChoicesTo | _ChoicesCallable # noqa: Y047 +_AllLimitChoicesTo: TypeAlias = _LimitChoicesTo | _ChoicesCallable # noqa: PYI047 _ErrorMessagesMapping: TypeAlias = Mapping[str, _StrOrPromise] _ErrorMessagesDict: TypeAlias = dict[str, _StrOrPromise] diff --git a/django-stubs/db/models/fields/related.pyi b/django-stubs/db/models/fields/related.pyi index 7f09d3373..d5c36ccc9 100644 --- a/django-stubs/db/models/fields/related.pyi +++ b/django-stubs/db/models/fields/related.pyi @@ -8,14 +8,12 @@ from django.db.models.expressions import Combinable from django.db.models.fields import Field, _AllLimitChoicesTo, _ErrorMessagesMapping, _FieldChoices, _LimitChoicesTo from django.db.models.fields.mixins import FieldCacheMixin from django.db.models.fields.related_descriptors import ForwardManyToOneDescriptor as ForwardManyToOneDescriptor -from django.db.models.fields.related_descriptors import ( # noqa: F401 - ForwardOneToOneDescriptor as ForwardOneToOneDescriptor, -) +from django.db.models.fields.related_descriptors import ForwardOneToOneDescriptor as ForwardOneToOneDescriptor from django.db.models.fields.related_descriptors import ManyRelatedManager from django.db.models.fields.related_descriptors import ManyToManyDescriptor as ManyToManyDescriptor from django.db.models.fields.related_descriptors import ReverseManyToOneDescriptor as ReverseManyToOneDescriptor from django.db.models.fields.related_descriptors import ReverseOneToOneDescriptor as ReverseOneToOneDescriptor -from django.db.models.fields.reverse_related import ForeignObjectRel as ForeignObjectRel # noqa: F401 +from django.db.models.fields.reverse_related import ForeignObjectRel as ForeignObjectRel from django.db.models.fields.reverse_related import ManyToManyRel as ManyToManyRel from django.db.models.fields.reverse_related import ManyToOneRel as ManyToOneRel from django.db.models.fields.reverse_related import OneToOneRel as OneToOneRel diff --git a/django-stubs/db/models/options.pyi b/django-stubs/db/models/options.pyi index 4216bbad2..4385e5d2c 100644 --- a/django-stubs/db/models/options.pyi +++ b/django-stubs/db/models/options.pyi @@ -1,11 +1,5 @@ from collections.abc import Iterable, Sequence -from typing import ( # noqa: Y037 # https://github.com/python/mypy/issues/12211 - Any, - Generic, - Literal, - TypeVar, - overload, -) +from typing import Any, Generic, Literal, TypeVar, overload from django.apps.config import AppConfig from django.apps.registry import Apps @@ -27,8 +21,7 @@ EMPTY_RELATION_TREE: Any IMMUTABLE_WARNING: str DEFAULT_NAMES: tuple[str, ...] -# https://github.com/python/mypy/issues/12211 -_OptionTogetherT: TypeAlias = _ListOrTuple[_ListOrTuple[str] | str] | set[tuple[str, ...]] # noqa: Y047 +_OptionTogetherT: TypeAlias = _ListOrTuple[_ListOrTuple[str] | str] | set[tuple[str, ...]] # noqa: PYI047 @overload def normalize_together(option_together: _ListOrTuple[_ListOrTuple[str] | str]) -> tuple[tuple[str, ...], ...]: ... diff --git a/django-stubs/db/models/query.pyi b/django-stubs/db/models/query.pyi index 92dac1703..5b19ab7bb 100644 --- a/django-stubs/db/models/query.pyi +++ b/django-stubs/db/models/query.pyi @@ -215,7 +215,7 @@ class RawQuerySet(Iterable[_T], Sized): def resolve_model_init_order(self) -> tuple[list[str], list[int], list[tuple[str, int]]]: ... def using(self, alias: str | None) -> RawQuerySet[_T]: ... -_QuerySetAny: TypeAlias = _QuerySet # noqa: Y047 +_QuerySetAny: TypeAlias = _QuerySet # noqa: PYI047 QuerySet: TypeAlias = _QuerySet[_T, _T] diff --git a/django-stubs/forms/models.pyi b/django-stubs/forms/models.pyi index 4b4aa287b..a1a3d2ebb 100644 --- a/django-stubs/forms/models.pyi +++ b/django-stubs/forms/models.pyi @@ -1,12 +1,5 @@ from collections.abc import Callable, Collection, Container, Iterator, Mapping, Sequence -from typing import ( # noqa: Y037 # https://github.com/python/mypy/issues/12211 - Any, - ClassVar, - Generic, - Literal, - TypeVar, - overload, -) +from typing import Any, ClassVar, Generic, Literal, TypeVar, overload from uuid import UUID from django.db import models @@ -27,7 +20,6 @@ from typing_extensions import TypeAlias ALL_FIELDS: Literal["__all__"] -# https://github.com/python/mypy/issues/12211 _Fields: TypeAlias = _ListOrTuple[str] | Literal["__all__"] _Widgets: TypeAlias = dict[str, type[Widget] | Widget] diff --git a/django-stubs/forms/utils.pyi b/django-stubs/forms/utils.pyi index 5b6bf46cd..f49dd0c02 100644 --- a/django-stubs/forms/utils.pyi +++ b/django-stubs/forms/utils.pyi @@ -11,9 +11,9 @@ from django.utils.functional import _StrOrPromise from django.utils.safestring import SafeString from typing_extensions import TypeAlias -_DataT: TypeAlias = Mapping[str, Any] # noqa: Y047 +_DataT: TypeAlias = Mapping[str, Any] # noqa: PYI047 -_FilesT: TypeAlias = MultiValueDict[str, UploadedFile] # noqa: Y047 +_FilesT: TypeAlias = MultiValueDict[str, UploadedFile] # noqa: PYI047 def pretty_name(name: str) -> str: ... def flatatt(attrs: dict[str, Any]) -> SafeString: ... diff --git a/django-stubs/template/base.pyi b/django-stubs/template/base.pyi index 523e9049d..4d0926f12 100644 --- a/django-stubs/template/base.pyi +++ b/django-stubs/template/base.pyi @@ -4,7 +4,7 @@ from logging import Logger from re import Pattern from typing import Any -from django.template.context import Context as Context # noqa: F401 # Django: imported for backwards compatibility +from django.template.context import Context as Context # Django: imported for backwards compatibility from django.template.engine import Engine from django.template.library import Library from django.template.loaders.base import Loader diff --git a/django-stubs/template/loader.pyi b/django-stubs/template/loader.pyi index 1e0a3fd83..f99d3293c 100644 --- a/django-stubs/template/loader.pyi +++ b/django-stubs/template/loader.pyi @@ -2,7 +2,7 @@ from collections.abc import Mapping, Sequence from typing import Any from django.http.request import HttpRequest -from django.template.exceptions import TemplateDoesNotExist as TemplateDoesNotExist # noqa: F401 +from django.template.exceptions import TemplateDoesNotExist as TemplateDoesNotExist from django.utils.safestring import SafeString from .backends.base import _EngineTemplate diff --git a/django-stubs/template/response.pyi b/django-stubs/template/response.pyi index b3c4bf611..1e94b0a58 100644 --- a/django-stubs/template/response.pyi +++ b/django-stubs/template/response.pyi @@ -1,7 +1,7 @@ import functools from collections.abc import Callable, Iterator, Sequence from http.cookies import SimpleCookie -from typing import Any # noqa: Y037 # https://github.com/python/mypy/issues/12211 +from typing import Any from django.core.handlers.wsgi import WSGIRequest from django.http import HttpResponse @@ -12,7 +12,6 @@ from django.test.client import Client from django.utils.datastructures import _ListOrTuple from typing_extensions import TypeAlias -# https://github.com/python/mypy/issues/12211 _TemplateForResponseT: TypeAlias = _ListOrTuple[str] | Template | str class ContentNotRenderedError(Exception): ... diff --git a/django-stubs/test/signals.pyi b/django-stubs/test/signals.pyi index b97709d0a..00ef8e95e 100644 --- a/django-stubs/test/signals.pyi +++ b/django-stubs/test/signals.pyi @@ -1,6 +1,6 @@ from typing import Any -from django.core.signals import setting_changed as setting_changed # noqa: F401 +from django.core.signals import setting_changed as setting_changed template_rendered: Any COMPLEX_OVERRIDE_SETTINGS: Any diff --git a/django-stubs/test/testcases.pyi b/django-stubs/test/testcases.pyi index 7ddd712c8..3b0466f17 100644 --- a/django-stubs/test/testcases.pyi +++ b/django-stubs/test/testcases.pyi @@ -8,7 +8,7 @@ from typing import Any, overload from django.core.exceptions import ImproperlyConfigured from django.core.handlers.wsgi import WSGIHandler from django.core.servers.basehttp import ThreadedWSGIServer, WSGIRequestHandler -from django.db import connections # noqa: F401 +from django.db import connections as connections from django.db.backends.base.base import BaseDatabaseWrapper from django.db.models.base import Model from django.db.models.query import QuerySet, RawQuerySet diff --git a/django-stubs/test/utils.pyi b/django-stubs/test/utils.pyi index f741ff404..a19c4bc0e 100644 --- a/django-stubs/test/utils.pyi +++ b/django-stubs/test/utils.pyi @@ -48,7 +48,7 @@ class TestContextDecorator: def __init__(self, attr_name: str | None = ..., kwarg_name: str | None = ...) -> None: ... def enable(self) -> Any: ... def disable(self) -> None: ... - def __enter__(self) -> Apps | None: ... # noqa: Y034 + def __enter__(self) -> Apps | None: ... def __exit__( self, exc_type: type[BaseException] | None, diff --git a/django-stubs/urls/__init__.pyi b/django-stubs/urls/__init__.pyi index 3eb258288..7949b5f93 100644 --- a/django-stubs/urls/__init__.pyi +++ b/django-stubs/urls/__init__.pyi @@ -37,4 +37,4 @@ from .resolvers import get_resolver as get_resolver from .utils import get_callable as get_callable from .utils import get_mod_func as get_mod_func -_AnyURL: TypeAlias = URLPattern | URLResolver # noqa: Y047 +_AnyURL: TypeAlias = URLPattern | URLResolver # noqa: PYI047 diff --git a/django-stubs/utils/datastructures.pyi b/django-stubs/utils/datastructures.pyi index ffbc93cf6..20089f3e3 100644 --- a/django-stubs/utils/datastructures.pyi +++ b/django-stubs/utils/datastructures.pyi @@ -1,5 +1,5 @@ from collections.abc import Collection, Iterable, Iterator, Mapping, MutableMapping, MutableSet -from typing import Any, Generic, NoReturn, Protocol, TypeVar, overload # noqa: Y022 +from typing import Any, Generic, NoReturn, Protocol, TypeVar, overload from _typeshed import Incomplete from typing_extensions import Self, TypeAlias @@ -11,7 +11,7 @@ _I = TypeVar("_I", covariant=True) # Unfortunately, there's often check `if isinstance(var, (list, tuple))` in django # codebase. So we need sometimes to declare exactly list or tuple. -_ListOrTuple: TypeAlias = list[_K] | tuple[_K, ...] | tuple[()] # noqa: Y047 +_ListOrTuple: TypeAlias = list[_K] | tuple[_K, ...] | tuple[()] # noqa: PYI047 class _PropertyDescriptor(Generic[_K, _V]): """ diff --git a/django-stubs/utils/functional.pyi b/django-stubs/utils/functional.pyi index b1f192a60..20d396059 100644 --- a/django-stubs/utils/functional.pyi +++ b/django-stubs/utils/functional.pyi @@ -44,7 +44,7 @@ class _StrPromise(Promise, Sequence[str]): # Mypy requires this for the attribute hook to take effect def __getattribute__(self, __name: str) -> Any: ... -_StrOrPromise: TypeAlias = str | _StrPromise # noqa: Y047 +_StrOrPromise: TypeAlias = str | _StrPromise # noqa: PYI047 _C = TypeVar("_C", bound=Callable) def lazy(func: _C, *resultclasses: Any) -> _C: ... diff --git a/django-stubs/utils/translation/trans_real.pyi b/django-stubs/utils/translation/trans_real.pyi index e2ab118ee..e58fd978d 100644 --- a/django-stubs/utils/translation/trans_real.pyi +++ b/django-stubs/utils/translation/trans_real.pyi @@ -4,7 +4,7 @@ from gettext import NullTranslations from re import Pattern # switch to tuple once https://github.com/python/mypy/issues/11098 is fixed -from typing import Any, Literal, Protocol, TypeVar # noqa: Y022 +from typing import Any, Literal, Protocol, TypeVar from django.http.request import HttpRequest from typing_extensions import TypeAlias diff --git a/mypy_django_plugin/django/context.py b/mypy_django_plugin/django/context.py index b3dc6df42..347ec92ef 100644 --- a/mypy_django_plugin/django/context.py +++ b/mypy_django_plugin/django/context.py @@ -48,8 +48,8 @@ class ArrayField: # type: ignore[no-redef] if TYPE_CHECKING: - from django.apps.registry import Apps # noqa: F401 - from django.conf import LazySettings # noqa: F401 + from django.apps.registry import Apps + from django.conf import LazySettings from django.contrib.contenttypes.fields import GenericForeignKey diff --git a/mypy_django_plugin/transformers/models.py b/mypy_django_plugin/transformers/models.py index 5dc371ff8..903d2b137 100644 --- a/mypy_django_plugin/transformers/models.py +++ b/mypy_django_plugin/transformers/models.py @@ -498,7 +498,7 @@ def run_with_model_cls(self, model_cls: Type[Model]) -> None: try: related_manager_info = self.lookup_typeinfo_or_incomplete_defn_error( fullnames.RELATED_MANAGER_CLASS - ) # noqa: E501 + ) default_manager = related_model_info.names.get("_default_manager") if not default_manager: raise helpers.IncompleteDefnException() @@ -776,7 +776,7 @@ def resolve_many_to_many_arguments(self, call: CallExpr, /, context: Context) -> look_for["through"] = call.args[5] # Sort out if any of the expected arguments was provided as keyword arguments - for arg_expr, arg_kind, arg_name in zip(call.args, call.arg_kinds, call.arg_names): + for arg_expr, _arg_kind, arg_name in zip(call.args, call.arg_kinds, call.arg_names): if arg_name in look_for and look_for[arg_name] is None: look_for[arg_name] = arg_expr diff --git a/pyproject.toml b/pyproject.toml index 510a37bf1..dbb28d548 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,6 +9,7 @@ ignore-words-list = "aadd,acount,nam" [tool.ruff] # Adds to default excludes: https://ruff.rs/docs/settings/#exclude extend-exclude = [ + ".*/", "django-source", "stubgen", "out", @@ -17,12 +18,35 @@ line-length = 120 target-version = "py38" # See Rules in Ruff documentation: https://beta.ruff.rs/docs/rules/ select = [ + "B", # bugbear + "E", # pycodestyle + "F", # pyflakes + "INP", # flake8-tidy-imports + "W", # pycodestyle "I", # isort - "F401", # Unused imports "UP", # pyupgrade "TID251", # Disallowed imports (flake8-tidy-imports.banned-api) + "PYI", # flake8-pyi + "RUF100", # Equivalent to flake8-noqa NQA103 + "PGH004", # Equivalent to flake8-noqa NQA104 "PGH003", # Disallowed blanket `type: ignore` annotations. ] +ignore = ["PYI021", "PYI024", "PYI041", "PYI043"] + +[tool.ruff.per-file-ignores] +"*.pyi" = [ + "B", + "E501", + "E741", + "E743", + "F403", # Use wildcard import + "F405", + "F822", + "F821", +] +"tests/*.py" = ["INP001"] +"ext/tests/*.py" = ["INP001"] +"setup.py" = ["INP001"] [tool.ruff.flake8-tidy-imports.banned-api] "_typeshed.Self".msg = "Use typing_extensions.Self (PEP 673) instead." diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 5fe224a74..000000000 --- a/setup.cfg +++ /dev/null @@ -1,9 +0,0 @@ -[flake8] -exclude = .*/ -extend-ignore = E203 -max_line_length = 120 -per-file-ignores = - *.pyi: B, E301, E302, E305, E501, E701, E741, E743, NQA102, F401, F403, F405, F822, Y021, Y024, Y041, Y043 - setup.py: INP001 - tests/*.py: INP001 - ext/tests/*.py: INP001