From ea7ced738a6d8ba18774b5fd1330ac9b1edb5f83 Mon Sep 17 00:00:00 2001 From: Andrej Date: Wed, 28 May 2025 17:31:10 +0500 Subject: [PATCH] Introduce Ruff github CI with some basic linter rules And also to help catching syntax errors on older Python versions. --- .github/workflows/ci-black-formatting.yaml | 17 ++++++-- pyproject.toml | 43 +++++++++++++++++++ .../docs/guides/development/code_style.rst | 16 ++++++- src/bonsai/pyproject.toml | 4 ++ src/ifcopenshell-python/pyproject.toml | 3 ++ 5 files changed, 79 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-black-formatting.yaml b/.github/workflows/ci-black-formatting.yaml index 9ed5482ef9..094d0576df 100644 --- a/.github/workflows/ci-black-formatting.yaml +++ b/.github/workflows/ci-black-formatting.yaml @@ -23,6 +23,8 @@ jobs: run: | python3 -m pip install --upgrade pip python3 -m pip install 'black>=24.10.0' + curl -LsSf https://astral.sh/uv/install.sh | sh + uv tool install ruff # black doesn't catch all syntax errors, so we check them explicitly. - name: Check syntax errors @@ -35,18 +37,27 @@ jobs: continue-on-error: true - name: Black formatter - id: linting + id: black run: | python3 -m black --diff --check . continue-on-error: true + - name: Ruff check + id: ruff + run: | + uvx ruff check + continue-on-error: true + - name: Final check run: | ERROR=0 if [ "${{ steps.syntax-errors.outcome }}" != "success" ]; then echo "::error::Syntax errors check failed, see 'syntax-errors' step for the details." && ERROR=1 fi - if [ "${{ steps.linting.outcome }}" != "success" ]; then - echo "::error::Black formatting check failed, see 'linting' step for the details." && ERROR=1 + if [ "${{ steps.black.outcome }}" != "success" ]; then + echo "::error::Black formatting check failed, see 'black' step for the details." && ERROR=1 + fi + if [ "${{ steps.ruff.outcome }}" != "success" ]; then + echo "::error::Ruff check failed, see 'ruff' step for the details." && ERROR=1 fi exit $ERROR diff --git a/pyproject.toml b/pyproject.toml index 1e0121dedd..e947504cdd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,3 +38,46 @@ disableBytesTypePromotions = true reportUnnecessaryTypeIgnoreComment = true # Just to add a quick insert of `# pyright: ignore[xxx]` comments in Pylance. enableTypeIgnoreComments = false + +# Define here general ruff settings, +# then they will be inherited projects .toml files. +# This allows using assuming different Python version for different projects. +[tool.ruff] +exclude = [ + # Submodules. + "src/ifcopenshell-python/ifcopenshell/express", + "src/ifcopenshell-python/ifcopenshell/mvd", + "src/ifcopenshell-python/ifcopenshell/simple_spf", + "src/svgfill", + # + # Unformatted. + "src/exterior-shell-extractor", + # Incompatible with linter. + "src/ifc2ca/templates", +] +[tool.ruff.lint] +select = [ + # Default Ruff rules. + # "E4", # imports + # "E7", # statements + "E9", # io errors + # "F", # pyflakes + # + "FA", # future annotations + "UP", # pyupgrade +] +ignore = [ + "FA100", # Conflicts with Blender using annotations for props definitions. + # Maybe will enable later: + "UP006", # deprecated symbols + "UP007", # Optional to X | Y + "UP015", # Unnecessary mode argument + "UP028", # yield for -> yield from + "UP030", # implicit references for positional format fields + "UP031", # Replace % with .format + "UP032", # Replace .format with f-string + "UP035", # List -> list + + # Deprecated Ruff rules. + "UP038", # Use X | Y in isinstance +] diff --git a/src/bonsai/docs/guides/development/code_style.rst b/src/bonsai/docs/guides/development/code_style.rst index 8857d6baab..45b8e6abba 100644 --- a/src/bonsai/docs/guides/development/code_style.rst +++ b/src/bonsai/docs/guides/development/code_style.rst @@ -2,7 +2,7 @@ Code style ============ -Black code formatter +Code formatters ------------------------------- For Python code formatting, we use `Black code formatter `__, black settings are stored in the repository's pyproject.toml. @@ -19,3 +19,17 @@ We have GitHub workflow `ci-black-formatting` to maintain black formatting acros # Format only some specific file. black src/bonsai/bonsai/bim/module/qto/operator.py + +There is also `ruff` with some basic linter rules (checked automatically by the same Github workflow). +Which also helps maintaining consistency across the code base +and ensure new Python syntax doesn't break code on older Python versions. + +``ruff`` can be installed using ``pip install ruff`` and files can be formatted with the following example commands: + +.. code-block:: bash + # Check issues for the entire repository. + ruff check + # Apply some automatic fixes, if available. + ruff check --fix + # Check only some specific file. + ruff src/bonsai/bonsai/bim/module/qto/operator.py diff --git a/src/bonsai/pyproject.toml b/src/bonsai/pyproject.toml index 577b2f6de5..51ce45798c 100644 --- a/src/bonsai/pyproject.toml +++ b/src/bonsai/pyproject.toml @@ -13,6 +13,7 @@ keywords = ["IFC", "Blender", "BIM"] classifiers = [ "Programming Language :: Python :: 3", ] +requires-python = ">=3.11" dependencies = [ "ifcopenshell", ] @@ -28,3 +29,6 @@ exclude = ["test*"] [tool.setuptools.package-data] "*" = ["*.*", "libs/desktop/bonsai", "libs/bin/ifcmerge"] + +[tool.ruff] +extend = "../../pyproject.toml" diff --git a/src/ifcopenshell-python/pyproject.toml b/src/ifcopenshell-python/pyproject.toml index 02fcf321cc..88b17c64a0 100644 --- a/src/ifcopenshell-python/pyproject.toml +++ b/src/ifcopenshell-python/pyproject.toml @@ -36,3 +36,6 @@ include = ["ifcopenshell*"] [tool.setuptools.package-data] "*" = ["*.*"] + +[tool.ruff] +extend = "../../pyproject.toml"