Contributing and development¶
This page is for people changing MIR itself. It covers the development setup, code style, the stability rules the package follows, and the checks every change has to pass.
Development setup¶
git clone https://github.com/junyuchen245/MIR.git
cd MIR
python3.8 -m pip install -e .[dev] # pytest, ruff, pre-commit
pre-commit install # run lint and formatting on every commit
Repository layout¶
Path |
Contents |
|---|---|
|
Registration networks, configuration factories ( |
|
Losses, regularizers and evaluation metrics. |
|
Training, visualization, I/O and analysis helpers. |
|
Unit and regression tests (CPU, about a minute). |
|
Compatibility checks used when refactoring (see below). |
|
Runnable training and inference scripts. They are users of the package, not part of it. |
Vendored code. models/SITReg, models/fireants, models/convexAdam, intensity_normalization
and random_image_generation/perlin_numpy are third-party projects kept close to upstream. They are
excluded from linting and formatting (pyproject.toml) and should only receive minimal, clearly marked fixes.
Code style¶
Lint and format with ruff; the configuration is in
pyproject.toml:ruff check src/MIR tests tools ruff format src/MIR tests tools
Docstrings follow the Google convention (
Args:,Returns:,Raises:) and state tensor shapes explicitly, e.g.[B, 3, H, W, D]for a displacement field in voxels. They are rendered in the API reference, so describe what the code does, including return-tuple order.Python 3.8 compatibility. The tutorials run with
python3.8: usetypingforms in annotations (Optional[int],List[int],Tuple[...]), notint | Noneorlist[int].Type hints on public functions and methods wherever the type is clear.
Device handling. Never hard-code
.cuda()or'cuda:0': create tensors on the input’s device (x.device) or move cached tensors with.to(x.device)inforward. All losses and models must run on CPU, which is also how the tests run.
API stability¶
The tutorials, downstream projects and published checkpoints depend on the package in detail, so MIR treats its whole module tree as public:
Do not move, rename or remove modules, classes, functions, methods or parameters. Tutorials import deep paths such as
MIR.models.registration_utilsorMIR.models.VFA.Decoder.New parameters go at the end of a signature and have defaults that preserve the old behaviour.
Keep
state_dictparameter names and shapes unchanged: pretrained weights are loaded by name withstrict=True. If a buffer becomes non-persistent, drop the stale key in_load_from_state_dict(seeSpatialTransformer) so older checkpoints keep loading.Changes in numerical output are bug fixes or explicit opt-in features, never side effects of refactoring.
Checks¶
Run the unit tests and the linter for every change:
python3.8 -m pytest tests -q
ruff check src/MIR tests tools && ruff format --check src/MIR tests tools
The test suite includes tests/test_public_api.py, which compares every first-party module against
tests/data/public_api.json: removing a name or changing a parameter fails CI. After an intended,
backwards-compatible addition, refresh the reference with python3.8 tools/api_snapshot.py --write-test-data.
Refactoring also has to pass the compatibility checks in tools/. Record the references before making
changes, then compare after each step:
# before: record the public API and reference outputs
python3.8 tools/api_snapshot.py --write /tmp/api.json
python3.8 tools/golden_outputs.py --write /tmp/golden.json
# after each change: all three must pass
tools/check_all.sh /tmp/api.json /tmp/golden.json
Tool |
What it guarantees |
|---|---|
|
Every module still imports, and no public name was removed or had its parameters (names, kinds, defaults) changed. Type annotations may be added freely. |
|
Fixed-seed CPU forward passes of every model family, every loss, regularizer and metric produce the same
numbers, every model has the same |
|
A formatting or documentation-only edit changed no code: compares syntax trees, optionally ignoring
docstrings and type annotations ( |
Adding a model¶
Put the network in
src/MIR/models/<Name>.pyand, if it is configurable, a factory inconfigs_<Name>.pyreturning anml_collections.ConfigDict.Export it from
src/MIR/models/__init__.pyand add it to__all__.Add a CPU test in
tests/that builds a small instance and runs a forward pass, and a case intools/golden_outputs.py.Document it: a page under
docs/models/, an entry in API reference, and a runnable tutorial folder.
Building the documentation¶
python3.8 -m pip install -e .[docs]
python3.8 -m sphinx -b html docs docs/_build/html
The API pages are generated from the docstrings at build time (docs/api is not committed).