diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 6a2ab30..0000000 --- a/.flake8 +++ /dev/null @@ -1,4 +0,0 @@ -[flake8] -max-line-length = 100 -extend-ignore = E203, W503 -exclude = .git,__pycache__,.pytest_cache,.pytest-tmp,venv,env,.venv,static,templates,migrations,node_modules diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3723772..f611eb9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,12 +43,10 @@ jobs: run: python -m pip install -r requirements-dev.txt - name: Install Node.js dependencies run: npm ci --ignore-scripts - - name: Run Black - run: black --check . - - name: Run isort - run: isort --check-only . - - name: Run Flake8 - run: flake8 . + - name: Run Ruff lint + run: ruff check . + - name: Check Python formatting + run: ruff format --check . - name: Run djLint run: djlint templates/ --check --profile=jinja - name: Run static asset checks diff --git a/.isort.cfg b/.isort.cfg deleted file mode 100644 index 44e7470..0000000 --- a/.isort.cfg +++ /dev/null @@ -1,9 +0,0 @@ -[settings] -profile = black -known_first_party = ["api"] -line_length = 100 -multi_line_output = 3 -include_trailing_comma = true -force_grid_wrap = 0 -use_parentheses = true -skip = migrations,.pytest_cache,.pytest-tmp,.venv,node_modules diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e73c0ea..9cc0632 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,21 +1,12 @@ exclude: ^(\.pytest_cache|\.pytest-tmp)/ repos: - - repo: https://github.com/psf/black - rev: 25.1.0 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.16.9 hooks: - - id: black - language_version: python3 - - repo: https://github.com/PyCQA/isort - rev: 6.0.1 - hooks: - - id: isort - language_version: python3 - - repo: https://github.com/pycqa/flake8 - rev: 7.3.0 - hooks: - - id: flake8 - language_version: python3 + - id: ruff + args: [--fix] + - id: ruff-format - repo: https://github.com/Riverside-Healthcare/djLint rev: v1.36.4 hooks: diff --git a/FORMATTERS_AND_LINTERS.md b/FORMATTERS_AND_LINTERS.md index e3a203a..d3f29a5 100644 --- a/FORMATTERS_AND_LINTERS.md +++ b/FORMATTERS_AND_LINTERS.md @@ -9,9 +9,7 @@ This project enforces consistent code style and quality across Python, Jinja tem | Tool | Purpose | Config File | Notes | |---------|----------------------------------------------|---------------------|-------| -| Black | Code formatter for Python | `pyproject.toml` | Enforces PEP 8 style, auto-formats code | -| isort | Sorts and organizes Python imports | `.isort.cfg` | Keeps imports grouped and ordered | -| Flake8 | Linter for Python code quality | `.flake8` | Reports style and logic issues | +| Ruff | Python linter, import sorter, and formatter | `pyproject.toml` | Replaces Flake8, isort, and Black | | djlint | Formatter/linter for Jinja templates | `.djlintrc` | Only runs on `.jinja` files | **Exclusions:** The `migrations/` folder is excluded from all Python formatters/linters to avoid altering migration scripts. @@ -33,7 +31,7 @@ All static asset tools are managed via `package.json` (see `devDependencies` and ## Automation - **Pre-commit hooks**: `.pre-commit-config.yaml` runs all formatters and linters automatically on commit for Python, Jinja, JS, and CSS files. - - Python: Black, isort, Flake8 + - Python: Ruff lint and format hooks - Jinja: djlint (only on `.jinja` files) - JS/CSS: Prettier, ESLint, Stylelint (via npm scripts) @@ -68,8 +66,8 @@ All static asset tools are managed via `package.json` (see `devDependencies` and ### Python/Jinja - Install dev tools: `pip install -r requirements-dev.txt` -- Format code: `black .` and `isort .` -- Lint code: `flake8 .` +- Format code: `ruff check --fix .` and `ruff format .` +- Lint code: `ruff check .` - Format/lint Jinja: `djlint templates/ --reformat --profile=jinja` ### JavaScript/CSS @@ -101,9 +99,7 @@ All static asset tools are managed via `package.json` (see `devDependencies` and --- ## References -- [Black](https://black.readthedocs.io/) -- [isort](https://pycqa.github.io/isort/) -- [Flake8](https://flake8.pycqa.org/) +- [Ruff](https://docs.astral.sh/ruff/) - [djlint](https://djlint.com/) - [ESLint](https://eslint.org/) - [Stylelint](https://stylelint.io/) diff --git a/database.py b/database.py index fcf1382..477a97d 100644 --- a/database.py +++ b/database.py @@ -282,11 +282,13 @@ def get_expired_comparisons(retention_days: int): expired_ids = [] # Get all comparisons with their expiration settings - comparisons = query((""" + comparisons = query(( + """ SELECT id, expiration_type, expiration_days, created_at, last_accessed, never_expire FROM comparisons - """)) + """ + )) print(f"Checking for expired comparisons with retention_days={retention_days}") num = len(comparisons) print(f"Found {num} comparisons to check for expiration") diff --git a/pyproject.toml b/pyproject.toml index 81f9f06..6c48892 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,13 +8,27 @@ authors = [ requires-python = ">=3.13" -[tool.black] +[tool.ruff] line-length = 100 -target-version = ['py38'] -include = '\.pyi?$' -exclude = ''' -/(\.pytest_cache|\.pytest-tmp|venv|env|\.venv|static|templates|migrations|node_modules)/ -''' +target-version = "py313" +extend-exclude = [ + ".pytest_cache", + ".pytest-tmp", + "venv", + "env", + "static", + "templates", + "migrations", + "node_modules", +] +force-exclude = true + +[tool.ruff.lint] +select = ["E", "F", "W", "I"] +ignore = ["E203"] + +[tool.ruff.lint.isort] +known-first-party = ["api"] [tool.pytest.ini_options] addopts = "--strict-markers --strict-config --basetemp=.pytest-tmp" diff --git a/requirements-dev.txt b/requirements-dev.txt index 4d26161..6239726 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,7 +1,5 @@ # Development requirements for formatting, linting and tests -black==26.5.1 -isort==8.0.1 -flake8==7.4.1 +ruff==0.16.9 djlint==1.44.2 pre-commit==4.6.2 setuptools==84.0.0 diff --git a/scripts/check_format_lint.bat b/scripts/check_format_lint.bat index 7603a08..f574217 100644 --- a/scripts/check_format_lint.bat +++ b/scripts/check_format_lint.bat @@ -5,9 +5,8 @@ echo. echo ============================= echo Checking Python files echo ============================= -black --check . -isort --check-only . -flake8 . +ruff check . +ruff format --check . echo. echo ============================= diff --git a/scripts/check_format_lint.sh b/scripts/check_format_lint.sh index 9feb42b..c3633f0 100644 --- a/scripts/check_format_lint.sh +++ b/scripts/check_format_lint.sh @@ -5,9 +5,8 @@ echo echo "=============================" echo " Checking Python files" echo "=============================" -black --check . -isort --check-only . -flake8 . +ruff check . +ruff format --check . echo echo "=============================" diff --git a/scripts/format_all.bat b/scripts/format_all.bat index be7f199..36d2016 100644 --- a/scripts/format_all.bat +++ b/scripts/format_all.bat @@ -6,9 +6,9 @@ echo. echo ============================= echo Formatting Python files echo ============================= -black . -isort . -flake8 . +ruff check --fix . +ruff format . +ruff check . echo. echo ============================= diff --git a/scripts/format_all.sh b/scripts/format_all.sh index 9174e7d..62d12a0 100644 --- a/scripts/format_all.sh +++ b/scripts/format_all.sh @@ -7,9 +7,9 @@ echo echo "=============================" echo " Formatting Python files" echo "=============================" -black . -isort . -flake8 . +ruff check --fix . +ruff format . +ruff check . echo echo "=============================" diff --git a/scripts/migrate_sqlite_to_postgres.py b/scripts/migrate_sqlite_to_postgres.py index 8117f6b..4b526a0 100644 --- a/scripts/migrate_sqlite_to_postgres.py +++ b/scripts/migrate_sqlite_to_postgres.py @@ -107,7 +107,7 @@ def _reset_sequences( continue # seq is like 'public.users_id_seq' execute_fn( - (f"SELECT setval('{seq}', " f"(SELECT COALESCE(MAX(id), 1) FROM {tbl}), true)"), + (f"SELECT setval('{seq}', (SELECT COALESCE(MAX(id), 1) FROM {tbl}), true)"), (), ) @@ -135,7 +135,7 @@ def migrate(sqlite_path: str, pg_url: str, wipe_target: bool = False): # Point adapter at Postgres and ensure schema os.environ["DB_BACKEND"] = "postgres" os.environ["DATABASE_URL"] = pg_url - # Import app modules lazily (after sys.path and env are set) to satisfy flake8 E402 + # Import app modules lazily (after sys.path and env are set) to satisfy Ruff E402 import database # type: ignore # noqa: WPS433 from db import backend_name as _backend_name # type: ignore # noqa: WPS433 from db import execute as _execute