mafw.devtools.toolchain.tools

Concrete tool implementations for the toolchain management system.

Each module in this package implements the ToolChainTool interface for a specific development tool. Tools are categorized as either "host" (managed via pipx) or "project" (managed via pyproject.toml).

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

Bases: ProjectTool

Manage the git-cliff changelog generator version in pyproject.toml.

Git-cliff is declared in project.optional-dependencies.dev with a >= lower-bound specifier. This tool queries PyPI for the latest release and updates the lower bound accordingly.

All behaviour (version detection, update, verify, bootstrap) is provided by ProjectTool.

Parameters:

project_root (Path | None) – Path to the project root directory containing pyproject.toml. Defaults to the current working directory.

property env_name: str

Hatch environment where git-cliff lives.

Returns:

"dev"

Return type:

str

property package_name: str

PyPI package name.

Returns:

"git-cliff"

Return type:

str

property section_path: str

TOML section path where git-cliff is declared.

Returns:

"project.optional-dependencies.dev"

Return type:

str

class mafw.devtools.toolchain.tools.HatchTool[source]

Bases: HostTool

Manage hatch as a host tool installed via pipx.

This tool handles bootstrapping (installing hatch via pipx), detecting the currently installed version from pipx metadata, querying PyPI for the latest release, and upgrading via pipx upgrade.

Since hatch is a host-level tool that does not modify repository files, the verify() method always returns an empty list.

All method implementations are inherited from HostTool.

property pipx_package_name: str

The pipx package name for hatch.

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

Bases: ProjectTool

Manage the mypy static type checker version in pyproject.toml.

Mypy is categorized as a project tool because its version is controlled through the types hatch environment extra-dependencies in pyproject.toml. After an update, the types environment is recreated and mypy type checking is executed at the highest supported Python version to validate compatibility. If the check fails, pyproject.toml is reverted to its pre-update state.

All standard behaviour (version detection, update, verify, bootstrap) is provided by ProjectTool. Only post_update() is overridden to run mypy type checking.

Parameters:

project_root (Path | None) – Path to the project root directory containing pyproject.toml. Defaults to the current working directory.

post_update() None[source]

Recreate the types environment and run mypy type checking.

Performs the following steps after a successful version update:

  1. Forces recreation of the types 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 mypy via hatch run types.py<version>:check.

If environment recreation fails due to a dependency conflict, the conflicting package name is extracted and reported. If the type check fails, pyproject.toml is reverted to its pre-update state.

Raises:

DevtoolsError – If environment recreation fails or the mypy check exits with a non-zero exit code.

property env_name: str

Hatch environment where mypy is validated.

Returns:

"types"

Return type:

str

property package_name: str

PyPI package name.

Returns:

"mypy"

Return type:

str

property section_path: str

TOML section path where mypy is declared.

Returns:

"tool.hatch.envs.types.extra-dependencies"

Return type:

str

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

Bases: ProjectTool

Manage pip-audit’s version lower bound in pyproject.toml.

pip-audit is categorized as a project tool because its version is controlled through the dev optional-dependencies group in pyproject.toml. There are no additional configuration files to keep in sync, so verify() always returns an empty list (inherited from ProjectTool).

All behaviour — bootstrapping, version detection, updating, and verification — is provided by the ProjectTool base class.

Parameters:

project_root (Path) – Path to the project root directory containing pyproject.toml. Defaults to the current working directory.

property env_name: str

Hatch environment where pip-audit lives.

property package_name: str

PyPI package name for pip-audit.

property section_path: str

Dot-separated TOML path to the dependency array containing pip-audit.

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

Bases: ProjectTool

Manage pre-commit’s version lower bound in pyproject.toml.

pre-commit is categorized as a project tool because its version is controlled through the dev optional-dependencies group in pyproject.toml. After an update, the dev hatch environment is recreated to ensure fresh dependency resolution, and then pre-commit run --all-files is executed to validate compatibility. If the command fails, pyproject.toml is reverted to its pre-update state.

All standard behaviour (version detection, update, bootstrap) is provided by ProjectTool. The post_update() is overridden to run pre-commit hooks, and verify() explicitly returns an empty list since pre-commit is referenced in a single location.

Parameters:

project_root (Path | None) – Path to the project root directory containing pyproject.toml. Defaults to the current working directory.

post_update() None[source]

Recreate the dev environment, then run pre-commit hooks; revert on failure.

Forces the recreation of the dev hatch environment to ensure the newly specified pre-commit version is resolved and installed. Then runs pre-commit run --all-files via the dev environment to validate compatibility. If the command fails (non-zero exit code), pyproject.toml is reverted to its saved pre-update content and a DevtoolsError is raised.

Raises:

DevtoolsError – If environment recreation fails or if pre-commit run --all-files exits with a non-zero code.

verify() list[Issue][source]

Return an empty list — pre-commit is referenced in a single location.

pre-commit has no cross-file consistency to verify (unlike ruff which appears in both pyproject.toml and .pre-commit-config.yaml).

Returns:

An empty list of issues.

Return type:

list[toolchain.Issue]

property env_name: str

Hatch environment where pre-commit hooks are run.

Returns:

"dev"

Return type:

str

property package_name: str

PyPI package name.

Returns:

"pre-commit"

Return type:

str

property section_path: str

TOML section path where pre-commit is declared.

Returns:

"project.optional-dependencies.dev"

Return type:

str

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

Bases: ProjectTool

Manage pytest’s version lower bound in pyproject.toml.

pytest is categorized as a project tool because its version is controlled through the test optional-dependencies group in pyproject.toml. After an update, the test hatch environment is recreated and the full test suite is executed at the highest supported Python version to validate compatibility. If the tests fail, pyproject.toml is reverted to its pre-update state.

All standard behaviour (version detection, update, verify, bootstrap) is provided by ProjectTool. Only post_update() is overridden to run the test suite.

Parameters:

project_root (Path | None) – Path to the project root directory containing pyproject.toml. Defaults to the current working directory.

post_update() None[source]

Recreate the test environment, then run the test suite; revert on failure.

Steps:

  1. Force recreation of the test hatch environment so that the newly specified pytest version is resolved and installed fresh.

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

  3. Execute hatch test -py <version> --without-integration --without-slow-integration from the project root.

  4. If the test suite fails (non-zero exit code), attempt to extract the conflicting package name via _parse_resolution_failure, revert pyproject.toml, and raise a descriptive error.

Raises:

DevtoolsError – If the test suite fails after the update, or if environment recreation fails due to a resolution conflict.

property env_name: str

Hatch environment where pytest is validated.

Returns:

"hatch-test"

Return type:

str

property package_name: str

PyPI package name.

Returns:

"pytest"

Return type:

str

property section_path: str

TOML section path where pytest is declared.

Returns:

"project.optional-dependencies.test"

Return type:

str

class mafw.devtools.toolchain.tools.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

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

Bases: ProjectTool

Manage Sphinx’s version lower bound in pyproject.toml.

Sphinx is categorized as a project tool because its version is controlled through the doc optional-dependencies group in pyproject.toml. After an update, the doc hatch environment is recreated and the documentation build is executed to validate compatibility. If the build fails, pyproject.toml is reverted to its pre-update state.

All standard behaviour (version detection, update, verify, bootstrap) is provided by ProjectTool. Only post_update() is overridden to run the documentation build.

Parameters:

project_root (Path | None) – Path to the project root directory containing pyproject.toml. Defaults to the current working directory.

post_update() None[source]

Recreate the doc environment and run the documentation build.

Forces recreation of the doc hatch environment to ensure the newly specified dependency versions are resolved and installed. Then executes hatch run dev.py3.14:doc from the project root.

If the documentation build fails (non-zero exit code), the pyproject.toml is reverted to its saved pre-update content and a DevtoolsError is raised. The error message includes the conflicting package name when the failure is caused by a dependency resolution conflict.

Raises:

DevtoolsError – If environment recreation or the documentation build fails after the update.

property env_name: str

Hatch environment where sphinx documentation is built.

Returns:

"dev"

Return type:

str

property package_name: str

PyPI package name for Sphinx.

Returns:

"sphinx"

Return type:

str

property section_path: str

Dot-separated TOML path to the dependency array containing Sphinx.

Returns:

"project.optional-dependencies.doc"

Return type:

str

class mafw.devtools.toolchain.tools.UvTool(pyproject_path: Path = PosixPath('pyproject.toml'))[source]

Bases: HostTool

Toolchain management for the uv package manager.

uv is installed as a host tool via pipx and its version specifier is additionally tracked in pyproject.toml under the hatch-uv hatch environment so that hatch uses a compatible uv version.

All common host-tool operations (bootstrap, version detection, PyPI queries) are inherited from HostTool. This subclass overrides update() to additionally synchronize the pyproject.toml specifier and verify() to check specifier satisfaction.

Parameters:

pyproject_path (Path) – Path to the pyproject.toml file. Defaults to pyproject.toml in the current working directory.

update() bool[source]

Upgrade uv via pipx and update the pyproject.toml specifier.

Performs two operations:

  1. Delegates to update() which runs pipx upgrade uv and checks if the version changed.

  2. If the version changed, updates the lower-bound version specifier for uv in the [tool.hatch.envs.hatch-uv] dependencies section of pyproject.toml.

Returns:

True if the version changed, False if already up to date.

Raises:

DevtoolsError – If pipx is not available, the upgrade fails, or the pyproject.toml modification fails.

verify() list[Issue][source]

Check that the pipx-installed uv satisfies the declared specifier.

Compares the version installed via pipx against the version specifier declared in pyproject.toml under [tool.hatch.envs.hatch-uv].

Returns:

A list containing one Issue if the versions are out of sync, or an empty list if consistent.

property pipx_package_name: str

The pipx package name for uv.

Modules

git_cliff

Git-cliff toolchain tool implementation.

hatch

Hatch host tool implementation.

mypy

Concrete ProjectTool implementation for mypy.

pip_audit

PipAuditTool — concrete ProjectTool for pip-audit.

precommit

Concrete ProjectTool implementation for pre-commit.

pytest

Concrete ProjectTool implementation for pytest.

pyupgrade

PyUpgradeTool — concrete ProjectTool for pyupgrade.

ruff

RuffTool — concrete ProjectTool for ruff.

sphinx

Concrete ProjectTool implementation for Sphinx.

uv

Concrete HostTool implementation for uv.