From 926dcbac0d6b414f9fc0a6e446f34f0880c337ec Mon Sep 17 00:00:00 2001 From: Osama Haikal Date: Thu, 6 Mar 2025 11:59:52 +0300 Subject: [PATCH 1/6] Migrate to ruff for linting and formatting --- .flake8 | 77 ------------------------ .github/workflows/format.yml | 10 +--- .gitignore | 2 +- .pre-commit-config.yaml | 50 ++++++---------- app/v1/routers/users/users_router.py | 8 +-- pyproject.toml | 25 ++------ ruff.toml | 51 ++++++++++++++++ tests/conftest.py | 2 +- uv.lock | 90 +++++++++------------------- 9 files changed, 111 insertions(+), 204 deletions(-) delete mode 100644 .flake8 create mode 100644 ruff.toml diff --git a/.flake8 b/.flake8 deleted file mode 100644 index aa1ae33..0000000 --- a/.flake8 +++ /dev/null @@ -1,77 +0,0 @@ -[flake8] -max-complexity = 6 -inline-quotes = double -max-line-length = 120 - -ignore = - ; Do not perform function calls in argument defaults (for dependency injection) - B008, - ; Missing docstring - D100, D101, D102, D103, D104, D105, D106, D107, - ; Found wrong module name - WPS100, - ; Found wrong variable name - WPS110, - ; Found module with too many imports - WPS201, - ; Found too many module members - WPS202, - ; Found overused expression - WPS204, - ; Found too many methods - WPS214, - ; Found string constant over-use - WPS226, - ; Found too long ``try`` body - WPS229, - ; Found too high module cognitive complexity - WPS232, - ; Found `f` string - WPS305, - ; Found class without a base class - WPS306, - ; Found complex default value (for dependency injection) - WPS404, - ; Found mutable module constant. - WPS407, - ; Found `__init__.py` module with logic - WPS412, - ; Found too many empty lines in `def` - WPS473, - ; Found too many arguments - WPS211, - -per-file-ignores = - ; all tests - test_*.py,tests.py,tests_*.py,*/tests/*,conftest.py: - ; Use of assert detected - S101, - ; Found too many local variables - WPS210, - ; Found too many arguments - WPS211, - ; Found magic number - WPS432, - - ; all init files - __init__.py: - ; ignore not used imports - F401, - ; ignore import with wildcard - F403, - ; Found wrong metadata variable - WPS410, - -exclude = - ./.cache, - ./.git, - ./.idea, - ./.mypy_cache, - ./.pytest_cache, - ./.venv, - ./venv, - ./env, - ./cached_venv, - ./docs, - ./var, - ./.vscode, diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 6f95cfc..6f8b6ee 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -7,14 +7,10 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - linter: [black, isort, flake8, mypy] + linter: [ruff, mypy] include: - - linter: black - command: black --check --diff . - - linter: isort - command: isort --check-only --diff . - - linter: flake8 - command: flake8 --count . + - linter: ruff + command: ruff check --diff . - linter: mypy command: mypy . steps: diff --git a/.gitignore b/.gitignore index 95b52b1..95e6c6b 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ __pycache__/ *.py[cod] *$py.class - +.idea # C extensions *.so diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1763a97..5ea8c92 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -26,41 +26,27 @@ repos: - id: trailing-whitespace types: [python] - - repo: https://github.com/asottile/pyupgrade - rev: v3.16.0 - hooks: - - id: pyupgrade - args: [--py312-plus] - - - repo: local + - repo: https://github.com/asottile/pyupgrade + rev: v3.16.0 hooks: - - id: black - name: Format Python code with Black - entry: uv run black - language: system - types: [python] - - - id: isort - name: Sort Python imports with isort - entry: uv run isort - language: system - types: [python] - - - id: autoflake - name: autoflake - entry: uv run autoflake - language: system - types: [python] - args: [--in-place, --remove-all-unused-imports, --remove-duplicate-keys, --ignore-init-module-imports] + - id: pyupgrade + args: [--py312-plus] - - id: flake8 - name: Check with Flake8 - entry: uv run flake8 - language: system - pass_filenames: false - types: [python] - args: [--count, .] + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.3.0 + hooks: + # Sort imports. + - id: ruff + name: ruff-sort-imports + args: [--select, I, --fix] + # Run the linter. + - id: ruff + args: [--fix] + # Run the formatter. + - id: ruff-format + - repo: local + hooks: - id: mypy name: Validate types with MyPy entry: uv run mypy diff --git a/app/v1/routers/users/users_router.py b/app/v1/routers/users/users_router.py index 3c3bf95..5329050 100644 --- a/app/v1/routers/users/users_router.py +++ b/app/v1/routers/users/users_router.py @@ -13,7 +13,7 @@ async def create_user(user: User, user_manager: UserManager = Depends(get_user_m try: return user_manager.create_user(user) except ValueError as ex: - raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=str(ex)) + raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=str(ex)) from ex @router.get("/{username}") @@ -21,7 +21,7 @@ async def get_user(username: str, user_manager: UserManager = Depends(get_user_m try: return user_manager.get_user(username) except ValueError as ex: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(ex)) + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(ex)) from ex @router.get("/") @@ -34,7 +34,7 @@ async def update_user(username: str, user: User, user_manager: UserManager = Dep try: return user_manager.update_user(username, user) except ValueError as ex: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(ex)) + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(ex)) from ex @router.delete("/{username}") @@ -42,4 +42,4 @@ async def delete_user(username: str, user_manager: UserManager = Depends(get_use try: return user_manager.delete_user(username) except ValueError as ex: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(ex)) + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(ex)) from ex diff --git a/pyproject.toml b/pyproject.toml index 5ff5944..33e360e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,27 +13,14 @@ dependencies = [ [dependency-groups] dev = [ - "autoflake>=2.3.1", - "black>=25.1.0", - "flake8>=7.1.2", - "isort>=6.0.0", - "mypy>=1.15.0", - "pre-commit>=4.1.0", - "pytest>=8.3.4", - "pytest-cov>=6.0.0", - "wemake-python-styleguide>=1.0.0", + "mypy>=1.15.0", + "pre-commit>=4.1.0", + "pytest>=8.3.4", + "pytest-cov>=6.0.0", + "ruff>=0.9.9", + "wemake-python-styleguide>=1.0.0", ] -[tool.black] -line-length = 120 - -[tool.isort] -profile = "black" -line_length = 120 -src_paths = ["app", "tests"] -lines_between_types = 1 -lines_after_imports = 2 - [tool.mypy] strict = true pretty = true diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 0000000..6a858da --- /dev/null +++ b/ruff.toml @@ -0,0 +1,51 @@ +line-length = 120 +[format] +quote-style = "double" +docstring-code-format = true + +exclude = [ + "./.cache", + "./.git", + "./.idea", + "./.mypy_cache", + "./.pytest_cache", + "./.venv", + "./venv", + "./env", + "./cached_venv", + "./docs", + "./var", + "./.vscode", +] + +[lint.isort] +lines-after-imports = 2 +lines-between-types = 1 +no-lines-before = ["future", "standard-library"] +no-sections = false +order-by-type = true + +[lint] +extend-select = ["E", "F", "I", "UP", "B", "W", "C90", "N", "D", "PYI", "PT", "RET", "SIM", "ARG", "ERA"] +ignore = [ + "B008", + "D100", + "D101", + "D102", + "D103", + "D104", + "D105", + "D106", + "D107", + "D203", + "D213", + "COM812" +] + +[lint.per-file-ignores] +"test_*.py" = ["S101"] +"tests.py" = ["S101"] +"tests_*.py" = ["S101"] +"*/tests/*" = ["S101"] +"conftest.py" = ["S101"] +"__init__.py" = ["F401", "F403"] diff --git a/tests/conftest.py b/tests/conftest.py index fc30b74..7767893 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -8,7 +8,7 @@ from app.main import app -@pytest.fixture +@pytest.fixture() def client() -> Generator[TestClient, Any, None]: yield TestClient(app) app.dependency_overrides = {} diff --git a/uv.lock b/uv.lock index cfa528a..251bddf 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,4 @@ version = 1 -revision = 1 requires-python = ">=3.12" [[package]] @@ -34,42 +33,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fc/30/d4986a882011f9df997a55e6becd864812ccfcd821d64aac8570ee39f719/attrs-25.1.0-py3-none-any.whl", hash = "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a", size = 63152 }, ] -[[package]] -name = "autoflake" -version = "2.3.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pyflakes" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2a/cb/486f912d6171bc5748c311a2984a301f4e2d054833a1da78485866c71522/autoflake-2.3.1.tar.gz", hash = "sha256:c98b75dc5b0a86459c4f01a1d32ac7eb4338ec4317a4469515ff1e687ecd909e", size = 27642 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/ee/3fd29bf416eb4f1c5579cf12bf393ae954099258abd7bde03c4f9716ef6b/autoflake-2.3.1-py3-none-any.whl", hash = "sha256:3ae7495db9084b7b32818b4140e6dc4fc280b712fb414f5b8fe57b0a8e85a840", size = 32483 }, -] - -[[package]] -name = "black" -version = "25.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "mypy-extensions" }, - { name = "packaging" }, - { name = "pathspec" }, - { name = "platformdirs" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/94/49/26a7b0f3f35da4b5a65f081943b7bcd22d7002f5f0fb8098ec1ff21cb6ef/black-25.1.0.tar.gz", hash = "sha256:33496d5cd1222ad73391352b4ae8da15253c5de89b93a80b3e2c8d9a19ec2666", size = 649449 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/83/71/3fe4741df7adf015ad8dfa082dd36c94ca86bb21f25608eb247b4afb15b2/black-25.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4b60580e829091e6f9238c848ea6750efed72140b91b048770b64e74fe04908b", size = 1650988 }, - { url = "https://files.pythonhosted.org/packages/13/f3/89aac8a83d73937ccd39bbe8fc6ac8860c11cfa0af5b1c96d081facac844/black-25.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e2978f6df243b155ef5fa7e558a43037c3079093ed5d10fd84c43900f2d8ecc", size = 1453985 }, - { url = "https://files.pythonhosted.org/packages/6f/22/b99efca33f1f3a1d2552c714b1e1b5ae92efac6c43e790ad539a163d1754/black-25.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b48735872ec535027d979e8dcb20bf4f70b5ac75a8ea99f127c106a7d7aba9f", size = 1783816 }, - { url = "https://files.pythonhosted.org/packages/18/7e/a27c3ad3822b6f2e0e00d63d58ff6299a99a5b3aee69fa77cd4b0076b261/black-25.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:ea0213189960bda9cf99be5b8c8ce66bb054af5e9e861249cd23471bd7b0b3ba", size = 1440860 }, - { url = "https://files.pythonhosted.org/packages/98/87/0edf98916640efa5d0696e1abb0a8357b52e69e82322628f25bf14d263d1/black-25.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f0b18a02996a836cc9c9c78e5babec10930862827b1b724ddfe98ccf2f2fe4f", size = 1650673 }, - { url = "https://files.pythonhosted.org/packages/52/e5/f7bf17207cf87fa6e9b676576749c6b6ed0d70f179a3d812c997870291c3/black-25.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:afebb7098bfbc70037a053b91ae8437c3857482d3a690fefc03e9ff7aa9a5fd3", size = 1453190 }, - { url = "https://files.pythonhosted.org/packages/e3/ee/adda3d46d4a9120772fae6de454c8495603c37c4c3b9c60f25b1ab6401fe/black-25.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:030b9759066a4ee5e5aca28c3c77f9c64789cdd4de8ac1df642c40b708be6171", size = 1782926 }, - { url = "https://files.pythonhosted.org/packages/cc/64/94eb5f45dcb997d2082f097a3944cfc7fe87e071907f677e80788a2d7b7a/black-25.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:a22f402b410566e2d1c950708c77ebf5ebd5d0d88a6a2e87c86d9fb48afa0d18", size = 1442613 }, - { url = "https://files.pythonhosted.org/packages/09/71/54e999902aed72baf26bca0d50781b01838251a462612966e9fc4891eadd/black-25.1.0-py3-none-any.whl", hash = "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717", size = 207646 }, -] - [[package]] name = "certifi" version = "2025.1.31" @@ -331,15 +294,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, ] -[[package]] -name = "isort" -version = "6.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1c/28/b382d1656ac0ee4cef4bf579b13f9c6c813bff8a5cb5996669592c8c75fa/isort-6.0.0.tar.gz", hash = "sha256:75d9d8a1438a9432a7d7b54f2d3b45cad9a4a0fdba43617d9873379704a8bdf1", size = 828356 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c7/d6017f09ae5b1206fbe531f7af3b6dac1f67aedcbd2e79f3b386c27955d6/isort-6.0.0-py3-none-any.whl", hash = "sha256:567954102bb47bb12e0fae62606570faacddd441e45683968c8d1734fb1af892", size = 94053 }, -] - [[package]] name = "jinja2" version = "3.1.5" @@ -472,15 +426,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, ] -[[package]] -name = "pathspec" -version = "0.12.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 }, -] - [[package]] name = "platformdirs" version = "4.3.6" @@ -642,14 +587,11 @@ dependencies = [ [package.dev-dependencies] dev = [ - { name = "autoflake" }, - { name = "black" }, - { name = "flake8" }, - { name = "isort" }, { name = "mypy" }, { name = "pre-commit" }, { name = "pytest" }, { name = "pytest-cov" }, + { name = "ruff" }, { name = "wemake-python-styleguide" }, ] @@ -658,14 +600,11 @@ requires-dist = [{ name = "fastapi", extras = ["standard"], specifier = ">=0.115 [package.metadata.requires-dev] dev = [ - { name = "autoflake", specifier = ">=2.3.1" }, - { name = "black", specifier = ">=25.1.0" }, - { name = "flake8", specifier = ">=7.1.2" }, - { name = "isort", specifier = ">=6.0.0" }, { name = "mypy", specifier = ">=1.15.0" }, { name = "pre-commit", specifier = ">=4.1.0" }, { name = "pytest", specifier = ">=8.3.4" }, { name = "pytest-cov", specifier = ">=6.0.0" }, + { name = "ruff", specifier = ">=0.9.9" }, { name = "wemake-python-styleguide", specifier = ">=1.0.0" }, ] @@ -731,6 +670,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7e/1b/1c2f43af46456050b27810a7a013af8a7e12bc545a0cdc00eb0df55eb769/rich_toolkit-0.13.2-py3-none-any.whl", hash = "sha256:f3f6c583e5283298a2f7dbd3c65aca18b7f818ad96174113ab5bec0b0e35ed61", size = 13566 }, ] +[[package]] +name = "ruff" +version = "0.9.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/c3/418441a8170e8d53d05c0b9dad69760dbc7b8a12c10dbe6db1e1205d2377/ruff-0.9.9.tar.gz", hash = "sha256:0062ed13f22173e85f8f7056f9a24016e692efeea8704d1a5e8011b8aa850933", size = 3717448 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/c3/2c4afa9ba467555d074b146d9aed0633a56ccdb900839fb008295d037b89/ruff-0.9.9-py3-none-linux_armv6l.whl", hash = "sha256:628abb5ea10345e53dff55b167595a159d3e174d6720bf19761f5e467e68d367", size = 10027252 }, + { url = "https://files.pythonhosted.org/packages/33/d1/439e58487cf9eac26378332e25e7d5ade4b800ce1eec7dc2cfc9b0d7ca96/ruff-0.9.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b6cd1428e834b35d7493354723543b28cc11dc14d1ce19b685f6e68e07c05ec7", size = 10840721 }, + { url = "https://files.pythonhosted.org/packages/50/44/fead822c38281ba0122f1b76b460488a175a9bd48b130650a6fb6dbcbcf9/ruff-0.9.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5ee162652869120ad260670706f3cd36cd3f32b0c651f02b6da142652c54941d", size = 10161439 }, + { url = "https://files.pythonhosted.org/packages/11/ae/d404a2ab8e61ddf6342e09cc6b7f7846cce6b243e45c2007dbe0ca928a5d/ruff-0.9.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3aa0f6b75082c9be1ec5a1db78c6d4b02e2375c3068438241dc19c7c306cc61a", size = 10336264 }, + { url = "https://files.pythonhosted.org/packages/6a/4e/7c268aa7d84cd709fb6f046b8972313142cffb40dfff1d2515c5e6288d54/ruff-0.9.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:584cc66e89fb5f80f84b05133dd677a17cdd86901d6479712c96597a3f28e7fe", size = 9908774 }, + { url = "https://files.pythonhosted.org/packages/cc/26/c618a878367ef1b76270fd027ca93692657d3f6122b84ba48911ef5f2edc/ruff-0.9.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abf3369325761a35aba75cd5c55ba1b5eb17d772f12ab168fbfac54be85cf18c", size = 11428127 }, + { url = "https://files.pythonhosted.org/packages/d7/9a/c5588a93d9bfed29f565baf193fe802fa676a0c837938137ea6cf0576d8c/ruff-0.9.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:3403a53a32a90ce929aa2f758542aca9234befa133e29f4933dcef28a24317be", size = 12133187 }, + { url = "https://files.pythonhosted.org/packages/3e/ff/e7980a7704a60905ed7e156a8d73f604c846d9bd87deda9cabfa6cba073a/ruff-0.9.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:18454e7fa4e4d72cffe28a37cf6a73cb2594f81ec9f4eca31a0aaa9ccdfb1590", size = 11602937 }, + { url = "https://files.pythonhosted.org/packages/24/78/3690444ad9e3cab5c11abe56554c35f005b51d1d118b429765249095269f/ruff-0.9.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fadfe2c88724c9617339f62319ed40dcdadadf2888d5afb88bf3adee7b35bfb", size = 13771698 }, + { url = "https://files.pythonhosted.org/packages/6e/bf/e477c2faf86abe3988e0b5fd22a7f3520e820b2ee335131aca2e16120038/ruff-0.9.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6df104d08c442a1aabcfd254279b8cc1e2cbf41a605aa3e26610ba1ec4acf0b0", size = 11249026 }, + { url = "https://files.pythonhosted.org/packages/f7/82/cdaffd59e5a8cb5b14c408c73d7a555a577cf6645faaf83e52fe99521715/ruff-0.9.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d7c62939daf5b2a15af48abbd23bea1efdd38c312d6e7c4cedf5a24e03207e17", size = 10220432 }, + { url = "https://files.pythonhosted.org/packages/fe/a4/2507d0026225efa5d4412b6e294dfe54725a78652a5c7e29e6bd0fc492f3/ruff-0.9.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9494ba82a37a4b81b6a798076e4a3251c13243fc37967e998efe4cce58c8a8d1", size = 9874602 }, + { url = "https://files.pythonhosted.org/packages/d5/be/f3aab1813846b476c4bcffe052d232244979c3cd99d751c17afb530ca8e4/ruff-0.9.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:4efd7a96ed6d36ef011ae798bf794c5501a514be369296c672dab7921087fa57", size = 10851212 }, + { url = "https://files.pythonhosted.org/packages/8b/45/8e5fd559bea0d2f57c4e12bf197a2fade2fac465aa518284f157dfbca92b/ruff-0.9.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ab90a7944c5a1296f3ecb08d1cbf8c2da34c7e68114b1271a431a3ad30cb660e", size = 11327490 }, + { url = "https://files.pythonhosted.org/packages/42/55/e6c90f13880aeef327746052907e7e930681f26a164fe130ddac28b08269/ruff-0.9.9-py3-none-win32.whl", hash = "sha256:6b4c376d929c25ecd6d87e182a230fa4377b8e5125a4ff52d506ee8c087153c1", size = 10227912 }, + { url = "https://files.pythonhosted.org/packages/35/b2/da925693cb82a1208aa34966c0f36cb222baca94e729dd22a587bc22d0f3/ruff-0.9.9-py3-none-win_amd64.whl", hash = "sha256:837982ea24091d4c1700ddb2f63b7070e5baec508e43b01de013dc7eff974ff1", size = 11355632 }, + { url = "https://files.pythonhosted.org/packages/31/d8/de873d1c1b020d668d8ec9855d390764cb90cf8f6486c0983da52be8b7b7/ruff-0.9.9-py3-none-win_arm64.whl", hash = "sha256:3ac78f127517209fe6d96ab00f3ba97cafe38718b23b1db3e96d8b2d39e37ddf", size = 10435860 }, +] + [[package]] name = "shellingham" version = "1.5.4" From e4b1446886511b6d5748d79a097026bb7eea7b5b Mon Sep 17 00:00:00 2001 From: Osama Haikal Date: Thu, 6 Mar 2025 12:41:41 +0300 Subject: [PATCH 2/6] fixup! Migrate to ruff for linting and formatting avoig conflict between hook and local --- .pre-commit-config.yaml | 11 ++++++----- tests/conftest.py | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5ea8c92..4645dd8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -39,14 +39,15 @@ repos: - id: ruff name: ruff-sort-imports args: [--select, I, --fix] - # Run the linter. - - id: ruff - args: [--fix] - # Run the formatter. - - id: ruff-format - repo: local hooks: + - id: ruff-lint-format + name: Ruff Lint & Format + entry: bash -c "uv run ruff check --fix && uv run ruff format" + language: system + types: [ python ] + - id: mypy name: Validate types with MyPy entry: uv run mypy diff --git a/tests/conftest.py b/tests/conftest.py index 7767893..fc30b74 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -8,7 +8,7 @@ from app.main import app -@pytest.fixture() +@pytest.fixture def client() -> Generator[TestClient, Any, None]: yield TestClient(app) app.dependency_overrides = {} From 0b7ffb137dbbf682bab145f4a45c143133be26c3 Mon Sep 17 00:00:00 2001 From: Ibraheem Tuffaha Date: Thu, 6 Mar 2025 12:18:47 +0000 Subject: [PATCH 3/6] Fix pyproject.toml formatting --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 33e360e..c080cee 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,12 +2,12 @@ name = "python-fastapi-template" version = "0.1.0" description = "A template for a Python FastAPI service with uv & Devcontainer" -authors = ["Ibraheem Tuffaha "] +authors = [{ name = "Ibraheem Tuffaha", email = "ibraheem.z.tuffaha@gmail.com" }] license = "MIT" readme = "README.md" requires-python = ">=3.12" dependencies = [ - "fastapi[standard]>=0.115.8", + "fastapi[standard]>=0.115.8", ] From 890698c0aa853e4076b6ceeb5ad7d010c4c721e9 Mon Sep 17 00:00:00 2001 From: Ibraheem Tuffaha Date: Thu, 6 Mar 2025 12:20:01 +0000 Subject: [PATCH 4/6] Delete wemake-python-styleguide dependency --- pyproject.toml | 1 - uv.lock | 67 +------------------------------------------------- 2 files changed, 1 insertion(+), 67 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c080cee..95b288d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,6 @@ dev = [ "pytest>=8.3.4", "pytest-cov>=6.0.0", "ruff>=0.9.9", - "wemake-python-styleguide>=1.0.0", ] [tool.mypy] diff --git a/uv.lock b/uv.lock index 251bddf..931f43c 100644 --- a/uv.lock +++ b/uv.lock @@ -1,4 +1,5 @@ version = 1 +revision = 1 requires-python = ">=3.12" [[package]] @@ -24,15 +25,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/46/eb/e7f063ad1fec6b3178a3cd82d1a3c4de82cccf283fc42746168188e1cdd5/anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a", size = 96041 }, ] -[[package]] -name = "attrs" -version = "25.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/49/7c/fdf464bcc51d23881d110abd74b512a42b3d5d376a55a831b44c603ae17f/attrs-25.1.0.tar.gz", hash = "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e", size = 810562 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/30/d4986a882011f9df997a55e6becd864812ccfcd821d64aac8570ee39f719/attrs-25.1.0-py3-none-any.whl", hash = "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a", size = 63152 }, -] - [[package]] name = "certifi" version = "2025.1.31" @@ -194,20 +186,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/89/ec/00d68c4ddfedfe64159999e5f8a98fb8442729a63e2077eb9dcd89623d27/filelock-3.17.0-py3-none-any.whl", hash = "sha256:533dc2f7ba78dc2f0f531fc6c4940addf7b70a481e269a5a3b93be94ffbe8338", size = 16164 }, ] -[[package]] -name = "flake8" -version = "7.1.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mccabe" }, - { name = "pycodestyle" }, - { name = "pyflakes" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/58/16/3f2a0bb700ad65ac9663262905a025917c020a3f92f014d2ba8964b4602c/flake8-7.1.2.tar.gz", hash = "sha256:c586ffd0b41540951ae41af572e6790dbd49fc12b3aa2541685d253d9bd504bd", size = 48119 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/35/f8/08d37b2cd89da306e3520bd27f8a85692122b42b56c0c2c3784ff09c022f/flake8-7.1.2-py2.py3-none-any.whl", hash = "sha256:1cbc62e65536f65e6d754dfe6f1bada7f5cf392d6f5db3c2b85892466c3e7c1a", size = 57745 }, -] - [[package]] name = "h11" version = "0.14.0" @@ -356,15 +334,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 }, ] -[[package]] -name = "mccabe" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/ff/0ffefdcac38932a54d2b5eed4e0ba8a408f215002cd178ad1df0f2806ff8/mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", size = 9658 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/27/1a/1f68f9ba0c207934b35b86a8ca3aad8395a3d6dd7921c0686e23853ff5a9/mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e", size = 7350 }, -] - [[package]] name = "mdurl" version = "0.1.2" @@ -460,15 +429,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/43/b3/df14c580d82b9627d173ceea305ba898dca135feb360b6d84019d0803d3b/pre_commit-4.1.0-py2.py3-none-any.whl", hash = "sha256:d29e7cb346295bcc1cc75fc3e92e343495e3ea0196c9ec6ba53f49f10ab6ae7b", size = 220560 }, ] -[[package]] -name = "pycodestyle" -version = "2.12.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/aa/210b2c9aedd8c1cbeea31a50e42050ad56187754b34eb214c46709445801/pycodestyle-2.12.1.tar.gz", hash = "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521", size = 39232 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/d8/a211b3f85e99a0daa2ddec96c949cac6824bd305b040571b82a03dd62636/pycodestyle-2.12.1-py2.py3-none-any.whl", hash = "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3", size = 31284 }, -] - [[package]] name = "pydantic" version = "2.10.6" @@ -522,15 +482,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/51/b2/b2b50d5ecf21acf870190ae5d093602d95f66c9c31f9d5de6062eb329ad1/pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", size = 1885186 }, ] -[[package]] -name = "pyflakes" -version = "3.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/57/f9/669d8c9c86613c9d568757c7f5824bd3197d7b1c6c27553bc5618a27cce2/pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f", size = 63788 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d4/d7/f1b7db88d8e4417c5d47adad627a93547f44bdc9028372dbd2313f34a855/pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a", size = 62725 }, -] - [[package]] name = "pygments" version = "2.19.1" @@ -592,7 +543,6 @@ dev = [ { name = "pytest" }, { name = "pytest-cov" }, { name = "ruff" }, - { name = "wemake-python-styleguide" }, ] [package.metadata] @@ -605,7 +555,6 @@ dev = [ { name = "pytest", specifier = ">=8.3.4" }, { name = "pytest-cov", specifier = ">=6.0.0" }, { name = "ruff", specifier = ">=0.9.9" }, - { name = "wemake-python-styleguide", specifier = ">=1.0.0" }, ] [[package]] @@ -873,17 +822,3 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c0/31/25a417a23e985b61ffa5544f9facfe4a118cb64d664c886f1244a8baeca5/websockets-15.0-cp313-cp313-win_amd64.whl", hash = "sha256:ae721bcc8e69846af00b7a77a220614d9b2ec57d25017a6bbde3a99473e41ce8", size = 176115 }, { url = "https://files.pythonhosted.org/packages/e8/b2/31eec524b53f01cd8343f10a8e429730c52c1849941d1f530f8253b6d934/websockets-15.0-py3-none-any.whl", hash = "sha256:51ffd53c53c4442415b613497a34ba0aa7b99ac07f1e4a62db5dcd640ae6c3c3", size = 169023 }, ] - -[[package]] -name = "wemake-python-styleguide" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "attrs" }, - { name = "flake8" }, - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/34/54/66d4fba9a80a5167efbfd8bc65764f85f91debcb9157b37f56d5c547400f/wemake_python_styleguide-1.0.0.tar.gz", hash = "sha256:00e96dc73faf5471b21d4baa5041f457c19739cf14677832429be69e5f4f7964", size = 155629 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/03/31/a96e579e4d73093b8e25271b14ef1c3c4f0c004bc450434a4641b38dc561/wemake_python_styleguide-1.0.0-py3-none-any.whl", hash = "sha256:c0cc3fe2a2aa8d7ca76f02bc27bfe344c76ed9652f94859c241b96f0fcefa9ac", size = 206619 }, -] From 0eb769226402b59337ba51dc0656119c6b0aebcf Mon Sep 17 00:00:00 2001 From: Ibraheem Tuffaha Date: Thu, 6 Mar 2025 12:20:17 +0000 Subject: [PATCH 5/6] Update devcontainer setup to use ruff --- .devcontainer/devcontainer.json | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index d875355..2df019d 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -34,12 +34,13 @@ "workbench": { "iconTheme": "vscode-icons" }, - "editor": { - "formatOnSave": true, - "defaultFormatter": "ms-python.black-formatter", - "codeActionsOnSave": { - "source.organizeImports": true - } + "[python]": { + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll": "explicit", + "source.organizeImports": "explicit" + }, + "editor.defaultFormatter": "charliermarsh.ruff" } }, "extensions": [ @@ -52,9 +53,7 @@ "tamasfe.even-better-toml", "redhat.vscode-yaml", "ms-python.mypy-type-checker", - "ms-python.flake8", - "ms-python.black-formatter", - "ms-python.isort" + "charliermarsh.ruff" ] } } From 6bb88de30d10f4b1bfb7e29be760bba0e9598f71 Mon Sep 17 00:00:00 2001 From: Ibraheem Tuffaha Date: Thu, 6 Mar 2025 12:26:08 +0000 Subject: [PATCH 6/6] Update & unify usage of ruff in pre-commit --- .pre-commit-config.yaml | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4645dd8..4b09021 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -32,24 +32,22 @@ repos: - id: pyupgrade args: [--py312-plus] - - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.3.0 - hooks: - # Sort imports. - - id: ruff - name: ruff-sort-imports - args: [--select, I, --fix] - - repo: local hooks: - - id: ruff-lint-format - name: Ruff Lint & Format - entry: bash -c "uv run ruff check --fix && uv run ruff format" + - id: ruff-lint + name: Python code linting with Ruff + entry: uv run ruff check --fix + language: system + types: [python] + + - id: ruff-format + name: Python code formatting with Ruff + entry: uv run ruff format language: system - types: [ python ] + types: [python] - id: mypy - name: Validate types with MyPy + name: Python type checking with MyPy entry: uv run mypy language: system types: [python]