Development tools
MAFw ships with a unified development tool called devtools that supports maintenance tasks
such as building versioned documentation trees, preparing tagged releases, and verifying dependency
compatibility.
These tools are not part of the scientific user-facing workflow: a typical MAFw user does not need them, and can safely ignore this section. They exist for the benefit of the development team and for community members who want to contribute to MAFw in a consistent, reproducible way.
Requirements
The devtools CLI requires additional Python packages that are installed when MAFw is set up with
the optional [devtools] or [dev] feature:
pip install mafw[devtools]
Dependency |
Minimum supported version |
Description |
|---|---|---|
packaging |
>=26.2 |
to parse and compare dependency version specifiers |
requests |
>=2.34.0 |
to interact with the GitLab API for registry operations |
psutil |
>=7.2.2 |
to manage background processes (documentation server) |
ruamel.yaml |
>=0.18.14 |
to read and write YAML files preserving comments and formatting (pre-commit config) |
How to invoke devtools
The unified tool is available as a console entry point from an activated development environment:
devtools --help
Or via Hatch (recommended for CI/CD and for reproducible local runs):
hatch run dev.py3.14:devtools --help
Note
The Hatch environment name includes the Python version (for example dev.py3.14). On CI, the
version is typically driven by the PYTHON_VERSION variable in .gitlab-ci.yml.
Command structure
devtools
├── completion Manage shell completion
│ ├── install
│ ├── uninstall
│ └── show
├── documentation Build and manage versioned documentation
│ ├── build Build multiversion documentation tree
│ ├── current Build only the current working tree
│ ├── clean Remove output directories
│ ├── prune Remove old versions to respect a size limit
│ ├── redirects Generate GitLab Pages _redirects file
│ ├── landing Generate root landing page
│ ├── requirements Generate RST requirement files from pyproject.toml
│ ├── registry Interact with the GitLab Generic Package Registry
│ │ ├── upload
│ │ ├── download
│ │ └── delete
│ └── server Local HTTP server helper
│ ├── start
│ ├── status
│ ├── stop
│ └── restart
├── release Release lifecycle management
│ └── create Prepare a new tagged release
├── dependencies Dependency verification and maintenance
│ ├── freeze Freeze dependency upper bounds in pyproject.toml
│ ├── unfreeze Remove frozen dependency upper bounds
│ ├── latest Rolling compatibility for the latest dependencies
│ │ ├── check Verify compatibility with newest dependencies
│ │ └── compare Compare dependencies against reference pylock files
│ ├── oldest Oldest dependency stack verification
│ │ └── check Verify compatibility with oldest supported dependencies
│ ├── audit Audit dependency vulnerabilities using pip-audit
│ └── registry GitLab registry for dependency reference files
│ ├── upload
│ ├── download
│ ├── delete
│ └── prune
└── toolchain Centralized development tool version management
├── list Show all managed tools
├── check Compare current vs latest versions
├── update Bring tools to their latest versions
├── verify Check configuration consistency
└── bootstrap Install missing host tools
Shell completion
devtools exposes shell TAB completion through the completion command group.
The feature is available for bash, zsh and fish.
Install it in the active virtual environment with:
devtools completion install
If you only want to activate directly (but not permanently) the completion functionality, use:
eval "$(devtools completion show)"
Documentation commands
Purpose and idea
The documentation group builds the MAFw documentation using Sphinx and produces a directory tree
that contains:
One folder per stable tag (for example
v2.1.0).A
stablealias pointing to the latest stable tag.Optionally a
devalias for the current branch if it is ahead ofstable.A
latestfolder containing a build of the current working tree.
This makes it possible to publish multiple documentation versions (HTML and optionally PDF) in a single GitLab Pages site, while keeping the workflow reproducible and CI-friendly.
Typical usage examples
Build only the current documentation (current)
This is the fastest way to validate documentation changes on your current branch.
devtools documentation current -y
Rebuild from scratch:
devtools documentation current -y --from-scratch
Build a multiversion documentation tree (build)
devtools documentation build --min-vers v1.0.0 --build-pdf
How documentation is built on CI
In the GitLab pipeline, the multiversion documentation is generated by the doc_build_all job:
hatch run dev.py${PYTHON_VERSION}:devtools documentation build \
--min-vers $DOC_MIN_VERS \
--build-pdf \
--max-size $DOC_MAX_SIZE \
--zip-filepath /tmp/zips \
--with-zip-file \
--with-upload-zip \
--with-cached-packages
Start a local documentation server
After building the documentation locally, serve the generated tree over HTTP:
devtools documentation server start -d docs/build -p 8000
Even though one can browse directly the generated files in the browser (file:///), serving the pages via a real server assures the proper functioning of all JavaScript and version switching mechanism.
Release commands
Purpose and idea
The release group orchestrates the MAFw release lifecycle: version bumps, changelog updates,
and tagging. It enforces consistency and automates repetitive tasks.
Release reproducibility and rolling compatibility
MAFw uses open lower bounds during development (for example rich>=13.9.4) to allow working
against newer upstream releases. For tagged releases, however, reproducibility matters.
The release create command applies a freeze → release → unfreeze pattern:
Freeze: rewrite dependency specifiers with explicit upper bounds based on the highest resolved version.
Release: the release commit includes the frozen
pyproject.toml.Unfreeze: remove the computed upper bounds so development continues unrestricted.
Documentation target version
The documentation target version is the major.minor value used by the release workflow to
annotate public API docstrings with Sphinx directives such as versionadded and
versionchanged.
Prepare a new release (release create)
The release create command automates the entire release pipeline. It requires a positional
argument SEGMENTS which is passed to Hatch (e.g., minor,rc, rc, or release).
devtools release create minor,rc --dry-run
Logical workflow summary
Safety checks: Verify the current branch is
mainand the working tree is clean.Freeze: Rewrite
pyproject.tomlto add explicit upper bounds to dependencies.Bump: Update the project version using
hatch version.Doc target: Update the documentation target version used by docstring version directives.
Metadata: Update
NOTICE.txtandCHANGELOG.md.Requirements: Update the requirements RST files and
README.rstwith frozen dependencies.Notes: Optionally generate a
release_note_vX.Y.Z.mdfile.Tag: Commit the changes and create a local git tag.
Unfreeze: Remove the computed upper bounds from
pyproject.toml.Requirements: Restore the requirements RST files and
README.rstto open upper bounds.Commit: Create a second commit on
mainwith the unfrozen dependencies.Push: Optionally push both commits and the tag to the remote repository.
Dependencies commands
Purpose and idea
The dependencies group ensures MAFw is compatible with both the latest and oldest supported
dependency stacks. It also provides tools for freezing upper bounds, auditing vulnerabilities,
and managing reference files in the GitLab Generic Package Registry.
Verify dependency stacks
Verify against newest dependencies:
devtools dependencies latest check
Verify against oldest supported dependencies (using lowest-direct resolution):
devtools dependencies oldest check
Both commands support --preserve-envs to keep hatch environments for local debugging.
Deprecated since version 2.3: The --remove-envs/--no-remove-envs option on dependencies oldest check is deprecated.
Use --preserve-envs instead.
Compare dependency versions (dependencies latest compare)
The compare subcommand detects ecosystem drift by comparing the latest resolved dependency
versions against reference pylock files.
devtools dependencies latest compare
devtools dependencies latest compare -o drift-report.md -f markdown
devtools dependencies latest compare -o drift-report.json -f json
devtools dependencies latest compare --gitlab-ref
Freeze and unfreeze
devtools dependencies freeze
devtools dependencies unfreeze
Manage dependency reference files (dependencies registry)
To speed up CI/CD pipelines, devtools can cache dependency reference files in the GitLab
Generic Package Registry.
devtools dependencies registry upload --all
devtools dependencies registry download --all
devtools dependencies registry prune
Added in version 2.3: The dependencies registry prune command.
Vulnerabilities check (dependencies audit)
A scheduled pipeline executed every night verifies that there are no known vulnerabilities for all MAFw dependencies. To run the audit manually:
devtools dependencies audit
Toolchain commands
Purpose and idea
The toolchain group centralizes management of all development tool versions used by MAFw. It
covers four main activities:
Checking whether tools are at their latest versions.
Updating tools following their declared update policy (pipx upgrade for host tools, lower-bound bump for project tools).
Verifying configuration consistency across
pyproject.tomland.pre-commit-config.yaml.Bootstrapping missing tools for a fresh development environment.
Tools are categorized as either host (installed system-wide via pipx) or project (managed
through pyproject.toml). By default, only project tools are processed; host tools are included
explicitly via --include-host.
Command tree
devtools toolchain
├── list – Show all managed tools
├── check – Compare current vs latest versions
├── update – Bring tools to their latest versions
├── verify – Check configuration consistency
└── bootstrap – Install missing host tools
Group-level options
The toolchain group accepts two mutually exclusive flags that control whether host tools
(installed via pipx) participate in subcommand processing:
--include-hostInclude host tools (hatch, uv) in the operation. When specified, both host and project tools are processed.
--exclude-hostExplicitly exclude host tools from the operation. This is the default behavior when neither option is provided.
If both --include-host and --exclude-host are specified, the CLI rejects the invocation
with an error message.
Subcommand-level filtering options
Each subcommand (list, check, update, verify, bootstrap) accepts two repeatable
options for filtering individual tools by name:
-i/--include <name>Process only the named tools. Can be repeated to include multiple tools. Unrecognized names produce a warning but do not abort.
-e/--exclude <name>Process all applicable tools except the named ones. Can be repeated to exclude multiple tools.
These two options are mutually exclusive: specifying both -i and -e in the same invocation
results in an error.
Example — update only ruff and mypy:
devtools toolchain update -i ruff -i mypy
Example — check all project tools except sphinx:
devtools toolchain check -e sphinx
List (toolchain list)
Displays a table of all applicable managed tools showing their name and category.
devtools toolchain list
To include host tools in the listing:
devtools toolchain --include-host list
Check (toolchain check)
Compares the currently configured version of each tool against its latest available version and reports whether tools are in sync. Exits with a non-zero exit code if any tool is out of date or if a version detection error occurred.
devtools toolchain check
Include host tools in the check:
devtools toolchain --include-host check
Update (toolchain update)
Brings tools to their latest versions following each tool’s update policy. After a successful
update, a post-update validation hook runs (for example, the full test suite for pytest, or
ruff check for ruff). If validation fails, the update is reverted automatically.
devtools toolchain update
Update only a specific tool:
devtools toolchain update -i ruff
Include host tools in the update:
devtools toolchain --include-host update
Verify (toolchain verify)
Checks that all tool configurations are internally consistent. For example, it detects when the
ruff version in pyproject.toml differs from the rev field in .pre-commit-config.yaml,
or when the pipx-installed uv version does not satisfy the declared constraint in the hatch-uv
environment. Exits with code 1 if any inconsistency is found.
devtools toolchain verify
Bootstrap (toolchain bootstrap)
Installs missing tools for a fresh development environment. For host tools, this runs
pipx install; project tools that are already declared in pyproject.toml are typically
available after a pip install -e .[dev] and are skipped. Exits with a non-zero code if any
installation fails.
devtools toolchain --include-host bootstrap
Managed tools
The following table lists all tools managed by the toolchain command group:
Tool |
Category |
Update policy |
|---|---|---|
hatch |
host |
|
uv |
host |
|
pytest |
project |
Lower bound bump in |
mypy |
project |
Lower bound bump in |
sphinx |
project |
Lower bound bump in |
ruff |
project |
Lower bound bump in |
pre-commit |
project |
Lower bound bump in |
git-cliff |
project |
Lower bound bump in |
pip-audit |
project |
Lower bound bump in |