From d4f92085533c93986a59d7bdb49cb16fbf4769ca Mon Sep 17 00:00:00 2001 From: Aakash Singh Date: Sun, 22 Sep 2024 16:15:32 +0530 Subject: [PATCH] Switch to ruff for lint and format (#1559) * add ruff * fix ruff command * use ruff action * update lint action * update rules --- .flake8 | 14 ----- .github/workflows/linter.yml | 31 ++++------ .pre-commit-config.yaml | 22 ++----- .vscode/extensions.json | 2 +- .vscode/settings.json | 11 ++-- Makefile | 12 ++++ Pipfile | 1 + Pipfile.lock | 63 +++++++++++++------ pyproject.toml | 117 ++++++++++++++++++++++++----------- 9 files changed, 160 insertions(+), 113 deletions(-) delete mode 100644 .flake8 diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 25f2b30205..0000000000 --- a/.flake8 +++ /dev/null @@ -1,14 +0,0 @@ -[flake8] -max-line-length = 88 -extend-ignore = E203,E501,E231 -exclude = - .git, - .gitignore, - *.pot, - *.py[co], - __pycache__, - .venv, - */migrations/*, - */migrations_old/*, - */static/CACHE/*, - docs diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index d17dd681a1..fdc8e815a4 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -10,29 +10,24 @@ on: permissions: { } jobs: - build: + lint: name: Lint Code Base runs-on: ubuntu-latest - permissions: - contents: read - packages: read - statuses: write steps: - name: Checkout Code uses: actions/checkout@v4 + + - name: Ruff check + uses: chartboost/ruff-action@v1 with: - fetch-depth: 0 + version: 0.6.7 + args: "check" + changed-files: "true" - - name: Lint Code Base - uses: super-linter/super-linter/slim@v6 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - VALIDATE_ALL_CODEBASE: false - VALIDATE_PYTHON_BLACK: true - VALIDATE_PYTHON_FLAKE8: true - VALIDATE_PYTHON_ISORT: true - LINTER_RULES_PATH: / - PYTHON_BLACK_CONFIG_FILE: "pyproject.toml" - PYTHON_FLAKE8_CONFIG_FILE: ".flake8" - PYTHON_ISORT_CONFIG_FILE: "pyproject.toml" + - name: Ruff format + uses: chartboost/ruff-action@v1 + with: + version: 0.6.7 + args: "format" + changed-files: "true" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c8b61c98e7..4cad6717e2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,21 +16,9 @@ repos: - id: check-yaml - id: check-toml - - repo: https://github.com/PyCQA/isort - rev: 5.13.2 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.6.7 hooks: - - id: isort - additional_dependencies: ["isort[pyproject]"] - - - repo: https://github.com/psf/black - rev: 24.4.2 - hooks: - - id: black - args: ["--config=pyproject.toml"] - - - repo: https://github.com/PyCQA/flake8 - rev: 7.1.0 - hooks: - - id: flake8 - args: ["--config=.flake8"] - additional_dependencies: [flake8-isort] + - id: ruff + args: [ --fix ] + - id: ruff-format diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 259dc3c09e..e9d06bb780 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -3,6 +3,6 @@ "boto3typed.boto3-ide", "ms-python.python", "ms-python.vscode-pylance", - "ms-python.isort" + "charliermarsh.ruff" ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index 88b18e9481..0f0840051d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,10 +3,12 @@ "editor.formatOnSave": false }, "[python]": { + "editor.formatOnSave": true, "editor.codeActionsOnSave": { + "source.fixAll": "explicit", "source.organizeImports": "explicit" }, - "editor.formatOnSave": true + "editor.defaultFormatter": "charliermarsh.ruff" }, "files.associations": { "*.envrc": "shellscript", @@ -19,10 +21,5 @@ "files.trimFinalNewlines": true, "files.trimTrailingWhitespace": true, "githubPullRequests.ignoredPullRequestBranches": ["develop", "staging"], - "python.formatting.blackPath": "${workspaceFolder}/.venv/bin/black", - "python.formatting.provider": "black", - "python.languageServer": "Pylance", - "python.linting.flake8Args": ["--config=.flake8"], - "python.linting.flake8Path": "${workspaceFolder}/.venv/bin/flake8", - "isort.args": ["--profile", "black"] + "python.languageServer": "Pylance" } diff --git a/Makefile b/Makefile index 549d86d8b7..0b84921fc0 100644 --- a/Makefile +++ b/Makefile @@ -52,5 +52,17 @@ reset_db: docker compose exec backend bash -c "python manage.py reset_db --noinput" docker compose exec backend bash -c "python manage.py migrate" +ruff-all: + ruff check . + +ruff: + ruff check --fix $(shell git diff --name-only --staged | grep -E '\.py$$|\/pyproject.toml$$') + +ruff-all-docker: + docker exec care bash -c "ruff check ." + +ruff-docker: + docker exec care bash -c "ruff check --fix $(shell git diff --name-only --staged | grep -E '\.py$$|\/pyproject.toml$$')" + %: docker compose exec backend bash -c "python manage.py $*" diff --git a/Pipfile b/Pipfile index 445f0f9265..a792c1df96 100644 --- a/Pipfile +++ b/Pipfile @@ -63,6 +63,7 @@ requests-mock = "==1.12.1" tblib = "==3.0.0" watchdog = "==5.0.2" werkzeug = "==3.0.4" +ruff = "==0.6.7" [docs] furo = "==2024.8.6" diff --git a/Pipfile.lock b/Pipfile.lock index c5b9fbdda4..52ebb6605e 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "84feb1d63404ac8bd49709c07717eeb2670f7766b6339f8ec277ed2e33a9366f" + "sha256": "bc01a15ab901f4331df57e40d2fbdaef62ff99cf3449949df2b640c9fd179a64" }, "pipfile-spec": 6, "requires": { @@ -200,11 +200,11 @@ }, "billiard": { "hashes": [ - "sha256:07aa978b308f334ff8282bd4a746e681b3513db5c9a514cbdd810cbbdc19714d", - "sha256:9a3c3184cb275aa17a732f93f65b20c525d3d9f253722d26a82194803ade5a2c" + "sha256:12b641b0c539073fc8d3f5b8b7be998956665c4233c7c1fcd66a7e677c4fb36f", + "sha256:40b59a4ac8806ba2c2369ea98d876bc6108b051c227baffd928c644d15d8f3cb" ], "markers": "python_version >= '3.7'", - "version": "==4.2.0" + "version": "==4.2.1" }, "boto3": { "hashes": [ @@ -217,11 +217,11 @@ }, "botocore": { "hashes": [ - "sha256:18362b7ec748561d786aebf1dd5c9faf22c4732efbf89344314199f96d3bbb65", - "sha256:d9bc656e7dde0b3e3f3080fc54bacff6a97fd7806b98acbcc21c7f9d4d0102b9" + "sha256:1e59b0f14f4890c4f70bd6a58a634b9464bed1c4c6171f87c8795d974ade614b", + "sha256:eb9ccc068255cc3d24c36693fda6aec7786db05ae6c2b13bcba66dce6a13e2e3" ], "markers": "python_version >= '3.8'", - "version": "==1.35.22" + "version": "==1.35.24" }, "celery": { "hashes": [ @@ -891,11 +891,11 @@ }, "kombu": { "hashes": [ - "sha256:1c05178826dab811f8cab5b0a154d42a7a33d8bcdde9fa3d7b4582e43c3c03db", - "sha256:621d365f234e4c089596f3a2510f1ade07026efc28caca426161d8f458786cab" + "sha256:14212f5ccf022fc0a70453bb025a1dcc32782a588c49ea866884047d66e14763", + "sha256:eef572dd2fd9fc614b37580e3caeafdd5af46c1eff31e7fba89138cdb406f2cf" ], "markers": "python_version >= '3.8'", - "version": "==5.4.1" + "version": "==5.4.2" }, "more-itertools": { "hashes": [ @@ -1835,19 +1835,19 @@ }, "botocore": { "hashes": [ - "sha256:18362b7ec748561d786aebf1dd5c9faf22c4732efbf89344314199f96d3bbb65", - "sha256:d9bc656e7dde0b3e3f3080fc54bacff6a97fd7806b98acbcc21c7f9d4d0102b9" + "sha256:1e59b0f14f4890c4f70bd6a58a634b9464bed1c4c6171f87c8795d974ade614b", + "sha256:eb9ccc068255cc3d24c36693fda6aec7786db05ae6c2b13bcba66dce6a13e2e3" ], "markers": "python_version >= '3.8'", - "version": "==1.35.22" + "version": "==1.35.24" }, "botocore-stubs": { "hashes": [ - "sha256:14dec6b00d974dce4747d6917a791bcea0d8efd1c8959821d8ce6ca69ce40d70", - "sha256:dae8cc433df3044ece464f4985e67a154bab51fd042757d0c59e4a9ea26d0376" + "sha256:052eead5808ef138988089b6de6786f6271fc7f395ee0d4395e96e06ab04573c", + "sha256:20ca0d0c77215b599ab79e365f2bf5f909a49f4c5440bbbbb08175971a3de442" ], "markers": "python_version >= '3.8'", - "version": "==1.35.22" + "version": "==1.35.24" }, "certifi": { "hashes": [ @@ -2171,11 +2171,11 @@ }, "faker": { "hashes": [ - "sha256:4294d169255a045990720d6f3fa4134b764a4cdf46ef0d3c7553d2506f1adaa1", - "sha256:e59c01d1e8b8e20a83255ab8232c143cb2af3b4f5ab6a3f5ce495f385ad8ab4c" + "sha256:32d0ee7d42925ff06e4a7d906ee7efbf34f5052a41a2a1eb8bb174a422a5498f", + "sha256:34e89aec594cad9773431ca479ee95c7ce03dd9f22fda2524e2373b880a2fa77" ], "markers": "python_version >= '3.8'", - "version": "==28.4.1" + "version": "==29.0.0" }, "filelock": { "hashes": [ @@ -2580,6 +2580,31 @@ "markers": "python_version >= '3.5'", "version": "==1.12.1" }, + "ruff": { + "hashes": [ + "sha256:02b083770e4cdb1495ed313f5694c62808e71764ec6ee5db84eedd82fd32d8f5", + "sha256:08277b217534bfdcc2e1377f7f933e1c7957453e8a79764d004e44c40db923f2", + "sha256:0c05fd37013de36dfa883a3854fae57b3113aaa8abf5dea79202675991d48624", + "sha256:17a86aac6f915932d259f7bec79173e356165518859f94649d8c50b81ff087e9", + "sha256:2f0b62056246234d59cbf2ea66e84812dc9ec4540518e37553513392c171cb18", + "sha256:44e52129d82266fa59b587e2cd74def5637b730a69c4542525dfdecfaae38bd5", + "sha256:525201b77f94d2b54868f0cbe5edc018e64c22563da6c5c2e5c107a4e85c1c0d", + "sha256:533d66b7774ef224e7cf91506a7dafcc9e8ec7c059263ec46629e54e7b1f90ab", + "sha256:590445eec5653f36248584579c06252ad2e110a5d1f32db5420de35fb0e1c977", + "sha256:6b1462fa56c832dc0cea5b4041cfc9c97813505d11cce74ebc6d1aae068de36b", + "sha256:8854450839f339e1049fdbe15d875384242b8e85d5c6947bb2faad33c651020b", + "sha256:9ba4efe5c6dbbb58be58dd83feedb83b5e95c00091bf09987b4baf510fee5c99", + "sha256:a0e1655868164e114ba43a908fd2d64a271a23660195017c17691fb6355d59bb", + "sha256:a939ca435b49f6966a7dd64b765c9df16f1faed0ca3b6f16acdf7731969deb35", + "sha256:b28f0d5e2f771c1fe3c7a45d3f53916fc74a480698c4b5731f0bea61e52137c8", + "sha256:b3f8822defd260ae2460ea3832b24d37d203c3577f48b055590a426a722d50ef", + "sha256:c6707a32e03b791f4448dc0dce24b636cbcdee4dd5607adc24e5ee73fd86c00a", + "sha256:f49c9caa28d9bbfac4a637ae10327b3db00f47d038f3fbb2195c4d682e925b14" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==0.6.7" + }, "s3transfer": { "hashes": [ "sha256:0711534e9356d3cc692fdde846b4a1e4b0cb6519971860796e6bc4c7aea00ef6", diff --git a/pyproject.toml b/pyproject.toml index 930e81fc03..2ab41f7ca4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,48 +9,91 @@ omit = [ "*/migrations*/*", "*/asgi.py", "*/wsgi.py", + "docs/*", "manage.py", - ".venv/*" + ".venv/*", ] [tool.coverage.report] -exclude_lines = [ - "pragma: no cover", - "raise NotImplementedError" -] +exclude_lines = ["pragma: no cover", "raise NotImplementedError"] ignore_errors = true -[tool.isort] -profile = "black" -known_third_party = [ - "allauth", - "boto3", - "celery", - "crispy_forms", - "dateutil", - "django", - "django_filters", - "django_rest_passwordreset", - "djangoql", - "djqscsv", - "drf_spectacular", - "dry_rest_permissions", - "environ", - "freezegun", - "hardcopy", - "healthy_django", - "jsonschema", - "jwt", - "phonenumber_field", - "phonenumbers", - "pytz", - "pywebpush", - "ratelimit", - "requests", - "rest_framework", - "rest_framework_nested", - "rest_framework_simplejwt", - "sentry_sdk", - "simple_history" +[tool.ruff] +target-version = "py312" +extend-exclude = ["*/migrations_old/*"] +include = ["*.py", "pyproject.toml"] + +[tool.ruff.lint] +# https://docs.astral.sh/ruff/rules/ +select = [ + "F", # pyflakes + "E", # pycodestyle errors + "W", # pycodestyle warnings + "I", # isort + "N", # pep8-naming + "UP", # pyupgrade + # "ANN", # flake8-annotations + "S", # flake8-bandit + "FBT", # flake8-boolean-trap + "B", # flake8-bugbear + "A", # flake8-builtins + "COM", # flake8-commas + "C4", # flake8-comprehensions + "DTZ", # flake8-datetimez + "T10", # flake8-debugger + "DJ", # flake8-django + "EM", # flake8-errmsg + "ISC", # flake8-import-conventions + "ICN", # flake8-import-order + "LOG", # flake8-logging + "G", # flake8-logging-format + "INP", # flake8-no-pep420 + "PIE", # flake8-pie + "T20", # flake8-print + "Q", # flake8-quotes + "RSE", # flake8-raise + "RET", # flake8-return + "SLF", # flake8-self + "SIM", # flake8-simplify + "TID", # flake8-tidy-imports + "TCH", # flake8-todo + "INT", # flake8-gettext + "ARG", # flake8-unused-arguments + "PTH", # flake8-use-pathlib + "TD", # flake8-todo + "ERA", # eradicate + "PL", # pylint + "FURB", # refurb + "RUF", # ruff +] +unfixable = [ + "T20", # don't remove print statements ] +ignore = [ + "E203", # whitespace-before-punctuation + "E501", # line-too-long + "FBT002", # boolean-default-value-positional-argument + "SIM105", # suppressible-exception + "PLR0913", # too-many-arguments + "DJ001", # django-nullable-model-string-field + "ISC001", # conflicts with format + "COM812", # conflicts with format +] + + +[tool.ruff.format] +line-ending = "lf" + + +[tool.ruff.lint.flake8-builtins] +builtins-ignorelist = ["id", "list", "filter"] + + +[tool.ruff.lint.flake8-quotes] +docstring-quotes = "double" + + +[tool.ruff.lint.per-file-ignores] +"**/__init__.py" = ["E402", "F401"] # for imports +"**/tests/**" = ["DTZ001"]