Skip to content

build: replace black, isort, flake8 and pydocstyle with ruff - #337

Merged
houtanb merged 1 commit into
forecastingresearch:mainfrom
nikbpetrov:ruff-tooling
Oct 29, 2026
Merged

houtanb merged 1 commit into
forecastingresearch:mainfrom
nikbpetrov:ruff-tooling

Conversation

@nikbpetrov

@nikbpetrov nikbpetrov commented Oct 18, 2026 •

Copy link
Copy Markdown
Collaborator

On top of #340

Only thing to pay attention to, @houtanb , is the jupyter notebooks - minor formatting changes.

===

Swap the four lint/format tools for a single exact-pinned ruff, configured in pyproject.toml with a ruleset that mirrors the previous setup: E/W/F/B/I/D with E203, E701 and bugbear's opt-in B9xx ignored, pycodestyle max-line-length = 110 standing in for B950, pep257 docstrings, and tests exempt from D as they were under pydocstyle. setup.cfg is gone. Markdown files are excluded from ruff format so fenced code blocks stay untouched, as before.

make lint keeps its name and its MAKE_LINT_ERROR_OUT=1 check mode, so the CI workflow is unchanged. ruff check --fix runs before ruff format, as ruff recommends.

Code changes are mechanical:

  • # noqa: B950 becomes # noqa: E501, or is dropped where ruff reports the directive unused. The 46 in sources/_metadata.py were leftovers on closing parentheses of lines black had already wrapped. # flake8: noqa: B950 used to exempt the whole file from flake8; # ruff: noqa: E501 only exempts line length, and those files are otherwise clean.
  • # noqa: E402 after sys.path edits is dropped because ruff allows imports there.
  • The ruff format pass, including the PEP 758 except A, B: form from target-version = "py314".

AST is byte-identical, so no parity job runs are needed.

Closes #121

@houtanb

houtanb commented Oct 29, 2026

Copy link
Copy Markdown
Member

3 issues found by claude:

  1. make lint stops before formatting (Makefile:58). ruff check --fix fails on a long line it can't fix, so ruff format
     never runs to wrap it. I reproduced this. The fix is to run ruff check --fix --exit-zero, then ruff format, then
     ruff check.
  2. A file-wide noqa sits mid-file (src/sources/wikipedia.py:954). # ruff: noqa: E501 turns off the line-length check
     for the whole module, not just the hash mapping below it. Use per-line # noqa: E501 or a per-file-ignores entry
     instead.
  3. AGENTS.md has the wrong line length (AGENTS.md:106). It says 100, but ruff check enforces 110 (pyproject.toml:30).
     Only ruff format targets 100.

Swap the four lint/format tools for a single exact-pinned `ruff`, configured in `pyproject.toml`
with a ruleset that mirrors the previous setup: `E`/`W`/`F`/`B`/`I`/`D` with `E203`, `E701` and
bugbear's opt-in `B9xx` ignored, pycodestyle `max-line-length = 110` standing in for `B950`,
`pep257` docstrings, and tests exempt from `D` as they were under `pydocstyle`. `setup.cfg` is gone.
Markdown files are excluded from `ruff format` so fenced code blocks stay untouched, as before.

`make lint` keeps its name and its `MAKE_LINT_ERROR_OUT=1` check mode, so the CI workflow is
unchanged. In fix mode it runs `ruff check --fix --exit-zero`, then `ruff format`, then
`ruff check`: fixes before formatting, as ruff recommends, and `--exit-zero` so that a finding
ruff cannot fix (a long line) does not stop `make` before the formatter has had its turn to
wrap it; the last `ruff check` reports what is left.

Code changes are mechanical:

* `# noqa: B950` becomes `# noqa: E501`, or is dropped where ruff reports the directive unused. The
  46 in `sources/_metadata.py` were leftovers on closing parentheses of lines black had already
  wrapped. `# flake8: noqa: B950` used to exempt the whole file from flake8; the two files that
  still need it (`sources/fred_questions.py`, `sources/wikipedia.py`, long ID and series tables)
  get a `per-file-ignores` entry for `E501` in `pyproject.toml` instead and are otherwise clean.
* `# noqa: E402` after `sys.path` edits is dropped because ruff allows imports there.
* The `ruff format` pass, including the PEP 758 `except A, B:` form from `target-version = "py314"`.

Closes forecastingresearch#121
@nikbpetrov

Copy link
Copy Markdown
Collaborator Author

3 issues found by claude:

  1. make lint stops before formatting (Makefile:58). ruff check --fix fails on a long line it can't fix, so ruff format
     never runs to wrap it. I reproduced this. The fix is to run ruff check --fix --exit-zero, then ruff format, then
     ruff check.
  2. A file-wide noqa sits mid-file (src/sources/wikipedia.py:954). # ruff: noqa: E501 turns off the line-length check
     for the whole module, not just the hash mapping below it. Use per-line # noqa: E501 or a per-file-ignores entry
     instead.
  3. AGENTS.md has the wrong line length (AGENTS.md:106). It says 100, but ruff check enforces 110 (pyproject.toml:30).
     Only ruff format targets 100.
  1. makes sense
  2. sure, though that's on parity with the old flake8 behaviour and is scoped to only 1-2 files; in any case, i've now centralized the logic using per-file-ignores in pyproject.toml to make it clearer
  3. explaind in pyproject.toml:
[tool.ruff.lint.pycodestyle]
# E501 at 110 reproduces bugbear's B950 (line-length + 10 %).
max-line-length = 110

(applies only to docs, not to code, which still uses line-length = 100; no further action taken here)

@houtanb
houtanb merged commit 9d1090b into forecastingresearch:main Oct 29, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

replace linters with ruff

2 participants