Repository navigation
docs: add AGENTS.md for the repository, monai/transforms and tests #9200
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
AyanZahid-Code
wants to merge
3
commits into
Project-MONAI:dev
Choose a base branch
from
AyanZahid-Code:docs/9199-agents-md
base: dev
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+217
−0
Open
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| # AGENTS.md | ||
|
|
||
| Notes for AI coding assistants working in this repository. Human contributors should read | ||
| [CONTRIBUTING.md](CONTRIBUTING.md) — this file only adds the machine-facing details and links back | ||
| to it rather than repeating it. | ||
|
|
||
| ## Project overview | ||
|
|
||
| MONAI is an open-source framework for deep learning in medical imaging, built on PyTorch. It ships | ||
| transforms, networks, losses, metrics, data loading, engines and bundle workflows for 2D and 3D | ||
| medical images. Supported Python and PyTorch versions are declared in | ||
| [pyproject.toml](pyproject.toml) and [setup.py](setup.py); read them there instead of copying | ||
| version numbers into prose. | ||
|
|
||
| ## Repository map | ||
|
|
||
| | Path | Purpose | | ||
| |------|---------| | ||
| | `monai/transforms` | array, dictionary (`*d`) and random (`Rand*`) transforms, lazy resampling, invertible transforms | | ||
| | `monai/networks` | `nets`, `blocks`, `layers`, `schedulers` | | ||
| | `monai/data` | datasets, image readers, `MetaTensor` | | ||
| | `monai/losses` | loss functions | | ||
| | `monai/metrics` | metrics and the confusion-matrix machinery | | ||
| | `monai/bundle` | YAML workflow configuration and the scripts that run it | | ||
| | `monai/apps` | applications built on the frameworks (pathology, radiology, ...) | | ||
| | `monai/auto3dseg` | automated 3D segmentation | | ||
| | `monai/engines` | engine base classes | | ||
| | `monai/handlers` | handler base classes and the concrete handlers | | ||
| | `monai/fl` | federated learning | | ||
| | `monai/inferers` | inference helpers | | ||
| | `monai/optimizers` | optimizers and learning-rate schedulers | | ||
| | `monai/visualize` | visualization helpers | | ||
| | `monai/utils` | shared helpers, `optional_import`, deprecation decorators | | ||
| | `monai/csrc` | optional C++/CUDA extensions | | ||
| | `monai/config` | the `python -m monai.config` command line entry point | | ||
| | `monai/_extensions` | optional compiled extensions loaded at runtime | | ||
| | `tests` | unit tests, mirroring the `monai` tree | | ||
| | `docs` | Sphinx sources: `docs/source/*.rst` and `docs/source/*.md` | | ||
|
|
||
| ## Where the detail lives | ||
|
|
||
| | File | Covers | | ||
| |------|--------| | ||
| | [monai/transforms/AGENTS.md](monai/transforms/AGENTS.md) | transform families, `MetaTensor`, invertibility, random state, lazy resampling | | ||
| | [tests/AGENTS.md](tests/AGENTS.md) | test layout, `min_tests.py`, skip decorators, running a single test | | ||
|
|
||
| ## Setup and commands | ||
|
|
||
| ```bash | ||
| ./runtests.sh --setup # install the pre-commit hooks (black, isort, ruff, DCO sign-off) | ||
| ./runtests.sh --autofix # format the working tree (isort + black) | ||
| ./runtests.sh --codeformat # style and static analysis checks | ||
| ./runtests.sh --quick --unittests # fast local verification | ||
| ./runtests.sh -f -u --net --coverage # recommended before opening a pull request | ||
| python -m tests.losses.test_dice_loss # run a single test module | ||
| ``` | ||
|
|
||
| `./runtests.sh -h` lists every option. | ||
|
|
||
| ## Repo-wide conventions | ||
|
|
||
| - Pull requests target the `dev` branch, and every commit carries a `Signed-off-by` line | ||
| (`git commit -s`). See [CONTRIBUTING.md](CONTRIBUTING.md#submitting-pull-requests). | ||
| - Line length is 120; `black`, `isort` and `ruff` all read it from | ||
| [pyproject.toml](pyproject.toml). | ||
| - New source files start with the Apache 2.0 header quoted in | ||
| [CONTRIBUTING.md](CONTRIBUTING.md#licensing-information). | ||
| - Optional dependencies are only ever reached through `monai.utils.optional_import` | ||
| (`monai/utils/module.py`); never import an optional package at module scope. | ||
| - A new public symbol is added to `__all__` in the module that defines it, re-exported from the | ||
| package `__init__.py`, and listed in the matching `docs/source/<area>.rst`. | ||
| - Deprecations go through `monai.utils.deprecated` and `monai.utils.deprecated_arg` | ||
| (`monai/utils/deprecate_utils.py`) with `since` and `removed` versions. | ||
| - Tests mirror the source tree: `monai/transforms/spatial/array.py` is covered by | ||
| `tests/transforms/test_*.py`. | ||
| - Use American English spelling, and f-strings rather than `%` formatting. See | ||
| [CONTRIBUTING.md](CONTRIBUTING.md#utility-functions). | ||
| - Prefer the shared helpers in `monai/utils` and `monai/networks/utils.py` over re-implementing | ||
| them. | ||
|
|
||
| ## AI-assisted contributions | ||
|
|
||
| MONAI accepts tool-assisted contributions under the conditions set out in | ||
| [CONTRIBUTING.md](CONTRIBUTING.md#tool-assisted-contribution-policy): the submitter reviews the | ||
| content, takes responsibility for it, signs off the work, and labels AI-generated content. The | ||
| policy is not repeated here. | ||
|
|
||
| ## Do not | ||
|
|
||
| - Edit generated files: `monai/_version.py` and the versioneer output. | ||
| - Commit data, weights or binaries. Test data is downloaded at test time, see | ||
| [CONTRIBUTING.md](CONTRIBUTING.md#testing-data). | ||
| - Change CI workflows unless the task is about them. | ||
| - Add personal tooling configuration, machine-specific paths or secrets to the repository. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| # AGENTS.md — `monai/transforms` | ||
|
|
||
| Notes for AI coding assistants changing `monai/transforms`. The repository-wide rules live in the | ||
| root [AGENTS.md](../../AGENTS.md); human contributors should read | ||
| [CONTRIBUTING.md](../../CONTRIBUTING.md). | ||
|
|
||
| ## Module map | ||
|
|
||
| | Path | Contents | | ||
| |------|----------| | ||
| | `transform.py` | base classes: `Transform`, `MapTransform`, `RandomizableTransform`, `LazyTransform` | | ||
| | `traits.py` | `LazyTrait`, `InvertibleTrait`, `RandomizableTrait`, `MultiSampleTrait`, `ReduceTrait` | | ||
| | `inverse.py` | `TraceableTransform`, `InvertibleTransform` — the transform stack and its inversion | | ||
| | `compose.py` | `Compose`, the pipeline that runs the transforms | | ||
| | `lazy/` | lazy resampling: `ApplyPending` and the pending `Affine`/`DisplacementField` bookkeeping | | ||
| | `croppad/`, `intensity/`, `io/`, `post/`, `regularization/`, `signal/`, `smooth_field/`, `spatial/`, `utility/` | the transform families | | ||
| | `meta_utility/` | dictionary-only transforms that work on `MetaTensor` metadata | | ||
| | `utils.py` | helpers shared by the transforms | | ||
|
|
||
| Each family directory follows the same convention: | ||
|
|
||
| - `array.py` — the transform applied to a single tensor, e.g. `Spacing`. | ||
| - `dictionary.py` — the dictionary variant named with a `d` suffix, e.g. `Spacingd`. | ||
| - `functional.py` — the functional API, where present (`croppad`, `lazy`, `spatial`). | ||
| - `batch.py` — batched dictionary transforms (`croppad` only). | ||
|
|
||
| ## Traps | ||
|
|
||
| **A transform is usually three or four classes.** Adding a transform means the array class, the `*d` | ||
| dictionary class, and a `Rand*` class when the transform is randomizable. A dictionary transform | ||
| derives from `MapTransform` and selects the keys it applies to with `key_iterator`; it is not the | ||
| array class with a different name. | ||
|
|
||
| **`MetaTensor` must survive the call.** `MetaTensor` (`monai/data/meta_tensor.py`) carries the | ||
| affine matrix, the original spatial shape and the stack of applied transforms. Converting to a | ||
| plain `torch.Tensor` or to numpy inside a transform silently drops that metadata and breaks | ||
| inversion and resampling, so keep the input type. | ||
|
|
||
| **Randomness goes through `self.R`.** `RandomizableTransform` owns a `numpy.random.RandomState` | ||
| that `set_random_state` configures, and `randomize()` runs it on every call. Using the global | ||
| `np.random` bypasses the seed, and the transform is no longer reproducible. | ||
|
|
||
| **Invertibility has a contract.** Inherit `InvertibleTransform`, call `push_transform` in | ||
| `__call__` and `pop_transform` in `inverse`, and keep the extra information needed by the inverse | ||
| in `extra_info`. `extra_info` may only hold values that survive the data loader's collate | ||
| function, so `None` is not allowed. The stack itself lives in | ||
| `MetaTensor.applied_operations` and is unwound in last-in-first-out order. | ||
|
|
||
| **Lazy resampling is opt-in and deferred.** A `LazyTransform` describes its operation as an affine | ||
| matrix and lets the pipeline resample once, at the end. `requires_current_data` marks the | ||
| transforms that cannot be deferred, and `ApplyPending` forces the pending resampling to happen. | ||
| Turning `lazy` on changes when the pixels are computed, so a change here needs a test that pins | ||
| the output, not only the shape. | ||
|
|
||
| **A new transform is also a docs and export change.** Re-export it from | ||
| `monai/transforms/__init__.py`, add an `.. autoclass::` entry in `docs/source/transforms.rst`, and | ||
| add the module to `docs/source/transforms_idx.rst` when it is a new module. | ||
|
|
||
| **Tests mirror the family.** `tests/transforms/test_<name>.py` covers the array transform and | ||
| `tests/transforms/test_<name>d.py` the dictionary one; the inversion tests live in | ||
| `tests/transforms/inverse/`. A transform that is not covered there is not covered. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| # AGENTS.md — `tests` | ||
|
|
||
| Notes for AI coding assistants changing the MONAI test suite. The repository-wide rules live in the | ||
| root [AGENTS.md](../AGENTS.md); human contributors should read | ||
| [CONTRIBUTING.md](../CONTRIBUTING.md). | ||
|
|
||
| ## Layout | ||
|
|
||
| `tests/` mirrors the `monai` package: `tests/transforms`, `tests/networks`, `tests/data`, | ||
| `tests/losses`, `tests/metrics`, `tests/bundle`, `tests/apps`, `tests/auto3dseg`, | ||
| `tests/engines`, `tests/handlers`, `tests/inferers`, `tests/optimizers`, `tests/utils`, | ||
| `tests/visualize`, plus `tests/integration` for the end-to-end workflows. | ||
|
|
||
| File names follow the convention in [CONTRIBUTING.md](../CONTRIBUTING.md#unit-testing): | ||
|
|
||
| - `test_[module_name].py` — a unit test module. | ||
| - `test_[module_name]_dist.py` — a unit test module that needs a distributed environment. | ||
| - `test_integration_[workflow_name].py` — an end-to-end test. | ||
|
|
||
| ## Running tests | ||
|
|
||
| ```bash | ||
| python -m tests.losses.test_dice_loss # a single test module | ||
| ./runtests.sh --quick --unittests # fast local verification | ||
| ./runtests.sh -f -u --net --coverage # recommended before opening a pull request | ||
| QUICKTEST=true python -m tests.min_tests # the minimal suite, without optional dependencies | ||
| ``` | ||
|
|
||
| `./runtests.sh -h` lists every option. | ||
|
|
||
| ## Traps | ||
|
|
||
| **Optional dependencies decide how a test is written.** Reach an optional package through | ||
| `monai.utils.optional_import` and skip the test when it is missing, either with the | ||
| `SkipIfNoModule` / `SkipIfModule` decorators in `tests/test_utils.py` or with the | ||
| `skipUnless(has_matplotlib, ...)` pattern. When a whole module needs an optional package, add its | ||
| name to `exclude_cases` in `tests/min_tests.py` so the minimal runner skips it; that list is | ||
| checked for duplicates, so add the name once. | ||
|
|
||
| **Test data is not in the repository.** The URLs live in | ||
| `tests/testing_data/data_config.json` and are read with `testing_data_config`, and the download | ||
| itself goes through `download_url_or_skip_test` — both in `tests/test_utils.py`. The `--net` runs | ||
| exercise the download path. Never add images, weights or other binaries to the repository, and do | ||
| not edit `tests/testing_data` to make a test pass. | ||
|
|
||
| **Import the helpers from `tests.test_utils`.** The shared helpers — `skip_if_quick`, | ||
| `skip_if_downloading_fails`, `skip_if_no_cpp_extension`, `skip_if_no_cuda`, `skip_if_windows`, | ||
| `skip_if_darwin`, `assert_allclose`, `dict_product` — live in `tests/test_utils.py`; the | ||
| `tests/utils` package holds the tests of `monai.utils` itself. | ||
|
|
||
| **`skip_if_quick` is the marker of a slow test.** A test that takes more than a couple of seconds | ||
| is expected to carry it, otherwise `--quick` and the minimal runner pay for it. | ||
|
|
||
| **A new test module should stay small in its dependencies.** The recommended set is the Python | ||
| standard library, `torch`, `numpy`, `coverage` and `parameterized`; anything else has to be | ||
| declared in `pyproject.toml` and, when it is optional, excluded from the minimal run as described | ||
| above. |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
--autofix also runs ruff check --fix --unsafe-fixes and the copyright-header fixer, not only isort and black. Worth saying, since an assistant will run it across the whole tree and should expect those edits.