Skip to content

Replace black and pylint with Ruff - #582

Merged
tompollard merged 4 commits into
MIT-LCP:mainfrom
cbrnr:ruff
Oct 27, 2026
Merged

tompollard merged 4 commits into
MIT-LCP:mainfrom
cbrnr:ruff

Conversation

@cbrnr

@cbrnr cbrnr commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

Fourth PR of the tooling series (after #578, #580 and #581). It replaces black (formatting) and pylint (which was not run anywhere, and had a 560 line config) with Ruff, which does both.

The PR consists of four commits, and I suggest reviewing them one by one:

  1. Replace black and pylint with Ruff: the actual configuration. The dev extra now contains ruff >= 0.13.0 (the first version that agrees with the rules below) instead of black and pylint, the style workflow runs ruff format --check and ruff check, pylintrc is removed, and the developer docs and the changelog are updated.
  2. Fix a test that was never run: tests/test_multi_record.py defines test_contained_combined_ranges_variable_layout twice, so the first definition was shadowed and never ran (Ruff reports this as F811). I renamed the second test. Both pass.
  3. Apply ruff formatting and safe lint fixes: purely mechanical (34 files). You can reproduce it with ruff check --fix . && ruff format . on the first two commits. It contains the formatting, plus the safe autofixes of the enabled rules: sorted imports, f-strings instead of str.format(), list[...]/X | None instead of typing aliases, class X: instead of class X(object):, and unused imports.
  4. Ignore the reformatting commit in git blame: adds .git-blame-ignore-revs with commit 3 (GitHub uses this file automatically; locally, run git config blame.ignoreRevsFile .git-blame-ignore-revs, which is documented in DEVELOPING.md). Note that the hash only stays valid if the commits of this PR are preserved, i.e. with a merge commit (as for the previous PRs), not when squashing or rebasing.

Configuration

  • Line length: Ruff's default of 88 instead of black's 80 (as configured so far).
  • Rules: E, F, W (pycodestyle/pyflakes), I (isort), UP (pyupgrade) and B (bugbear). E501 is ignored because the formatter takes care of line lengths, and F401 is ignored in __init__.py files (re-exports).
  • Existing violations: I did not want to change code behavior in this PR, so the rules whose fixes are not safe are ignored for now (about 90 occurrences in total): E711, E721, E722, E741, F841, UP031, B006, B007, B020, B904, B905. They can be enabled one by one in follow-up PRs.
  • Jupyter notebooks are not checked (black did not check them either).

Testing

  • ruff check . and ruff format --check . pass (also with the oldest allowed Ruff, 0.13.0), and all modules still import.
  • The test suite behaves as before on Python 3.11 with the lowest allowed dependency versions and on 3.15 with the latest (65 passed, and only the 17 tests that need PhysioNet fail when offline; the test that was shadowed before is now among the passing ones).
  • With the ignore file, git blame attributes lines changed by commit 3 to their original commits.

cbrnr added 4 commits October 27, 2026 21:41
Use Ruff for both formatting and linting. black was configured with a line
length of 80, Ruff uses its default of 88. pylint was not run anywhere.

- Replace black and pylint with ruff in the dev extra, and check the
  formatting and the lint rules in the style workflow.
- Enable the rule sets E, F, W, I (isort), UP (pyupgrade) and B (bugbear).
  Existing violations of a few rules are ignored for now, to be cleaned up
  separately. E501 is ignored because the formatter takes care of line
  lengths. Jupyter notebooks are not checked (black did not either).
- Remove the unused pylintrc and update the developer documentation and
  the changelog.

The code is not reformatted yet (see the next commits), so the style check
fails at this commit.
tests/test_multi_record.py defined test_contained_combined_ranges_variable_layout
twice, so the first definition was shadowed by the second and never run.
Rename the second one (which reads all signal pairs of a different record).
Reformat the code with ruff format (line length 88) and apply the safe
autofixes of the enabled rule sets, for example: sorted imports, f-strings
instead of str.format(), builtin generics and `X | None` annotations,
`class X:` instead of `class X(object):`, and removal of unused imports.

This commit is purely mechanical. It is listed in .git-blame-ignore-revs.
Add .git-blame-ignore-revs with the commit that applied ruff formatting
and the safe lint fixes, so that it does not show up in git blame (GitHub
uses this file automatically), and document how to enable it locally.
@cbrnr
cbrnr requested a review from tompollard October 27, 2026 20:46
@tompollard

Copy link
Copy Markdown
Member

Looks good, thanks. We might want to cap the Ruff version (e.g. ruff >= 0.13.0, < 0.15) so new Ruff releases don't break the style check on unrelated PRs? This is going to result in a lot of conflicts on open PRs, but that's okay.

@tompollard
tompollard merged commit 9b99560 into MIT-LCP:main Oct 27, 2026
18 checks passed
@cbrnr
cbrnr deleted the ruff branch October 28, 2026 08:43
@cbrnr

cbrnr commented Oct 28, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @tompollard, see #585 where your Ruff concern is addressed.

tompollard added a commit that referenced this pull request Oct 28, 2026
#589)

This is the last part of the cleanup that started with #578, #580, #581,
#582 and #588. It builds the documentation without warnings, applies one
docstring style everywhere, and moves the package to a `src` layout.
Each commit can be reviewed on its own.

1. **Fix all Sphinx documentation warnings.** The docs build reported 94
warnings. They are fixed, and the docs workflow now builds with `-W
--keep-going` so they stay fixed.
- Duplicate object descriptions: repeated `automodule` directives and
the classes documented on both the `wfdb` and `io` pages are marked
`:no-index:`, so each object is indexed once.
- `numpydoc_class_members_toctree = False`, because the autosummary
stubs it links to do not exist.
- Too short title underlines, and reStructuredText errors in docstrings
(lists, literal blocks for the EDF/MATLAB/WAV format descriptions and
tables, doctest continuation lines).
- The `:no-index:` option needs Sphinx 7.2, so the pinned Sphinx version
of the `docs` group goes from 7.0.0 to 7.2.6.
2. **Wrap docstrings and comments at 88 columns**, the same width as the
code, and enable W505 in Ruff so it stays that way. This is a mechanical
change, and the commit is listed in `.git-blame-ignore-revs`.
3. **Start docstrings on the opening quote line with a one-line
summary.** Summaries that were wrapped over several lines or too long
for one line are shortened, and the rest of the text moves into the
description below. No code changes: comparing the ASTs with docstrings
removed shows no difference. A few docstrings were reworded to fit, and
the descriptions of `csv_to_wfdb` and `csv2ann` (which described reading
a WFDB header) now match what the functions do. Also listed in
`.git-blame-ignore-revs`.
4. **Move the package to `src/wfdb`.** This is the default module root
of `uv_build`, so the `module-root` setting is removed. The tests now
always run against the installed package, and `docs/conf.py` adds `src`
to `sys.path`. Files are moved without changes, so `git blame` and `git
log --follow` keep working. The wheel and the sdist build as expected.
5. **Ignore the two reformatting commits in git blame**, and add a note
about the docstring style to `DEVELOPING.md`. The hashes stay valid with
a merge commit, as in #582.
6. **Add `AGENTS.md` and `CLAUDE.md`** with short guidance for coding
agents (commands and conventions). `CLAUDE.md` only points to
`AGENTS.md`.

Checked locally: Ruff lint and format, the docs build with `-W
--keep-going`, and the tests that work offline on Python 3.11 with the
lowest dependencies and on 3.15.

@tompollard this concludes the tooling and infrastructure refresh. Any
remaining changes are minor, such as fixing the ignored Ruff rules,
which can be done later in follow-up PRs.
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.

2 participants