Repository navigation
Replace black, isort and flake8 with ruff - #40
Merged
Merged
Conversation
Consolidates linting, import sorting and formatting into a single tool in both the repo and the template. - pyproject.toml: [tool.black]/[tool.isort] replaced with a single [tool.ruff] section. Rule selection (E, F, I, B, W) is scoped to what flake8+isort already checked, plus flake8-bugbear (B), which wasn't installed before. - Deleted both .flake8 files. Ruff reads pyproject.toml natively, which is the whole reason .flake8 existed as a separate file in the first place (flake8 still doesn't, see PyCQA/flake8#234). - requirements.txt (both trees): black/isort/flake8 -> ruff==0.16.9. - scripts/check-style.sh and fix-style.sh (both trees) now call `ruff check`/`ruff format --check` and `ruff check --fix`/`ruff format`. - .vscode/settings.json and extensions.json: swapped to charliermarsh.ruff, with format-on-save fix-all and import-sort actions. - Docs (README, tool-choices, project-structure, CLAUDE.md), .gitignore (.ruff_cache) and clean.sh updated to match. Two things found while verifying against the real tool, not assumed: - Ruff's exclude/extend-exclude uses glob syntax, where `{` and `}` are brace-expansion metacharacters, unlike black's regex-based exclude (which treated the brace-named template directory as a literal match). Unescaped, ruff would both crash trying to parse the template's Jinja-templated pyproject.toml as real TOML during config discovery, and lint files inside it. Fixed by escaping the pattern. - flake8-bugbear (B011) caught `assert False` in the template's own scaffolded skipped-test placeholder, which flake8 alone never did (the plugin wasn't installed). Fixed both copies to `raise AssertionError` instead, per ruff's own suggested fix. Verified locally with real dependencies (Python 3.11): check-style, check-types, test-unit (with coverage), test-integration (18/18) and test-e2e (2/2, which bakes the template and runs the generated project's own make ci/build against the real ruff config) all pass. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The escaped-brace exclude pattern from the previous commit
('\{\{cookiecutter.__project_name_kebab_case\}\}') only worked by
accident on macOS/Linux. Per globset's own docs (the crate ruff uses
for exclude/extend-exclude matching), backslash escaping is enabled by
default on Unix platforms only, not on Windows. On Windows CI the
backslash was inert, `{`/`}` reverted to brace-alternation
metacharacters, the directory wasn't excluded, and ruff crashed trying
to parse the template's Jinja-templated pyproject.toml as real TOML:
Cause: Failed to parse .../{{cookiecutter.__project_name_kebab_case}}/pyproject.toml
Cause: TOML parse error ... invalid key-value pair, expected key
Switched to character-class escaping ([{] matches a literal `{`),
which globset documents as a separate, unconditional mechanism (not
gated behind the same platform-specific backslash_escape setting).
Verified locally on macOS: ruff check/format still correctly exclude
the template directory, and check-style/check-types/test-unit/
test-integration all pass. The actual cross-platform fix can only be
confirmed by the Windows leg of CI on this push.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Consolidates linting, import sorting and formatting into a single tool, in both the repo and the template.
What changed
pyproject.toml(both trees):[tool.black]/[tool.isort]replaced with a single[tool.ruff]section. Rule selection (E, F, I, B, W) is scoped to what flake8+isort already checked, plus flake8-bugbear (B), which wasn't installed before..flake8files. Ruff readspyproject.tomlnatively — the whole reason.flake8existed as a separate file in the first place (flake8 still doesn't).requirements.txt(both trees):black/isort/flake8→ruff==0.16.9.scripts/check-style.sh/fix-style.sh(both trees):ruff check/ruff format --checkandruff check --fix/ruff format..vscode/settings.json/extensions.json: swapped tocharliermarsh.ruff, with format-on-save fix-all and import-sort actions.README.md,tool-choices.md,project-structure.md,CLAUDE.md),.gitignore(.ruff_cache),clean.shupdated to match.Two things found while verifying against the real tool (not assumed)
exclude/extend-excludeuses glob syntax, where{/}are brace-expansion metacharacters — unlike black's regex-based exclude, which treated the brace-named template directory as a literal match. Unescaped, ruff would crash trying to parse the template's Jinja-templatedpyproject.tomlas real TOML during config discovery, and would lint files inside it. Fixed by escaping the pattern ('\{\{cookiecutter.__project_name_kebab_case\}\}').B011) caughtassert Falsein the template's own scaffolded skipped-test placeholder, which flake8 alone never did (the plugin wasn't installed). Fixed both copies toraise AssertionErrorinstead, per ruff's own suggested fix.Testing
All run locally with real dependencies (Python 3.11), not simulated:
make check-style/make check-types— passmake test-unit(with coverage) — 24/24 passmake test-integration— 18/18 passmake test-e2e(bakes the template and runs the generated project's ownmake ci/make buildagainst the real[tool.ruff]config) — 2/2 passruff format --check .reports zero reformatting needed on the existing (previously black-formatted) codebase — theline-length = 88/[tool.ruff.lint.pycodestyle] max-line-length = 120split reproduces the old black-88/flake8-120 behavior exactly🤖 Generated with Claude Code