Skip to content

Migrate linting from black to ruff, with a stricter rule set enforced by pre-commit #22

Description

@AlexLipp

The repo currently lints with black --line-length=100 only, pinned at black==22.6.0 in .pre-commit-config.yaml. That is formatting alone — no import sorting, no unused-import detection, no modernisation, no bug-pattern checks. Proposal: replace it with ruff, which covers formatting and linting in one fast tool.

Proposed configuration

Add to pyproject.toml (which currently has only [build-system] and [tool.pytest.ini_options]):

[tool.ruff]
line-length = 100          # keep the repo's existing width
target-version = "py311"

[tool.ruff.lint]
select = [
  "E", "F",      # pycodestyle + pyflakes
  "I",           # isort - import order
  "UP",          # pyupgrade - modern syntax
  "B",           # bugbear - common bug patterns
  "SIM",         # simplify - redundant code
  "C4",          # comprehension cleanups
  "NPY",         # numpy-specific gotchas
  "PTH",         # use pathlib over os.path
  "RUF",         # ruff's own extra checks
]

And replace the black hook in .pre-commit-config.yaml:

repos:
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.16.0
    hooks:
      - id: ruff
        args: [--fix]
      - id: ruff-format
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v5.0.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-added-large-files

Refactoring the codebase to conform

This is the bulk of the work, and the reason it needs to be a deliberate pass rather than a drive-by:

  • network_unmixer.py is entirely under # fmt: off (line 2), so no formatter has ever touched it. It has many lines well over 100 characters (one docstring line is 744 characters). Deciding whether to lift # fmt: off — and reflowing if so — is the single biggest decision here. ELEMENT_LIST carries # fmt: skip and must keep it.
  • Expect a meaningful number of UP and PTH hits: the codebase uses typing.Dict/List/Optional throughout (pre-PEP 585/604 style) and os.path in places.
  • B will likely flag the bare assert statements used for input validation, and the broad raise Exception(...) calls in solve (TRY/EM rules would too, if adopted).
  • The codebase is annotated for pyre and carries deliberate # pyre-fixme comments — these must survive the pass.
  • Any rule that genuinely needs suppressing should get a # noqa: RULE with a one-line reason, not a blanket ignore.

Suggested sequencing

  1. Add the ruff config and run ruff check in report-only mode to size the problem.
  2. Land the mechanical --fix-able changes first (imports, comprehensions, pyupgrade) in one commit.
  3. Handle # fmt: off in network_unmixer.py as a separate, reviewable commit.
  4. Address remaining hand-fix rules.
  5. Swap the pre-commit hooks and re-run pre-commit install; note in the README that collaborators need to run it once after cloning.

Keeping hooks to lint/format only — the full test suite is slow by design (Hypothesis, deadline=None) and belongs in CI, not a per-commit hook.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions