Skip to content

refactor: replace black, flake8, isort, pydocstyle with ruff#427

Merged
clstaudt merged 6 commits into
mainfrom
refactor/replace-black-flake8-with-ruff
Jul 24, 2026
Merged

refactor: replace black, flake8, isort, pydocstyle with ruff#427
clstaudt merged 6 commits into
mainfrom
refactor/replace-black-flake8-with-ruff

Conversation

@clstaudt

@clstaudt clstaudt commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Replace black, flake8, isort, and pydocstyle with ruff in dev dependencies and tooling config
  • Switch pre-commit hooks from psf/black to astral-sh/ruff-pre-commit (lint + format)
  • Replace CI flake8 step with ruff check + ruff format --check
  • Apply ruff formatting and lint fixes across the codebase (92 fixes, 78 files reformatted)

All 504 tests pass. Supersedes #420.

Closes #426

Test plan

  • ruff check . passes clean
  • ruff format --check . passes clean
  • Pre-commit hooks pass
  • Full test suite passes (504 passed, 1 skipped)
  • CI workflow passes on PR

Made with Cursor

Consolidate four Python linting/formatting tools into ruff:

- pyproject.toml: swap black/isort/pydocstyle dev deps for ruff,
  replace [tool.flake8] + [tool.isort] with [tool.ruff] config
- .pre-commit-config.yaml: replace psf/black hook with
  astral-sh/ruff-pre-commit (ruff check --fix + ruff format)
- CI: replace flake8 lint step with ruff check + ruff format --check
- Apply ruff format and ruff check --fix across the codebase

Supersedes #420 — the Python 3.14 event-loop crash in black is
no longer relevant since ruff is written in Rust.

Co-authored-by: Cursor <cursoragent@cursor.com>
aaronspring
aaronspring previously approved these changes Jul 21, 2026

@aaronspring aaronspring left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

robust decision going to ruff and pre-commit.

locally one test failed therefore claude created #428 and #429

@clstaudt
clstaudt added this pull request to the merge queue Jul 21, 2026
@clstaudt
clstaudt removed this pull request from the merge queue due to a manual request Jul 21, 2026
Ruff reformatted committed revisions in tuttle/migrations/versions,
joining multi-line op.execute(...) calls onto one line. The formatting is
fine and stays; the guard was the problem — it compared raw diff text, so
a cosmetic reflow read as an edit to a shipped schema delta and
test_versions_are_append_only_in_git failed on this branch locally.

Compare the parsed op.* calls in upgrade() instead. Reflows and import
sorting become invisible; a change to what a call actually does still
fails. Scoped to upgrade() because that is the code already-migrated
databases executed, and because downgrade() bodies were legitimately
replaced with `raise NotImplementedError` after the fact.

CI never caught any of this: actions/checkout defaults to fetch-depth: 1,
and the guard skips files whose per-file git log has one commit — under a
shallow clone that is every file, so the assert always passed vacuously.
With full history it also surfaces a real pre-existing violation on main
(c3d70beffa72, backfill changed from "" to "Unknown" in 9cec3e0), which
is grandfathered here with a comment and tracked in #429.

Verified: ruff check clean, ruff format --check clean, 504 passed /
1 skipped, and the guard still fails on a planted table rename.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
clstaudt and others added 2 commits July 24, 2026 19:30
* feat: add Region settings tab, remove country-specific defaults

Rename the "Local" settings tab to "Region" and move the operating
country selector there alongside currency settings. Remove all
hardcoded "Germany" defaults from the frontend forms, backend model,
intent fallbacks, and KPI function parameters — the onboarding wizard
collects the operating country explicitly.

Also neutralize German-specific UI text: remove "Soli" from tax labels,
drop § 16 Abs. 6 UStG from the currency description, and replace
USt-IdNr / Steuernummer references with generic terms.

Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor: move VAT and tax number from Profile to Region tab

Tax identifiers belong with the tax jurisdiction, not personal identity.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: single save button for Region tab

Merge the separate jurisdiction and currency save buttons into one
"Save Region Settings" that saves both in parallel.

Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor: onboarding wizard mirrors settings tabs (Profile, Region)

Split the "Business" wizard step into "Profile" (identity, address,
bank account) and "Region" (operating country, tax identifiers),
matching the settings tab structure.

Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor: split Profile wizard step into Profile + Address

Keep each onboarding step focused: Profile has name/email/phone,
Address has street address and bank account.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: remove German-specific placeholder text from all form fields

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat: expand country list and graceful tax model degradation

- Add 59 major countries to operating-country dropdown (previously
  limited to ~7 with tax models)
- Add has_tax_model() check and all_operating_countries() RPC
- Show info banner when selected country lacks a tax model, with
  link to request it on GitHub
- Gray out tax-dependent UI (income tax waterfall bars, tax estimates,
  spendable income KPI) when country is unsupported
- Add country_supported flag to salary and KPI responses
- Fix remaining Germany default in salary intent

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@aaronspring

Copy link
Copy Markdown
Contributor

CI was red on both test (3.13) and test (3.14) for a single reason: ruff format --check flagged tuttle/app/settings/intent.py. The branch on its own was clean — CI checks the merge with main, and main had since picked up a change to intent.py that this PR's formatting pass never saw.

Fixed by merging main and re-running ruff format (one line, +1/-3). Verified locally: ruff check, ruff format --check, npx tsc --noEmit, and pytest (504 passed, 1 skipped) all pass on the merged result.

To keep this from recurring

This PR will go red again every time main touches a Python file before it lands — each merge reintroduces unformatted code that the one-time format pass here can't cover. Two things help:

  1. Merge this soon. The window where drift can accumulate is the problem; closing it is the real fix.
  2. The PR is self-healing once merged. It already adds the astral-sh/ruff-pre-commit hooks, so after merge every commit on main gets formatted at commit time and the ruff format --check step in CI stops being a tripwire for drift.

Worth noting for reviewers: because CI runs against the merge commit rather than the branch head, a green run here has a shelf life. If this sits for a while, re-merge main and re-run ruff format before merging.

@aaronspring
aaronspring self-requested a review July 24, 2026 17:40

@aaronspring aaronspring left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@clstaudt
clstaudt added this pull request to the merge queue Jul 24, 2026
Merged via the queue into main with commit 1fd08eb Jul 24, 2026
4 checks passed
@clstaudt
clstaudt deleted the refactor/replace-black-flake8-with-ruff branch July 24, 2026 20:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Replace black, flake8, isort, pydocstyle with ruff

2 participants