mafw.devtools.toolchain.tools.ruff

RuffTool — concrete ProjectTool for ruff.

This module implements the RuffTool class that manages the ruff linter/formatter across two configuration files:

  • pyproject.toml — lower-bound >= specifier in project.optional-dependencies.dev

  • .pre-commit-config.yaml — the rev field of the https://github.com/astral-sh/ruff-pre-commit repository entry

Because ruff is referenced in two places, the verify() method checks that the two declared versions are consistent. The post_update() hook recreates the dev hatch environment, then runs both the ruff-check and ruff-format hatch scripts at the highest supported Python version, and reverts both files if either script fails.

Unlike simpler project tools (e.g. git-cliff, pip-audit), RuffTool overrides update(), verify(), and post_update() because of the cross-file synchronization requirement. The base class’s _saved_content and _revert() handle pyproject.toml, while a separate _saved_precommit attribute tracks the pre-commit config file state.

Classes

RuffTool([project_root])

Manage the ruff linter/formatter across pyproject.toml and pre-commit.

class mafw.devtools.toolchain.tools.ruff.RuffTool(project_root: Path | None = None)[source]

Bases: ProjectTool

Manage the ruff linter/formatter across pyproject.toml and pre-commit.

Ruff is categorized as a project tool. Its version lower bound lives in project.optional-dependencies.dev and the pre-commit hook revision is declared in .pre-commit-config.yaml under the astral-sh/ruff-pre-commit repository. Both must stay in sync.

The update() method writes both files (pyproject first, then pre-commit). On post_update() failure, both files are reverted to their pre-update contents: pyproject.toml via the inherited _revert() helper, and .pre-commit-config.yaml via the local _saved_precommit attribute.

Parameters:

project_root (Path | None) – Path to the project root directory containing both pyproject.toml and .pre-commit-config.yaml. Defaults to the current working directory.

_get_precommit_version() Version | None[source]

Read the ruff version from the pre-commit config rev field.

Parses .pre-commit-config.yaml, locates the astral-sh/ruff-pre-commit repo entry, reads its rev field, strips the v prefix, and returns it as a Version.

Returns:

The version from the pre-commit rev field, or None if the repo or rev cannot be found.

Return type:

Version | None

_revert_all() None[source]

Restore both config files to their saved pre-update state.

Uses the parent class _revert() for pyproject.toml and manually restores .pre-commit-config.yaml from the saved content. Silently handles the case where saved content is not available.

_revert_precommit() None[source]

Restore .pre-commit-config.yaml to its saved pre-update state.

Silently handles the case where saved content is not available.

post_update() None[source]

Recreate the dev environment and run ruff-check and ruff-format.

Performs the following steps after a successful version update:

  1. Forces recreation of the dev hatch environment so that the newly specified dependency versions are resolved and installed.

  2. Determines the highest supported Python version dynamically from tool.mafw.supported-python in pyproject.toml.

  3. Runs hatch run dev.py<version>:ruff-check.

  4. Runs hatch run dev.py<version>:ruff-format.

If environment recreation fails due to a dependency conflict, both pyproject.toml and .pre-commit-config.yaml are reverted. If either ruff script fails, both files are also reverted.

Raises:

DevtoolsError – If environment recreation fails or either ruff script exits with a non-zero exit code.

update() bool[source]

Update the ruff version in pyproject.toml and .pre-commit-config.yaml.

Performs both updates:

  1. Sets the >= lower bound for ruff in project.optional-dependencies.dev to the latest PyPI version (delegated to the parent class).

  2. Updates the rev field of the astral-sh/ruff-pre-commit repo entry in .pre-commit-config.yaml to v{latest_version}.

Before modifying, saves both file contents so they can be reverted by post_update() on failure. The parent class handles saving pyproject.toml via _saved_content; this method additionally saves the pre-commit config.

Returns:

True if either file was changed, False if both are already up to date.

Return type:

bool

Raises:

DevtoolsError – If either file cannot be read or written.

verify() list[Issue][source]

Compare ruff version in pyproject.toml with the pre-commit rev.

Reads the >= lower bound from project.optional-dependencies.dev and the rev field (stripped of v prefix) from the astral-sh/ruff-pre-commit repo entry. Returns an Issue if they do not match.

Returns:

A list containing at most one toolchain.Issue if the two versions differ, or an empty list if they are consistent.

Return type:

list[toolchain.Issue]

property env_name: str

Hatch environment where ruff is validated.

Returns:

"dev"

Return type:

str

property package_name: str

PyPI package name.

Returns:

"ruff"

Return type:

str

property section_path: str

TOML section path where ruff is declared.

Returns:

"project.optional-dependencies.dev"

Return type:

str

mafw.devtools.toolchain.tools.ruff._PRECOMMIT_REPO_URL: Final[str] = 'https://github.com/astral-sh/ruff-pre-commit'

Repository URL for the ruff pre-commit hook entry.