Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 17 additions & 15 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,24 @@ jobs:
strategy:
matrix:
# https://github.com/actions/python-versions/blob/main/versions-manifest.json
python-version: [3.8, 3.9, "3.10", "3.11", "3.12", "3.13"]
python-version: [3.9, "3.10", "3.11", "3.12", "3.13"]
django-version:
- "Django>=4.2,<5.0"
- "Django>=5.0,<5.1"
- "Django>=5.1,<5.2"
- "Django==5.2a1"
# - "https://github.com/django/django/archive/main.tar.gz"
include:
- drf: djangorestframework
python-version: "3.12"
django-version: "Django<5.2,>=5.0" # must be different from django-version
exclude:
- django-version: "Django>=5.0,<5.1"
python-version: 3.8
- django-version: "Django>=5.0,<5.1"
python-version: 3.9
- django-version: "Django>=5.1,<5.2"
python-version: 3.8
- django-version: "Django>=5.1,<5.2"
python-version: 3.9
- django-version: "Django==5.2a1"
python-version: 3.9
# - django-version: "https://github.com/django/django/archive/main.tar.gz"
# python-version: 3.8
# - django-version: "https://github.com/django/django/archive/main.tar.gz"
Expand All @@ -46,16 +45,19 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
if: "!endsWith(matrix.python-version, '-dev')"
with:
python-version: ${{ matrix.python-version }}
cache: "pip"
cache-dependency-path: "pyproject.toml"
- name: Install uv
uses: astral-sh/setup-uv@v5
- name: Patch pyproject.toml
if: "matrix.python-version != '3.9'"
run: |
sed -i 's/requires-python = ">=3.9"/requires-python = ">=3.10"/' pyproject.toml
- name: Install deps
run: |
python -m pip install -e .[test]
python -m pip install "${{ matrix.django-version }}" ${{ matrix.drf }}
- run: pytest
uv add --group test "${{ matrix.django-version }}" ${{ matrix.drf }}
uv sync --no-dev --group test
- run: uv run pytest

lint:
runs-on: ubuntu-latest
Expand All @@ -67,14 +69,14 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: "pip"
cache-dependency-path: "pyproject.toml"
- name: Install uv
uses: astral-sh/setup-uv@v5
- uses: actions/cache@v4
with:
path: ~/.cache/pre-commit
key: pre-commit|${{ env.pythonLocation }}|${{ hashFiles('.pre-commit-config.yaml') }}
- run: python -m pip install -e .[dev]
- run: pre-commit run --show-diff-on-failure --color=always --all-files
- run: uv sync
- run: uv run pre-commit run --show-diff-on-failure --color=always --all-files

package:
runs-on: ubuntu-latest
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

### Unreleased

- drop python 3.8 support
- add django 5.2 to test matrix

### 0.16.1

- fix `field-choices-constraint`
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ EXTRA_CHECKS = {

## Development

Install dev deps in virtualenv `pip install -e .[dev,test]`.
Install dev deps in virtualenv `uv sync --group test`.

## Credits

Expand Down
6 changes: 3 additions & 3 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ def handler(self, handler):
def run(self):
self._registry.enabled_checks = {}
handlers = self._registry.bind()
assert (
self._registry.is_healthy
), f"Settings has errors: {self._registry._config.errors.as_text()}"
assert self._registry.is_healthy, (
f"Settings has errors: {self._registry._config.errors.as_text()}"
)
return list(handlers[self.TEST_TAG]())

def models(self, *models):
Expand Down
12 changes: 6 additions & 6 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,16 @@
let
pkgs = import nixpkgs { inherit system; };
app-test = pkgs.writeShellScriptBin "app.test" ''pytest $@'';
app-install = pkgs.writeShellScriptBin "app.install" ''uv pip install -e .[dev,test] && pre-commit install'';
app-install = pkgs.writeShellScriptBin "app.install" ''uv sync && pre-commit install'';
app-typecheck = pkgs.writeShellScriptBin "app.typecheck" ''mypy src/extra_checks tests'';
app-lint = pkgs.writeShellScriptBin "app.lint" ''pre-commit run -a'';
in
{
devShells.default = pkgs.mkShell {
packages = [
pkgs.python312
pkgs.python313
pkgs.pre-commit
pkgs.uv
];
buildInputs = [
app-test
Expand Down
9 changes: 5 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ dynamic = ["version"]
description = "Collection of useful checks for Django Checks Framework"
readme = "README.md"
license = "MIT"
requires-python = ">=3.8"
requires-python = ">=3.9"
authors = [
{ name = "Konstantin Alekseev", email = "[email protected]" },
]
Expand All @@ -23,20 +23,20 @@ classifiers = [
"Framework :: Django :: 4.2",
"Framework :: Django :: 5.0",
"Framework :: Django :: 5.1",
"Framework :: Django :: 5.2",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"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",
]

[project.optional-dependencies]
[dependency-groups]
dev = [
"Django",
"django-stubs",
Expand All @@ -46,6 +46,7 @@ dev = [
"pdbpp",
"pre-commit",
"ruff",
{include-group = "test"},
]
test = [
"pytest",
Expand All @@ -67,7 +68,7 @@ packages = ["src/extra_checks"]

[tool.ruff]
src = ["src"]
target-version = "py38"
target-version = "py39"
[tool.ruff.lint]
select = [
'B',
Expand Down
4 changes: 2 additions & 2 deletions src/extra_checks/ast/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Container, Type
from collections.abc import Container

from django.db import models

Expand All @@ -14,7 +14,7 @@


def get_model_ast(
model_cls: Type[models.Model],
model_cls: type[models.Model],
meta_checks: Container[CheckId],
) -> ModelASTDisableCommentProtocol:
return ModelAST(model_cls, meta_checks)
Expand Down
24 changes: 9 additions & 15 deletions src/extra_checks/ast/ast.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
import ast
from collections.abc import Container, Iterable, Iterator
from functools import partial
from typing import (
TYPE_CHECKING,
Callable,
Container,
Dict,
Iterable,
Iterator,
List,
Optional,
Tuple,
Type,
Union,
cast,
)
Expand All @@ -36,10 +30,10 @@


class ModelAST(DisableCommentProtocol, ModelASTProtocol):
def __init__(self, model_cls: Type[models.Model], meta_checks: Container[CheckId]):
def __init__(self, model_cls: type[models.Model], meta_checks: Container[CheckId]):
self.model_cls = model_cls
self.meta_checks = meta_checks
self._assignment_nodes: List[ast.Assign] = []
self._assignment_nodes: list[ast.Assign] = []
self._meta: Optional[ast.ClassDef] = None

@cached_property
Expand Down Expand Up @@ -73,8 +67,8 @@ def _meta_node(self) -> Optional[ast.ClassDef]:
return self._meta

@cached_property
def _meta_vars(self) -> Dict[str, ast.Assign]:
data: Dict[str, ast.Assign] = {}
def _meta_vars(self) -> dict[str, ast.Assign]:
data: dict[str, ast.Assign] = {}
if not self._meta_node:
return data
for node in ast.iter_child_nodes(self._meta_node):
Expand All @@ -83,7 +77,7 @@ def _meta_vars(self) -> Dict[str, ast.Assign]:
return data

@cached_property
def _assignments(self) -> Dict[str, ast.Assign]:
def _assignments(self) -> dict[str, ast.Assign]:
self._parse()
result = {}
for node in self._assignment_nodes:
Expand All @@ -92,7 +86,7 @@ def _assignments(self) -> Dict[str, ast.Assign]:
return result

@cached_property
def field_nodes(self) -> Iterable[Tuple[models.fields.Field, "FieldAST"]]:
def field_nodes(self) -> Iterable[tuple[models.fields.Field, "FieldAST"]]:
for field in self.model_cls._meta.get_fields(include_parents=False):
if isinstance(field, models.Field):
yield (
Expand Down Expand Up @@ -155,11 +149,11 @@ def __init__(
self._source_provider = source_provider

@cached_property
def _args(self) -> List[ast.expr]:
def _args(self) -> list[ast.expr]:
return self._node.value.args # type: ignore

@cached_property
def _kwargs(self) -> Dict[str, ast.keyword]:
def _kwargs(self) -> dict[str, ast.keyword]:
return {kw.arg: kw for kw in self._node.value.keywords if kw.arg} # type: ignore

def get_arg(self, name: str) -> Optional[ArgASTProtocol]:
Expand Down
5 changes: 3 additions & 2 deletions src/extra_checks/ast/protocols.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import Any, Iterable, Optional, Protocol, Tuple
from collections.abc import Iterable
from typing import Any, Optional, Protocol

from django.db import models

Expand All @@ -21,7 +22,7 @@ class ModelASTProtocol(Protocol):
@property
def field_nodes(
self,
) -> Iterable[Tuple[models.fields.Field, "FieldASTDisableCommentProtocol"]]: ...
) -> Iterable[tuple[models.fields.Field, "FieldASTDisableCommentProtocol"]]: ...

def has_meta_var(self, name: str) -> bool: ...

Expand Down
13 changes: 7 additions & 6 deletions src/extra_checks/ast/source_provider.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import inspect
import re
import textwrap
from typing import TYPE_CHECKING, Dict, Iterable, Optional, Set, Type
from collections.abc import Iterable
from typing import TYPE_CHECKING, Optional

from extra_checks.check_id import ALL_CHECKS_NAMES, CheckId

Expand All @@ -14,7 +15,7 @@
DISABLE_COMMENT_PATTERN = r"^#\s*extra-checks-disable-next-line(?:\s+(.*))?$"


def _parse_comment(checks: Optional[str]) -> Set[str]:
def _parse_comment(checks: Optional[str]) -> set[str]:
if not checks:
return ALL_CHECKS_NAMES # type: ignore
result = set()
Expand All @@ -25,7 +26,7 @@ def _parse_comment(checks: Optional[str]) -> Set[str]:
return result


def _find_disabled_checks(comments: Iterable[str]) -> Set[str]:
def _find_disabled_checks(comments: Iterable[str]) -> set[str]:
result = set()
for line in comments:
m = re.match(DISABLE_COMMENT_PATTERN, line)
Expand All @@ -35,9 +36,9 @@ def _find_disabled_checks(comments: Iterable[str]) -> Set[str]:


class SourceProvider:
def __init__(self, obj: Type) -> None:
def __init__(self, obj: type) -> None:
self._obj = obj
self._comments_cache: Dict[int, Set[str]] = {}
self._comments_cache: dict[int, set[str]] = {}

@cached_property
def source(self) -> Optional[str]:
Expand All @@ -63,7 +64,7 @@ def _get_line_comments(self, line_no: int) -> Iterable[str]:
else:
break

def get_disabled_checks_for_line(self, line_no: int) -> Set[str]:
def get_disabled_checks_for_line(self, line_no: int) -> set[str]:
if line_no not in self._comments_cache:
comments = self._get_line_comments(line_no)
self._comments_cache[line_no] = _find_disabled_checks(comments)
Expand Down
11 changes: 4 additions & 7 deletions src/extra_checks/checks/base_checks.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import warnings
from abc import ABC, abstractmethod
from collections.abc import Iterator
from typing import (
TYPE_CHECKING,
Any,
Callable,
ClassVar,
Iterator,
List,
Optional,
Set,
Type,
)

import django.core.checks
Expand All @@ -28,14 +25,14 @@

class BaseCheck(ABC):
Id: CheckId
settings_form_class: ClassVar[Type[forms.BaseCheckForm]] = forms.BaseCheckForm
settings_form_class: ClassVar[type[forms.BaseCheckForm]] = forms.BaseCheckForm
level = django.core.checks.WARNING
deprecation_warnings: List[str] = []
deprecation_warnings: list[str] = []

def __init__(
self,
level: Optional[int] = None,
ignore_objects: Optional[Set[Any]] = None,
ignore_objects: Optional[set[Any]] = None,
ignore_types: Optional[set] = None,
skipif: Optional[Callable] = None,
) -> None:
Expand Down
Loading