Skip to content

Add spatial shape constraints to UNETR docstring and validation - #9093

Open
Lubnaaziz-28 wants to merge 72 commits into
Project-MONAI:mainfrom
Lubnaaziz-28:docs/unetr-spatial-constraints
Open

Add spatial shape constraints to UNETR docstring and validation#9093
Lubnaaziz-28 wants to merge 72 commits into
Project-MONAI:mainfrom
Lubnaaziz-28:docs/unetr-spatial-constraints

Conversation

@Lubnaaziz-28

Copy link
Copy Markdown

Description

Adds documentation and validation for the spatial shape constraint that each dimension of img_size must be divisible by 16 (the patch size).

Changes

  • Added "Spatial Shape Constraints" section to UNETR class docstring
  • Added validation check in __init__ that raises ValueError if img_size is not divisible by 16
  • Added examples of valid input sizes

Related

Partially addresses #6771 (documentation of spatial shape constraints for networks)

Testing

from monai.networks.nets import UNETR

# Valid size
net = UNETR(in_channels=1, out_channels=4, img_size=(96, 96, 96))

# Invalid size (raises ValueError)
net = UNETR(in_channels=1, out_channels=4, img_size=(100, 100, 100))

ericspod and others added 30 commits June 15, 2026 13:22
### Description

Sets the weekly preview version to start with 1.7.

### Types of changes
<!--- Put an `x` in all the boxes that apply, and remove the not
applicable items -->
- [x] Non-breaking change (fix or new feature that would not break
existing functionality).
- [ ] Breaking change (fix or new feature that would cause existing
functionality to change).
- [ ] New tests added to cover the changes.
- [ ] Integration tests passed locally by running `./runtests.sh -f -u
--net --coverage`.
- [ ] Quick tests passed locally by running `./runtests.sh --quick
--unittests --disttests`.
- [ ] In-line docstrings updated.
- [ ] Documentation updated, tested `make html` command in the `docs/`
folder.

Signed-off-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
… matrix (Project-MONAI#8888)

Closes Project-MONAI#6711.

### Description

This PR adds a documentation note to the `Transpose` and `Transposed`
transforms clarifying that they do not update the affine matrix in the
image metadata. As established in Project-MONAI#5975, this is intended behavior:
applying an affine-dependent transform such as `Spacing`/`Spacingd`
after `Transpose`/`Transposed` can therefore produce unexpected results.
The note points users to `Orientation`/`Orientationd` for affine-aware
reorientation.

This is a documentation-only change; no functional code is modified.

### Types of changes
<!--- Put an `x` in all the boxes that apply, and remove the not
applicable items -->
- [x] Non-breaking change (fix or new feature that would not break
existing functionality).
- [ ] Breaking change (fix or new feature that would cause existing
functionality to change).
- [ ] New tests added to cover the changes.
- [ ] Integration tests passed locally by running `./runtests.sh -f -u
--net --coverage`.
- [ ] Quick tests passed locally by running `./runtests.sh --quick
--unittests --disttests`.
- [x] In-line docstrings updated.
- [ ] Documentation updated, tested `make html` command in the `docs/`
folder.

Signed-off-by: Akarsh Doki <doki.ak@northeastern.edu>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
…ject-MONAI#8887)

Fixes Project-MONAI#8886 

### Types of changes
- [x] Non-breaking change (fix or new feature that would not break
existing functionality).

---------

Signed-off-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
Signed-off-by: Soumya Snigdha Kundu <soumya_snigdha.kundu@kcl.ac.uk>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
…ect-MONAI#8893)

Fixes Project-MONAI#8892

### Description
During automated test execution, the logs were getting flooded with
thousands of verbose lines when `unittest.TestCase.assertWarns`
internally triggered property accessors for `__warningregistry__` on
dynamic configurations.

This PR globally configures `pytest` inside `setup.cfg` to ignore and
suppress regex pattern filter hits matching `.*__warningregistry__.*`,
significantly cleaning up the CI/CD pipeline output logs.

Signed-off-by: jet1technology-tech <jet1technology@ryngo.in>
Co-authored-by: jet1technology-tech <jet1technology@ryngo.in>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
### Description

Test-only cleanup. Removes byte-identical duplicate cases and one
permanently-skipped test. No production code or test logic changes.

### Changes

Duplicate within-file parametrized cases (identical entries that
asserted the same thing twice, so removal changes nothing covered):

- `tests/losses/test_unified_focal_loss.py`: both `TEST_CASES` entries
were identical
- `tests/inferers/test_sliding_window_inference.py`: duplicate `3D small
roi` case
- `tests/losses/test_dice_loss.py`: `sigmoid` case repeated
- `tests/losses/test_generalized_dice_loss.py`: `sigmoid` case repeated
- `tests/transforms/utility/test_apply_transform_to_pointsd.py`:
duplicate entry

Dead test removed:

- `tests/apps/test_download_url_yandex.py`: removed `test_verify` and
its now-unused `YANDEX_MODEL_URL`. It was permanently
`@unittest.skip`-ed ("data source unstable") and hits an external Yandex
URL, so it never runs in CI. The error path stays covered by
`test_verify_error`.

### Types of changes
- [x] Non-breaking change (test-only cleanup)
- [x] In-line documentation / comments updated as needed
- [x] All tests passing locally

---------

Signed-off-by: Soumya Snigdha Kundu <soumya_snigdha.kundu@kcl.ac.uk>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
## Summary
Fixes Project-MONAI#6397

- Adds a `_spatial_ndim: int` attribute to `MetaTensor` that explicitly
tracks the number of spatial dimensions, preventing dimension-mismatch
crashes when `einops.rearrange()` or other reshape operations change
`ndim`
- The attribute propagates through `copy_meta_from` (via `__dict__`
copy) and is preserved through arbitrary torch operations
- Updates transforms (`Resize`, `Rotate`, `Zoom`, `Flip`, `Affine`,
`SplitDim`, `AddCoordinateChannels`, etc.) and lazy resampling to use
`spatial_ndim` instead of hardcoded 3

### Key design decisions
- **Constructor**: `spatial_ndim = min(affine.shape[-1] - 1, ndim - 1)`
— clamped by actual tensor dims
- **Affine setter**: `spatial_ndim = affine.shape[-1] - 1` — no clamping
(user is explicit)
- **`peek_pending_affine`**: uses affine's inner matrix shape (fixes
batched `(1,4,4)` case)
- **`spatial_resample`**: `min(spatial_ndim, ndim - 1, 3)` — adds ndim-1
constraint as safety net

### Files changed (16)
- `monai/data/meta_obj.py`, `meta_tensor.py`, `utils.py`, `__init__.py`
— core MetaTensor changes
- `monai/transforms/` — spatial, croppad, intensity, inverse, lazy,
post, utility transforms updated
- `tests/data/meta_tensor/test_spatial_ndim.py` — 18 new tests
- Existing test files updated with `spatial_ndim` assertions

## Test plan
- [x] 18 new unit tests for `spatial_ndim` property (construction,
affine sync, propagation, einops reshape, transforms)
- [x] Existing MetaTensor tests pass (162 tests)
- [x] SqueezeDim and SplitDim tests pass with new assertions
- [x] Total: 216 tests verified passing

---------

Signed-off-by: Soumya Snigdha Kundu <soumya_snigdha.kundu@kcl.ac.uk>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
…Project-MONAI#8727)

## Summary
This PR improves the documentation for the `Affine` transform and adds
unit tests for the `compute_w_affine` method.

Fixes Project-MONAI#7092

## Changes

### Documentation improvements (`monai/transforms/spatial/array.py`)
- **Added Note section** to `Affine` class documenting the center-origin
coordinate system assumption
- **Clarified `normalized` parameter** documentation with user-friendly
explanation
- **Added comprehensive docstring** to `compute_w_affine` classmethod
(previously undocumented)

### Unit tests (`tests/transforms/test_affine.py`)
- Added `TestComputeWAffine` test class with focused tests:
  - 2D/3D identity matrix with same input/output size
  - Different input/output sizes with expected translation offsets
  - Output shape validation
  - Torch tensor input compatibility

## Verification
- All existing Affine tests pass (no regressions)
- All new `compute_w_affine` tests pass
- Documentation matches actual code logic

## Type of change
- [x] Documentation improvement
- [x] Test coverage improvement
- [ ] Breaking change

Signed-off-by: Mohamed Salah <eng.mohamed.tawab@gmail.com>
Signed-off-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
…l compatibility (Project-MONAI#8912)

## Summary

- Rebase Docker image from `nvcr.io/nvidia/pytorch:24.10-py3` to
`25.03-py3` to support RTX 5090 (Blackwell, SM_120/CUDA 12.8); remove
the now-obsolete `torch.patch` ONNX revert which was specific to 24.10
- Pin `mlflow<3.0` — mlflow 3.x is broken on Python 3.12 due to a
relative import in `mlflow.utils.uv_utils` (`from .. import zipp` fails
at top-level scope); this caused 4 tutorial notebooks to fail in our CI
run
- Pin `transformers<5.0` — transformers 5.x references
`torch.float8_e8m0fnu` which does not exist in the nv25.03 build of
PyTorch 2.7; this caused the HuggingFace tutorial to fail
- Add `aim` and `lightning>=2.0` as declared dependencies in
`requirements-dev.txt` (were previously undeclared but required by
tutorial notebooks)
- Rebuild the NVIDIA pip constraint file to retain `numpy==1.26.4`
(nv25.03 PyTorch compiled against NumPy 1.x) and add `setuptools<71`
(newer setuptools dropped `pkg_resources` needed by legacy `setup.py` in
git-sourced packages like MetricsReloaded and segment-anything)
- Remove `python_version <= '3.10'` caps from `cucim`, `onnxruntime`,
and `transformers` — these restrictions were keeping packages out of the
Python 3.12 image unnecessarily
- Install `papermill`, `jupytext`, `autopep8`, `autoflake`, and
`ipywidgets` directly in the Dockerfile so the tutorial runner is
self-contained

## Context

These changes were identified by running the full MONAI tutorial test
suite in a fresh Docker build against a MONAI 1.6 dev branch and
comparing results with a native conda reference run (Eric's run,
`eccefc57`). The rerun with stderr captured
(`runner_output_our_only.logs`) confirmed the specific error for each
notebook group.

## Type of change
- [x] Bug fix
- [ ] Feature
- [ ] Hotfix
- [ ] Spike / exploration
- [ ] Documentation
- [ ] Refactor

## Test plan
- [ ] Rebuild Docker image with `docker build -t monai_1_6:latest .`
- [ ] Re-run `bash run_our_only.sh 2>&1 | tee runner_output_v2.logs`
inside the container
- [ ] Verify mlflow notebooks pass (R1: 4 notebooks)
- [ ] Verify `hugging_face/hugging_face_pipeline_for_monai.ipynb` passes
(R3)
- [ ] Verify `experiment_management/spleen_segmentation_aim.ipynb`
passes (R6)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: R. Garcia-Dias <rafaelagd@gmail.com>
## Summary

- Fix division by zero in `SoftclDiceLoss` and `SoftDiceclDiceLoss` when
computing the harmonic mean of topology precision and sensitivity
- Add a small epsilon (`1e-7`) to the denominator `(tprec + tsens)` to
prevent `NaN` when both values are zero
- Add test cases for zero-input and non-overlapping edge cases with
`smooth=0`

## Details

The clDice loss computes `cl_dice = 1.0 - 2.0 * (tprec * tsens) / (tprec
+ tsens)`. When both `tprec` and `tsens` are zero (e.g., empty inputs,
non-overlapping predictions/targets, or `smooth=0`), this results in
`0/0 = NaN`, which propagates through the loss and crashes training.

While the default `smooth=1.0` prevents `tprec` and `tsens` from being
exactly zero in most cases, setting `smooth=0` (a valid configuration)
exposes this bug whenever skeleton overlap is zero. The fix adds `1e-7`
to the harmonic mean denominator, which:

- Has negligible impact on normal computation (tprec, tsens are bounded
in [0, 1])
- Returns `cl_dice = 1.0` (maximum loss) when both precision and
sensitivity are zero, which is the correct semantic result
- Is consistent with epsilon-based denominator guards used elsewhere in
MONAI (e.g., `smooth_dr` in `DiceLoss`)

## Test plan

- [x] Existing `test_cldice_loss.py` tests still pass (perfect overlap
cases)
- [x] New `test_zero_input_no_nan`: verifies zero-valued inputs with
`smooth=0` do not produce NaN
- [x] New `test_no_overlap_no_nan`: verifies non-overlapping
predictions/targets with `smooth=0` do not produce NaN
…-MONAI#8872)

## Summary

- `GlobalMutualInformationLoss` stored `preterm` and `bin_centers` as
plain tensor attributes when `kernel_type="gaussian"`, so calling
`loss.to("cuda")` or `loss.cuda()` did **not** move them to the target
device
- Replace the plain assignments with `register_buffer(...,
persistent=False)`, consistent with the pattern already applied to
`LocalNormalizedCrossCorrelationLoss` in Project-MONAI#8818
- The `.to(img)` calls in `parzen_windowing_gaussian` are retained for
dtype coercion (e.g. float16 inference)

## Test plan

- [x] `python -m pytest
tests/losses/image_dissimilarity/test_global_mutual_information_loss.py
-v` — all existing tests still pass
- [x]
`TestGlobalMutualInformationLossBuffers::test_gaussian_kernel_registers_buffers`
— `preterm` and `bin_centers` are in `_buffers` and have
`requires_grad=False`
- [x]
`TestGlobalMutualInformationLossBuffers::test_bspline_kernel_has_no_gaussian_buffers`
— b-spline mode is unaffected
- [x]
`TestGlobalMutualInformationLossBuffers::test_gaussian_kernel_forward_correct`
— forward pass returns a scalar loss

Closes Project-MONAI#8819

---------

Signed-off-by: Oleksandr Sanin <alexaaander.sanin@gmail.com>
Signed-off-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
### Description

Follow-up to Project-MONAI#8896. Test-only cleanup removing byte-identical duplicate
entries from parametrized case lists. No coverage is lost since each
removed entry has an identical sibling that remains.

Only genuine duplicates from the comment are removed.

### Changes

- `tests/transforms/test_border_pad.py`: repeated 6-element
`spatial_border` case
- `tests/transforms/test_border_padd.py`: `spatial_border=2` case
repeated twice
- `tests/transforms/test_spatial_padd.py`: repeated `method="end"` case
- `tests/transforms/test_center_spatial_crop.py`: repeated `roi_size=[2,
2, 2]` case
- `tests/networks/nets/test_autoencoderkl.py`: duplicate
`CASES_ATTENTION` entry
- `tests/networks/nets/test_spade_autoencoderkl.py`: duplicate
`CASES_ATTENTION` entry

### Types of changes
- [x] Non-breaking change (test-only cleanup)
- [x] All tests passing locally

---------

Signed-off-by: Soumya Snigdha Kundu <soumya_snigdha.kundu@kcl.ac.uk>
### Description

`batched_nms` is documented to accept an Nx4/Nx6 torch tensor or
ndarray, but it computed `boxes_for_nms = boxes + offsets[:, None]`
using the original `boxes` argument instead of the converted tensor
`boxes_t`. Since `offsets` is a torch tensor derived from `boxes_t`,
passing an ndarray added a numpy array to a torch tensor and raised
`TypeError`, breaking `batched_nms` for all ndarray inputs.

The offset is now added to the converted tensor: `boxes_for_nms =
boxes_t + offsets[:, None]`. Everything else downstream already operates
on `boxes_t`, and the result is converted back to the input type, so the
torch path is unchanged.

### Types of changes
- [x] Non-breaking change (fix or new feature that would not break
existing functionality).
- [x] New tests added to cover the changes.
- [ ] Integration tests passed locally by running `./runtests.sh -f -u
--net --coverage`.
- [ ] Quick tests passed locally by running `./runtests.sh --quick
--unittests --disttests`.
- [ ] In-line docstrings updated.

---------

Signed-off-by: Soumya Snigdha Kundu <soumya_snigdha.kundu@kcl.ac.uk>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
…roject-MONAI#8931) (Project-MONAI#8932)

Fixes Project-MONAI#8931

## Problem

12 `warnings.warn()` calls in `monai/metrics/` are missing
`stacklevel=2`. Without this parameter, warnings point to MONAI library
internals instead of the user's calling code, making them unhelpful for
debugging.

This follows the same pattern identified in `losses/` (PR Project-MONAI#8930) and is
a natural extension to the `metrics/` module.

## Solution

Added `stacklevel=2` to all 12 `warnings.warn()` calls across 6 files in
`monai/metrics/`:

| File | Warning | Line |
|------|---------|------|
| `cumulative_average.py` | non-finite inputs received | ~157 |
| `average_precision.py` | y values all same / invalid | ~91, ~96 |
| `utils.py` | ground truth/prediction all zero | ~342, ~348 |
| `utils.py` | binarized tensor | ~380 |
| `utils.py` | Voronoi CPU | ~515 |
| `active_learning_metrics.py` | spatial map / reduction | ~140, ~195 |
| `confusion_matrix.py` | compute_sample | ~96 |
| `rocauc.py` | y values all same / invalid | ~80, ~85 |

Note: `embedding_collapse.py` already had `stacklevel=3` (intentionally
different for its call depth) and was left unchanged.

## Verification

- All 6 modified files pass `ast.parse()` syntax check
- All 14 `warnings.warn()` calls in `monai/metrics/` confirmed to have
`stacklevel` parameter
- No other code changes — purely additive `stacklevel=2` parameter
additions

## Changelog

| Date | Change | Author |
|------|--------|--------|
| 2026-06-19 | Add missing stacklevel=2 to 12 warnings.warn() calls in
monai/metrics/ | rtmalikian |

### Files Changed
- `monai/metrics/cumulative_average.py` — Added stacklevel=2 to 1
warning
- `monai/metrics/average_precision.py` — Added stacklevel=2 to 2
warnings
- `monai/metrics/utils.py` — Added stacklevel=2 to 4 warnings
- `monai/metrics/active_learning_metrics.py` — Added stacklevel=2 to 2
warnings
- `monai/metrics/confusion_matrix.py` — Added stacklevel=2 to 1 warning
- `monai/metrics/rocauc.py` — Added stacklevel=2 to 2 warnings

### Verification
- All 6 files pass Python syntax check (ast.parse)
- All 14 warnings.warn() calls in monai/metrics/ confirmed to have
stacklevel parameter
- No functional behavior changes — only warning source location improves

---

**About the Author:** Raphael Malikian — Clinical AI Solutions
Architect. I specialise in building and fixing AI/ML systems for
healthcare, including vector databases, RAG pipelines, and clinical NLP.
If you need help with your project or think I can add value to your
organisation, feel free to reach out — I'd love to connect.

📧 rtmalikian@gmail.com
🔗 GitHub: https://github.com/rtmalikian
🔗 LinkedIn:
http://www.linkedin.com/in/raphael-t-malikian-mbbs-bsc-hons-71075436a

---

**Disclosure:** This code was developed with assistance from
**mimo-v2.5-pro** (Xiaomi) via **Hermes Agent** (Nous Research). All
changes were reviewed, tested against the actual codebase, and verified
for correctness.

---------

Signed-off-by: Raphael Malikian <rtmalikian@gmail.com>
Signed-off-by: rtmalikian <rtmalikian@gmail.com>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
…oject-MONAI#8929) (Project-MONAI#8930)

Fixes Project-MONAI#8929

## Problem

28 calls to `warnings.warn()` in `monai/losses/` are missing the
`stacklevel` parameter. Without `stacklevel=2`, warnings point to the
MONAI internal code instead of the user's calling code, making it
difficult for users to identify which part of their script triggered the
warning.

## Solution

Added `stacklevel=2` to all 28 `warnings.warn()` calls across 9 loss
modules:
- `dice.py` (7 instances)
- `tversky.py` (3 instances)
- `mcc_loss.py` (3 instances)
- `focal_loss.py` (3 instances)
- `hausdorff_loss.py` (3 instances)
- `unified_focal_loss.py` (3 instances)
- `spatial_mask.py` (3 instances)
- `perceptual.py` (2 instances)
- `adversarial_loss.py` (1 instance)

Also fixes a typo in `perceptual.py`: `"supp, ort"` → `"support"`
(carried from Project-MONAI#8924).

## Verification

```bash
# All 28 warnings.warn() calls now have stacklevel=2
$ grep -c "stacklevel" monai/losses/*.py
# Each file's stacklevel count matches its warnings.warn count

# All 9 files pass syntax check
$ python3 -c "import ast; [ast.parse(open(f).read()) for f in files]"
9 files checked, 0 errors
```

## Changelog

| Date | Change | Author |
|------|--------|--------|
| 2026-06-19 | Add missing stacklevel=2 to 28 warnings.warn() calls in 9
loss modules | rtmalikian |

### Files Changed
- `monai/losses/dice.py` — 7 warnings.warn() calls updated
- `monai/losses/tversky.py` — 3 calls updated
- `monai/losses/mcc_loss.py` — 3 calls updated
- `monai/losses/focal_loss.py` — 3 calls updated
- `monai/losses/hausdorff_loss.py` — 3 calls updated
- `monai/losses/unified_focal_loss.py` — 3 calls updated
- `monai/losses/spatial_mask.py` — 3 calls updated
- `monai/losses/perceptual.py` — 2 calls updated + typo fix
- `monai/losses/adversarial_loss.py` — 1 call updated

### Verification
- All 28 warnings.warn() calls now include stacklevel=2
- All 9 modified files pass Python syntax validation
- No duplicate stacklevel parameters

---

**About the Author:** Raphael Malikian — Clinical AI Solutions
Architect. I specialise in building and fixing AI/ML systems for
healthcare, including vector databases, RAG pipelines, and clinical NLP.
If you need help with your project or think I can add value to your
organisation, feel free to reach out — I'd love to connect.

📧 rtmalikian@gmail.com
🔗 GitHub: https://github.com/rtmalikian
🔗 LinkedIn:
http://www.linkedin.com/in/raphael-t-malikian-mbbs-bsc-hons-71075436a

---

**Disclosure:** This code was developed with assistance from
**MiMo-v2.5-Pro** (Xiaomi) via **Hermes Agent** (Nous Research). All
changes were reviewed, tested against the actual codebase, and verified
for correctness.

---------

Signed-off-by: Raphael Malikian <rtmalikian@gmail.com>
Signed-off-by: rtmalikian <rtmalikian@gmail.com>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
…apping dict (Project-MONAI#8907)

**fix: adaptor map_names calls dict as function when inputs is a
name-mapping dict**

When `adaptor` wraps a function with `**kwargs` and `inputs` is a dict,
the `map_names` helper calls `input_map(k, k)` instead of
`input_map.get(k, k)`, raising `TypeError` before any data reaches the
wrapped function. The fix uses `input_map.get(k, k)` so the dict is
looked up rather than called, falling back to the original key when no
mapping exists.

### Types of changes
- [x] Non-breaking change (fix or new feature that would not break
existing functionality).
- [x] New tests added to cover the changes.
- [ ] Integration tests passed locally by running `./runtests.sh -f -u
--net --coverage`.
- [ ] Quick tests passed locally by running `./runtests.sh --quick
--unittests --disttests`.
- [ ] In-line docstrings updated.

---------

Signed-off-by: Soumya Snigdha Kundu <soumya_snigdha.kundu@kcl.ac.uk>
Addresses
[GHSA-636w-j999-g7x5](GHSA-636w-j999-g7x5).

### Description

This modifies the `PersistentDataset` class to permit storing
`MetaTensor` objects. This is done by relying on the `torch.load`
functionality to load only safe object types and those white-listed with
`torch.serialization.add_safe_globals`. This also uses sha256 hashing in
place of md5 in case of security concerns.

### Types of changes
<!--- Put an `x` in all the boxes that apply, and remove the not
applicable items -->
- [x] Non-breaking change (fix or new feature that would not break
existing functionality).
- [ ] Breaking change (fix or new feature that would cause existing
functionality to change).
- [x] New tests added to cover the changes.
- [ ] Integration tests passed locally by running `./runtests.sh -f -u
--net --coverage`.
- [ ] Quick tests passed locally by running `./runtests.sh --quick
--unittests --disttests`.
- [x] In-line docstrings updated.
- [ ] Documentation updated, tested `make html` command in the `docs/`
folder.

---------

Signed-off-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
…roject-MONAI#8918)

Fixes Project-MONAI#5939.

### Summary

`BendingEnergyLoss` previously computed second-order derivatives by
applying the central first-order helper `spatial_gradient` twice, which
yields a wide `[1, 0, -2, 0, 1] / 4` stencil for pure second derivatives
that spans four voxels per axis. That stencil is less accurate than the
standard compact one and forced the validation "all spatial dims > 4".

This PR replaces the second-order computation with compact central
stencils evaluated directly on `pred`:

- **Pure** ``d^2/dx_i^2``: ``x[i+1] - 2 * x[i] + x[i-1]`` (the standard
`[1, -2, 1]` kernel).
- **Mixed** ``d^2/(dx_i dx_j)``: ``(x[i+1,j+1] - x[i+1,j-1] - x[i-1,j+1]
+ x[i-1,j-1]) / 4`` (compact 4-point central scheme).

Both span three voxels per axis, so the spatial-size validation is
relaxed from `> 4` to `> 2`, matching `DiffusionLoss`. The public API
(`__init__(normalize, reduction)`, `forward(pred)`) and `normalize`
semantics are unchanged. The existing `spatial_gradient` helper is left
untouched because `DiffusionLoss` still uses it.

### Why TEST_CASES expected values do not change

For ``f(x) = x^2``, the analytical second derivative is the constant
`2`. Both the previous central-of-central stencil ``(f[i+2] - 2*f[i] +
f[i-2]) / 4`` and the new compact ``[1, -2, 1]`` stencil ``f[i+1] -
2*f[i] + f[i-1]`` are exact for quadratics, so both return `2` at every
interior voxel. Mixed-partial test inputs are constant in at least one
of the two axes, so both stencils return `0` for mixed terms on these
cases. Squared and reduced by ``mean``, the existing `TEST_CASES`
expected values (``0.0``, ``4.0``, ``100.0``) are therefore invariant
under this change.

What does change in the tests:

- `test_ill_shape` is updated to trigger on shape `2` (was `4`) so it
still exercises the spatial-size guard.
- A new `TEST_CASES` row covers shape `(1, 3, 3, 3, 3)` of ones
(previously rejected by the `> 4` guard) → expected `0.0`, validating
the relaxed guard.

Reference for the compact mixed-partial scheme: Pavel Holoborodko's
finite-difference notes cited in the original issue.

---------

Signed-off-by: Vishnu Kannaujia <vishnu.kannaujia@gmail.com>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
…files (Project-MONAI#8919)

Fixes Project-MONAI#5461.

### Summary

WSI reader tests emit `ResourceWarning: unclosed file <_io.FileIO ...>`
/ `BufferedReader` for the temp TIFF inputs they exercise (e.g. the
CMU-1 generic TIFF). Investigation:

- Every direct `reader.read(...)` call site in
``tests/utils/enums/test_wsireader.py`` already either uses ``with
reader.read(...) as obj:`` or explicitly calls ``obj.close()`` on the
returned WSI object. Those sites are not the leak.
- The remaining leak comes from ``LoadImage.__call__`` in
``monai/transforms/io/array.py`` (around L256–289), which does:
  ```python
  img = reader.read(filename)
  img_array, meta_data = reader.get_data(img)
  # ... img_array is wrapped into MetaTensor and returned
  # the reader-returned `img` is never closed
  ```
The two ``test_with_dataloader*`` tests in this module use
``LoadImaged(reader=WSIReader, backend=..., ...)`` and inherit that
leak. The temp TIFF handles only get closed when the garbage collector
eventually runs, frequently after Python has already emitted the
warning.

This PR keeps the fix at test-hygiene scope: add ``gc.collect()`` to
``tearDown`` of the shared ``WSIReaderTests.Tests`` base class. Each of
``TiffFile.__del__`` / ``OpenSlide.__del__`` / ``CuImage.__del__``
closes the underlying file descriptor, so running gc explicitly at the
end of every test invokes those finalizers deterministically and
eliminates the warning.

### Why not change ``LoadImage`` / ``BaseWSIReader``

A reader-level or ``LoadImage``-level fix is feasible (e.g. closing
``img`` after ``get_data`` returns) but is broader in scope, affects all
readers, and would need to land alongside changes to the public contract
of ``BaseWSIReader.read`` (currently documented to return an open WSI
object). Happy to follow up with that if a maintainer prefers; this PR
was scoped narrowly to the test symptom that the issue raises.

### Verify

```bash
python -m pytest tests/utils/enums/test_wsireader.py -W error::ResourceWarning -v
```
Expected: tests pass and no ``ResourceWarning`` escalations.

---------

Signed-off-by: Vishnu Kannaujia <vishnu.kannaujia@gmail.com>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
…ce volumes (Fixes Project-MONAI#8925) (Project-MONAI#8926)

Fixes Project-MONAI#8925

## Problem

In `DICOMReader._get_affine`, when processing single-slice 3D DICOM
segmentation volumes (where `n == 1`), the code computes:

```python
k1, k2, k3 = (t1n - sx) / (n - 1), (t2n - sy) / (n - 1), (t3n - sz) / (n - 1)
```

Since `n - 1 = 0`, this raises a `ZeroDivisionError`. The issue occurs
in the segmentation code path (`_get_seg_data`, line 898) where
`lastImagePositionPatient` is always set from the frame metadata
regardless of the number of frames. For a single-frame segmentation, the
first and last positions are identical, producing `0 / 0`.

## Solution

Added an `n > 1` guard before computing the z-axis direction vector from
`lastImagePositionPatient`. For single-slice volumes, the z-axis column
of the affine remains as the identity `[0, 0, 1, 0]` from `np.eye(4)`,
which is a correct default — there is no meaningful z-direction for a
single slice.

## Verification

```python
import numpy as np

# Single-slice scenario (n=1) — previously caused ZeroDivisionError
n = 1
sx, sy, sz = 0.0, 0.0, 0.0
t1n, t2n, t3n = 0.0, 0.0, 0.0

affine = np.eye(4)
if n > 1:
    affine[0, 2] = (t1n - sx) / (n - 1)
    affine[1, 2] = (t2n - sy) / (n - 1)
    affine[2, 2] = (t3n - sz) / (n - 1)

print(f'z-axis column: {affine[:, 2]}')  # [0, 0, 1, 0] — identity ✓

# Normal multi-slice case (n=10) — still works correctly
n = 10
t1n, t2n, t3n = 0.0, 0.0, 45.0
affine2 = np.eye(4)
if n > 1:
    affine2[0, 2] = (t1n - sx) / (n - 1)
    affine2[1, 2] = (t2n - sy) / (n - 1)
    affine2[2, 2] = (t3n - sz) / (n - 1)

print(f'z-axis column: {affine2[:, 2]}')  # [0, 0, 5.0, 0] — correct direction ✓
```

---

**About the Author:** Raphael Malikian — Clinical AI Solutions
Architect. I specialise in building and fixing AI/ML systems for
healthcare, including vector databases, RAG pipelines, and clinical NLP.
If you need help with your project or think I can add value to your
organisation, feel free to reach out — I'd love to connect.

📧 rtmalikian@gmail.com
🔗 GitHub: https://github.com/rtmalikian
🔗 LinkedIn:
http://www.linkedin.com/in/raphael-t-malikian-mbbs-bsc-hons-71075436a

---

**Disclosure:** This code was developed with assistance from
**mimo-2.5-pro** (Xiaomi) via **Hermes Agent** (Nous Research). All
changes were reviewed, tested against the actual codebase, and verified
for correctness.


## Changelog

| Date | Change | Author |
|------|--------|--------|
| 2026-06-18 | Initial fix: guard division by zero for single-slice
DICOM volumes | rtmalikian |
| 2026-06-18 | Added DCO sign-off to commit | rtmalikian |
| 2026-06-18 | Updated PR documentation with changelog | rtmalikian |

### Files Changed
- `monai/data/image_reader.py` — Added `n > 1` guard before computing
affine offsets for multi-slice volumes in `DICOMReader._get_affine()`

### Verification
- ✅ Single-slice 3D DICOM volumes no longer trigger ZeroDivisionError
- ✅ Multi-slice volumes continue to compute affine correctly
- ✅ DCO sign-off present on all commits

Signed-off-by: Raphael Malikian <rtmalikian@gmail.com>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
…ort_format (Fixes Project-MONAI#8927) (Project-MONAI#8928)

Fixes Project-MONAI#8927

## Problem

In `monai/auto3dseg/utils.py` line 287, the code uses `raise
UserWarning("list length in report_format is not 1")`. This raises
`UserWarning` as an exception, which crashes the program. Since
`UserWarning` inherits from `Warning → Exception`, the `raise` works but
terminates execution.

The function `verify_report_format` returns `bool` to indicate format
validity — a warning is appropriate here, not a fatal exception. The
`warnings` module is already imported in the file.

## Solution

Replace `raise UserWarning(...)` with `warnings.warn(...,
stacklevel=2)`:

```python
# Before (crashes):
raise UserWarning("list length in report_format is not 1")

# After (warns):
warnings.warn("list length in report_format is not 1", stacklevel=2)
```

## Verification

Confirmed that:
- `raise UserWarning(...)` crashes the program (raises as exception)
- `warnings.warn(...)` correctly emits a `UserWarning` without crashing
- The file passes syntax validation
- `warnings` is already imported in the file

---

**About the Author:** Raphael Malikian — Clinical AI Solutions
Architect. I specialise in building and fixing AI/ML systems for
healthcare, including vector databases, RAG pipelines, and clinical NLP.
If you need help with your project or think I can add value to your
organisation, feel free to reach out — I'd love to connect.

📧 rtmalikian@gmail.com
🔗 GitHub: https://github.com/rtmalikian
🔗 LinkedIn:
http://www.linkedin.com/in/raphael-t-malikian-mbbs-bsc-hons-71075436a

---

**Disclosure:** This code was developed with assistance from
**mimo-2.5-pro** (Xiaomi) via **Hermes Agent** (Nous Research). All
changes were reviewed, tested against the actual codebase, and verified
for correctness.


## Changelog

| Date | Change | Author |
|------|--------|--------|
| 2026-06-18 | Initial fix: replace raise UserWarning with
warnings.warn() | rtmalikian |
| 2026-06-18 | Added DCO sign-off to commit | rtmalikian |
| 2026-06-18 | Updated PR documentation with changelog | rtmalikian |

### Files Changed
- `monai/auto3dseg/utils.py` — Changed `raise UserWarning(...)` to
`warnings.warn(...)` in `verify_report_format()`

### Verification
- ✅ Function no longer crashes on invalid report format
- ✅ Warning is emitted instead of raising exception
- ✅ Return value (bool) still indicates format validity
- ✅ DCO sign-off present on all commits

Signed-off-by: Raphael Malikian <rtmalikian@gmail.com>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
…MONAI#8951)

### Description

`compute_fp_tp_probs_nd` computed `num_targets = max_label -
len(labels_to_exclude)`, which only holds when every excluded label is a
distinct value present in `[1, max_label]`. An absent, out-of-range, or
duplicated entry subtracts targets that were never counted, leaving
`num_targets` too small. Since `compute_froc_curve_data` divides
cumulative true positives by `num_targets`, this inflates the reported
sensitivity.

The count is now the labels in `[1, max_label]` that are not excluded,
computed in the existing loop. A regression test covering an
out-of-range and a duplicated exclusion is included; both undercount
before the fix.

### Types of changes
- [x] Non-breaking change (fix or new feature that would not break
existing functionality).
- [x] New tests added to cover the changes.
- [ ] Integration tests passed locally by running `./runtests.sh -f -u
--net --coverage`.
- [ ] Quick tests passed locally by running `./runtests.sh --quick
--unittests --disttests`.
- [ ] In-line docstrings updated.

---------

Signed-off-by: Soumya Snigdha Kundu <soumya_snigdha.kundu@kcl.ac.uk>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
### Description

Ran a code agent for dead code. Vetted them myself thereafter. 

Removes dead statements, no-ops, and leftover commented-out code. No
runtime behavior changes.

| File | Dead/redundant code removed |
|---|---|
| `networks/nets/basic_unet.py` | Stray `print(f"BasicUNet features:
...")` debug call in constructor |
| `networks/nets/basic_unetplusplus.py` | Stray
`print(f"BasicUNetPlusPlus features: ...")` debug call in constructor |
| `networks/blocks/text_embedding.py` | Stray
`print(self.text_embedding)` debug call in `TextEncoder.forward` |
| `metrics/generalized_dice.py` | No-op self-assignment `y_pred_o =
y_pred_o` |
| `networks/layers/simplelayers.py` | No-op self-assignment `filter =
filter` in `MeanFilter` |
| `losses/nacl_loss.py` | Redundant `.abs_()` after `.pow_(2)` (operand
already non-negative) in L2 branch |
| `losses/image_dissimilarity.py` | Overwrite discarding the
`look_up_option`-validated `kernel_type` in
`GlobalMutualInformationLoss` |
| `data/ultrasound_confidence_map.py` | Dead `elif` branch with
discarded bare `s.shape[0]` expression |
| `inferers/merger.py` | Duplicated recomputation of `is_zarr_v3` in
`ZarrAvgMerger` |
| `utils/profiling.py` | Unused module-level `pandas` optional-import
(only consumer re-imports locally) |
| `apps/nnunet/utils.py` | Three blocks of commented-out code in
`create_new_dataset_json` |
| `apps/vista3d/transforms.py` | Commented-out `AsDiscrete` alternative
|
| `transforms/utils.py` | Commented-out `torch.zeros` alternative |
| `networks/layers/filtering.py` | Unreachable commented-out body after
`raise` in `PHLFilter.backward` |

### Types of changes
- [x] Non-breaking change (fix or new feature that would not break
existing functionality).

---------

Signed-off-by: Soumya Snigdha Kundu <soumya_snigdha.kundu@kcl.ac.uk>
Fixes Project-MONAI#6119 .

### Description

`docs/source/installation.md` only documents the POSIX inline form
`BUILD_MONAI=1 pip install ...` for building the MONAI C++/CUDA
extensions. This `VAR=value command` syntax is not supported by Windows
`cmd.exe` or PowerShell, so the documented commands fail out of the box
on Windows.

This adds short cmd.exe and PowerShell snippets to both install flows
(Option 1 system-wide and Option 2 editable): set the environment
variable first, then run the existing `pip install` command. The `set
BUILD_MONAI=1` form is the one confirmed working on Windows 11 in the
issue thread.

### Types of changes
- [x] Non-breaking change (documentation only).
- [x] Documentation updated.

### How tested
- Verified the new `bat`/`powershell` fenced blocks use valid Pygments
lexers and lex without error tokens, so the strict docs build
(`build_docs.yml`) emits no new warnings.
- pre-commit markdown hooks (end-of-file, trailing-whitespace,
mixed-line-ending) pass on the changed file.

Signed-off-by: Lanre Shittu <136805224+Shizoqua@users.noreply.github.com>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
…metric computation (Project-MONAI#8910)

Fixes # 8909.
Project-MONAI#8909

### Description

Pretty straightforward: we don't need to compute the distance between
every conceivable voxel, just the edges, so we can use a KDTree on CPU
and compute `HausdorffDistanceMetric` and `SurfaceDistanceMetric` etc
significantly faster.

GPU implementations of KDTrees exist, but I did a little benchmarking
and found that they are slower than the full EDT since the distance
computations are embarrassingly parallel and well-suited to the hardware
(gpu goes brrr), so I left that path unchanged.

Measured speedups (on my M3 mac, and Intel Cascade Lake) range from 1.5x
for small inputs to 16x for larger volumes and noisier data.

I think existing test coverage is good enough that we don't need more
here - all pass for me, and I've spot checked a few problems to ensure
identical output metrics. Edit: have added some more tests per the
coderabbit's suggestions.

### Types of changes
<!--- Put an `x` in all the boxes that apply, and remove the not
applicable items -->
- [x] Non-breaking change (fix or new feature that would not break
existing functionality).
- [ ] Breaking change (fix or new feature that would cause existing
functionality to change).
- [ ] New tests added to cover the changes.
- [x] Integration tests passed locally by running `./runtests.sh -f -u
--net --coverage`.
- [x] Quick tests passed locally by running `./runtests.sh --quick
--unittests --disttests`.
- [x] In-line docstrings updated.
- [ ] Documentation updated, tested `make html` command in the `docs/`
folder.

---------

Signed-off-by: J Berg <j.berg2349@gmail.com>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
…#8941) (Project-MONAI#8944)

### Description

`nnUNetV2Runner.train_single_model_command` builds the `nnUNetv2_train`
argv by iterating `kwargs` and always appending `str(_value)`, so
documented `store_true` flags were emitted with a value instead of bare.
Passing `c=True` produced `--c True`, `val=True` produced `--val True`,
and likewise for `use_compressed` and `disable_checkpointing`.
`nnUNetv2_train` declares these as `store_true`, so the trailing `True`
is parsed as a positional argument and the command fails. A falsy
`pretrained_weights` was similarly emitted as `-pretrained_weights
False` instead of being omitted.

The builder now appends `store_true` flags only when their value is
truthy and skips them otherwise, and includes `pretrained_weights`/`-p`
only when given a real path. Regular value kwargs and the existing
`--npz` handling are unchanged.

Fixes Project-MONAI#8941, originally flagged in a review thread on Project-MONAI#8887.

### Types of changes
- [x] Non-breaking change (fix or new feature that would not break
existing functionality).
- [x] New tests added to cover the changes.
- [ ] Integration tests passed locally by running `./runtests.sh -f -u
--net --coverage`.
- [ ] Quick tests passed locally by running `./runtests.sh --quick
--unittests --disttests`.
- [ ] In-line docstrings updated.

---------

Signed-off-by: Soumya Snigdha Kundu <soumya_snigdha.kundu@kcl.ac.uk>
…roject-MONAI#8968)

Fixes Project-MONAI#8237 .

### Description
The runner passed boolean flags like `--c` through as `--c True`, but
nnU-Net treats these as `store_true` flags that take no value, so it
errored out with `unrecognized arguments: True`. Now we emit just the
bare flag when it's set, drop it when it isn't, and leave the other args
alone.

### Types of changes
- [x] Non-breaking change (fix or new feature that would not break
existing functionality).

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved how command-line options are passed for training and
validation, so boolean settings now behave as expected.
* Validation now runs through the standard training workflow with
validation enabled, helping ensure more consistent results.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Soumya Snigdha Kundu <soumya_snigdha.kundu@kcl.ac.uk>
Signed-off-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
)

Fixes Project-MONAI#6029 .

### Description

`create_rotate` hard-coded 3D rotations to the intrinsic `Rx @ Ry @ Rz`
composition. This adds a `rotate_order` parameter following the
convention of `scipy.spatial.transform.Rotation.from_euler`: a string of
up to three axes from `{x, y, z}`, where lower case selects extrinsic
rotations (about the fixed world axes) and upper case selects intrinsic
rotations (about the moving body axes). The default `"XYZ"` reproduces
the previous behaviour exactly, so existing pipelines are unaffected.

The name avoids collision with the spline interpolation order already
selected via `mode`. The parameter is threaded through
`functional.rotate`, `Rotate`, `RandRotate`, `AffineGrid`,
`RandAffineGrid`, `Affine`, `RandAffine` and their dictionary variants.
Invalid sequences raise `ValueError`, and 2D inputs ignore it.

A new test module checks that the default matches the legacy matrix,
that every supported axis sequence matches scipy for both the numpy and
torch backends, that invalid sequences raise, that 2D inputs ignore the
order, and that the `Rotate` transform honours it while remaining
invertible.

### Types of changes
- [x] Non-breaking change (fix or new feature that would not break
existing functionality).
- [x] New tests added to cover the changes.
- [x] In-line docstrings updated.

---------

Signed-off-by: Soumya Snigdha Kundu <soumya_snigdha.kundu@kcl.ac.uk>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to
7.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/releases">actions/checkout's
releases</a>.</em></p>
<blockquote>
<h2>v7.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>block checking out fork pr for pull_request_target and workflow_run
by <a href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2454">actions/checkout#2454</a></li>
<li>Bump actions/publish-immutable-action from 0.0.3 to 0.0.4 in the
minor-actions-dependencies group across 1 directory by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2458">actions/checkout#2458</a></li>
<li>Bump flatted from 3.3.1 to 3.4.2 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2460">actions/checkout#2460</a></li>
<li>Bump js-yaml from 4.1.0 to 4.2.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2461">actions/checkout#2461</a></li>
<li>Bump <code>@​actions/core</code> and
<code>@​actions/tool-cache</code> and Remove uuid by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2459">actions/checkout#2459</a></li>
<li>upgrade module to esm and update dependencies by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2463">actions/checkout#2463</a></li>
<li>Bump the minor-npm-dependencies group across 1 directory with 3
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2462">actions/checkout#2462</a></li>
<li>getting ready for checkout v7 release by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2464">actions/checkout#2464</a></li>
<li>update error wording by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2467">actions/checkout#2467</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/2454">actions/checkout#2454</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v6.0.3...v7.0.0">https://github.com/actions/checkout/compare/v6.0.3...v7.0.0</a></p>
<h2>v6.0.3</h2>
<h2>What's Changed</h2>
<ul>
<li>Update changelog by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2357">actions/checkout#2357</a></li>
<li>fix: expand merge commit SHA regex and add SHA-256 test cases by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2414">actions/checkout#2414</a></li>
<li>Fix checkout init for SHA-256 repositories by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2439">actions/checkout#2439</a></li>
<li>Update changelog for v6.0.3 by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2446">actions/checkout#2446</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/yaananth"><code>@​yaananth</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/2414">actions/checkout#2414</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v6...v6.0.3">https://github.com/actions/checkout/compare/v6...v6.0.3</a></p>
<h2>v6.0.2</h2>
<h2>What's Changed</h2>
<ul>
<li>Add orchestration_id to git user-agent when ACTIONS_ORCHESTRATION_ID
is set by <a
href="https://github.com/TingluoHuang"><code>@​TingluoHuang</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2355">actions/checkout#2355</a></li>
<li>Fix tag handling: preserve annotations and explicit fetch-tags by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2356">actions/checkout#2356</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v6.0.1...v6.0.2">https://github.com/actions/checkout/compare/v6.0.1...v6.0.2</a></p>
<h2>v6.0.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Update all references from v5 and v4 to v6 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2314">actions/checkout#2314</a></li>
<li>Add worktree support for persist-credentials includeIf by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2327">actions/checkout#2327</a></li>
<li>Clarify v6 README by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2328">actions/checkout#2328</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v6...v6.0.1">https://github.com/actions/checkout/compare/v6...v6.0.1</a></p>
<h2>v6.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update README to include Node.js 24 support details and requirements
by <a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2248">actions/checkout#2248</a></li>
<li>Persist creds to a separate file by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2286">actions/checkout#2286</a></li>
<li>v6-beta by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2298">actions/checkout#2298</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/blob/main/CHANGELOG.md">actions/checkout's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h2>v7.0.0</h2>
<ul>
<li>Block checking out fork PR for pull_request_target and workflow_run
by <a href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2454">actions/checkout#2454</a></li>
<li>Bump actions/publish-immutable-action from 0.0.3 to 0.0.4 in the
minor-actions-dependencies group across 1 directory by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2458">actions/checkout#2458</a></li>
<li>Bump flatted from 3.3.1 to 3.4.2 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2460">actions/checkout#2460</a></li>
<li>Bump js-yaml from 4.1.0 to 4.2.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2461">actions/checkout#2461</a></li>
<li>Bump <code>@​actions/core</code> and
<code>@​actions/tool-cache</code> and Remove uuid by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2459">actions/checkout#2459</a></li>
<li>upgrade module to esm and update dependencies by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2463">actions/checkout#2463</a></li>
<li>Bump the minor-npm-dependencies group across 1 directory with 3
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2462">actions/checkout#2462</a></li>
</ul>
<h2>v6.0.3</h2>
<ul>
<li>Fix checkout init for SHA-256 repositories by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2439">actions/checkout#2439</a></li>
<li>fix: expand merge commit SHA regex and add SHA-256 test cases by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2414">actions/checkout#2414</a></li>
</ul>
<h2>v6.0.2</h2>
<ul>
<li>Fix tag handling: preserve annotations and explicit fetch-tags by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2356">actions/checkout#2356</a></li>
</ul>
<h2>v6.0.1</h2>
<ul>
<li>Add worktree support for persist-credentials includeIf by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2327">actions/checkout#2327</a></li>
</ul>
<h2>v6.0.0</h2>
<ul>
<li>Persist creds to a separate file by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2286">actions/checkout#2286</a></li>
<li>Update README to include Node.js 24 support details and requirements
by <a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2248">actions/checkout#2248</a></li>
</ul>
<h2>v5.0.1</h2>
<ul>
<li>Port v6 cleanup to v5 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2301">actions/checkout#2301</a></li>
</ul>
<h2>v5.0.0</h2>
<ul>
<li>Update actions checkout to use node 24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2226">actions/checkout#2226</a></li>
</ul>
<h2>v4.3.1</h2>
<ul>
<li>Port v6 cleanup to v4 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2305">actions/checkout#2305</a></li>
</ul>
<h2>v4.3.0</h2>
<ul>
<li>docs: update README.md by <a
href="https://github.com/motss"><code>@​motss</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li>
<li>Add internal repos for checking out multiple repositories by <a
href="https://github.com/mouismail"><code>@​mouismail</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li>
<li>Documentation update - add recommended permissions to Readme by <a
href="https://github.com/benwells"><code>@​benwells</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li>
<li>Adjust positioning of user email note and permissions heading by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2044">actions/checkout#2044</a></li>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2194">actions/checkout#2194</a></li>
<li>Update CODEOWNERS for actions by <a
href="https://github.com/TingluoHuang"><code>@​TingluoHuang</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2224">actions/checkout#2224</a></li>
<li>Update package dependencies by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2236">actions/checkout#2236</a></li>
</ul>
<h2>v4.2.2</h2>
<ul>
<li><code>url-helper.ts</code> now leverages well-known environment
variables by <a href="https://github.com/jww3"><code>@​jww3</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/1941">actions/checkout#1941</a></li>
<li>Expand unit test coverage for <code>isGhes</code> by <a
href="https://github.com/jww3"><code>@​jww3</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1946">actions/checkout#1946</a></li>
</ul>
<h2>v4.2.1</h2>
<ul>
<li>Check out other refs/* by commit if provided, fall back to ref by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1924">actions/checkout#1924</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/checkout/commit/9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0"><code>9c091bb</code></a>
update error wording (<a
href="https://redirect.github.com/actions/checkout/issues/2467">#2467</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/1044a6dea927916f2c38ba5aeffbc0a847b1221a"><code>1044a6d</code></a>
getting ready for checkout v7 release (<a
href="https://redirect.github.com/actions/checkout/issues/2464">#2464</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/f0282184c7ce73ab54c7e4ab5a617122602e575f"><code>f028218</code></a>
Bump the minor-npm-dependencies group across 1 directory with 3 updates
(<a
href="https://redirect.github.com/actions/checkout/issues/2462">#2462</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/d914b262ffc244530a203ab40decab34c3abf34d"><code>d914b26</code></a>
upgrade module to esm and update dependencies (<a
href="https://redirect.github.com/actions/checkout/issues/2463">#2463</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/537c7ef99cef6e5ddb5e7ff5d16d14510503801d"><code>537c7ef</code></a>
Bump <code>@​actions/core</code> and <code>@​actions/tool-cache</code>
and Remove uuid (<a
href="https://redirect.github.com/actions/checkout/issues/2459">#2459</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/130a169078a413d3a5246a393625e8e742f387f6"><code>130a169</code></a>
Bump js-yaml from 4.1.0 to 4.2.0 (<a
href="https://redirect.github.com/actions/checkout/issues/2461">#2461</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/7d09575332117a40b46e5e020664df234cd416f3"><code>7d09575</code></a>
Bump flatted from 3.3.1 to 3.4.2 (<a
href="https://redirect.github.com/actions/checkout/issues/2460">#2460</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/0f9f3aa320cb53abeb534aeb54048075d9697a0e"><code>0f9f3aa</code></a>
Bump actions/publish-immutable-action (<a
href="https://redirect.github.com/actions/checkout/issues/2458">#2458</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/f9e715a95fcd1f9253f77dd28f11e88d2d6460c7"><code>f9e715a</code></a>
block checking out fork pr for pull_request_target and workflow_run (<a
href="https://redirect.github.com/actions/checkout/issues/2454">#2454</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/df4cb1c069e1874edd31b4311f1884172cec0e10"><code>df4cb1c</code></a>
Update changelog for v6.0.3 (<a
href="https://redirect.github.com/actions/checkout/issues/2446">#2446</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/checkout/compare/v4...v7">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=4&new-version=7)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
Bumps
[codecov/codecov-action](https://github.com/codecov/codecov-action) from
6 to 7.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/codecov/codecov-action/releases">codecov/codecov-action's
releases</a>.</em></p>
<blockquote>
<h2>v7.0.0</h2>
<p>⚠️ Due to migration issues with keybase, we are unable to update our
keys under the <code>codecovsecurity</code> account. We have deleted the
account and are using <code>codecovsecops</code> with the original gpg
key</p>
<h2>What's Changed</h2>
<ul>
<li>ci: remove Enforce License Compliance workflow by <a
href="https://github.com/thomasrockhu-codecov"><code>@​thomasrockhu-codecov</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1950">codecov/codecov-action#1950</a></li>
<li>chore(release): 7.0.0 by <a
href="https://github.com/thomasrockhu-codecov"><code>@​thomasrockhu-codecov</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1957">codecov/codecov-action#1957</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/codecov/codecov-action/compare/v6.0.1...v7.0.0">https://github.com/codecov/codecov-action/compare/v6.0.1...v7.0.0</a></p>
<h2>v6.0.2</h2>
<p>This is a copy of the <code>v7.0.0</code> release to make updates
easier</p>
<h2>What's Changed</h2>
<ul>
<li>ci: remove Enforce License Compliance workflow by <a
href="https://github.com/thomasrockhu-codecov"><code>@​thomasrockhu-codecov</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1950">codecov/codecov-action#1950</a></li>
<li>chore(release): 7.0.0 by <a
href="https://github.com/thomasrockhu-codecov"><code>@​thomasrockhu-codecov</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1957">codecov/codecov-action#1957</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/codecov/codecov-action/compare/v6.0.1...v6.0.2">https://github.com/codecov/codecov-action/compare/v6.0.1...v6.0.2</a></p>
<h2>v6.0.1</h2>
<h2>What's Changed</h2>
<ul>
<li>fix: prevent template injection in run: steps (VULN-1652) by <a
href="https://github.com/thomasrockhu-codecov"><code>@​thomasrockhu-codecov</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1947">codecov/codecov-action#1947</a></li>
<li>chore(release): 6.0.1 by <a
href="https://github.com/thomasrockhu-codecov"><code>@​thomasrockhu-codecov</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1949">codecov/codecov-action#1949</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/codecov/codecov-action/compare/v6.0.0...v6.0.1">https://github.com/codecov/codecov-action/compare/v6.0.0...v6.0.1</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md">codecov/codecov-action's
changelog</a>.</em></p>
<blockquote>
<h2>v5.5.2</h2>
<h3>What's Changed</h3>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/codecov/codecov-action/compare/v5.5.1..v5.5.2">https://github.com/codecov/codecov-action/compare/v5.5.1..v5.5.2</a></p>
<h2>v5.5.1</h2>
<h3>What's Changed</h3>
<ul>
<li>fix: overwrite pr number on fork by <a
href="https://github.com/thomasrockhu-codecov"><code>@​thomasrockhu-codecov</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1871">codecov/codecov-action#1871</a></li>
<li>build(deps): bump actions/checkout from 4.2.2 to 5.0.0 by
<code>@​app/dependabot</code> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1868">codecov/codecov-action#1868</a></li>
<li>build(deps): bump github/codeql-action from 3.29.9 to 3.29.11 by
<code>@​app/dependabot</code> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1867">codecov/codecov-action#1867</a></li>
<li>fix: update to use local app/ dir by <a
href="https://github.com/thomasrockhu-codecov"><code>@​thomasrockhu-codecov</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1872">codecov/codecov-action#1872</a></li>
<li>docs: fix typo in README by <a
href="https://github.com/datalater"><code>@​datalater</code></a> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1866">codecov/codecov-action#1866</a></li>
<li>Document a <code>codecov-cli</code> version reference example by <a
href="https://github.com/webknjaz"><code>@​webknjaz</code></a> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1774">codecov/codecov-action#1774</a></li>
<li>build(deps): bump github/codeql-action from 3.28.18 to 3.29.9 by
<code>@​app/dependabot</code> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1861">codecov/codecov-action#1861</a></li>
<li>build(deps): bump ossf/scorecard-action from 2.4.1 to 2.4.2 by
<code>@​app/dependabot</code> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1833">codecov/codecov-action#1833</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/codecov/codecov-action/compare/v5.5.0..v5.5.1">https://github.com/codecov/codecov-action/compare/v5.5.0..v5.5.1</a></p>
<h2>v5.5.0</h2>
<h3>What's Changed</h3>
<ul>
<li>feat: upgrade wrapper to 0.2.4 by <a
href="https://github.com/jviall"><code>@​jviall</code></a> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1864">codecov/codecov-action#1864</a></li>
<li>Pin actions/github-script by Git SHA by <a
href="https://github.com/martincostello"><code>@​martincostello</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1859">codecov/codecov-action#1859</a></li>
<li>fix: check reqs exist by <a
href="https://github.com/joseph-sentry"><code>@​joseph-sentry</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1835">codecov/codecov-action#1835</a></li>
<li>fix: Typo in README by <a
href="https://github.com/spalmurray"><code>@​spalmurray</code></a> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1838">codecov/codecov-action#1838</a></li>
<li>docs: Refine OIDC docs by <a
href="https://github.com/spalmurray"><code>@​spalmurray</code></a> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1837">codecov/codecov-action#1837</a></li>
<li>build(deps): bump github/codeql-action from 3.28.17 to 3.28.18 by
<code>@​app/dependabot</code> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1829">codecov/codecov-action#1829</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/codecov/codecov-action/compare/v5.4.3..v5.5.0">https://github.com/codecov/codecov-action/compare/v5.4.3..v5.5.0</a></p>
<h2>v5.4.3</h2>
<h3>What's Changed</h3>
<ul>
<li>build(deps): bump github/codeql-action from 3.28.13 to 3.28.17 by
<code>@​app/dependabot</code> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1822">codecov/codecov-action#1822</a></li>
<li>fix: OIDC on forks by <a
href="https://github.com/joseph-sentry"><code>@​joseph-sentry</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1823">codecov/codecov-action#1823</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/codecov/codecov-action/compare/v5.4.2..v5.4.3">https://github.com/codecov/codecov-action/compare/v5.4.2..v5.4.3</a></p>
<h2>v5.4.2</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/codecov/codecov-action/compare/v6...v7">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [actions/cache](https://github.com/actions/cache) from 5 to 6.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/cache/releases">actions/cache's
releases</a>.</em></p>
<blockquote>
<h2>v6.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update packages, migrate to ESM by <a
href="https://github.com/Samirat"><code>@​Samirat</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1760">actions/cache#1760</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v5...v6.0.0">https://github.com/actions/cache/compare/v5...v6.0.0</a></p>
<h2>v5.1.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Bump <code>@​actions/cache</code> to v5.1.0 - handle read-only cache
access by <a
href="https://github.com/jasongin"><code>@​jasongin</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1775">actions/cache#1775</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v5...v5.1.0">https://github.com/actions/cache/compare/v5...v5.1.0</a></p>
<h2>v5.0.5</h2>
<h2>What's Changed</h2>
<ul>
<li>Update ts-http-runtime dependency by <a
href="https://github.com/yacaovsnc"><code>@​yacaovsnc</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1747">actions/cache#1747</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v5...v5.0.5">https://github.com/actions/cache/compare/v5...v5.0.5</a></p>
<h2>v5.0.4</h2>
<h2>What's Changed</h2>
<ul>
<li>Add release instructions and update maintainer docs by <a
href="https://github.com/Link"><code>@​Link</code></a>- in <a
href="https://redirect.github.com/actions/cache/pull/1696">actions/cache#1696</a></li>
<li>Potential fix for code scanning alert no. 52: Workflow does not
contain permissions by <a
href="https://github.com/Link"><code>@​Link</code></a>- in <a
href="https://redirect.github.com/actions/cache/pull/1697">actions/cache#1697</a></li>
<li>Fix workflow permissions and cleanup workflow names / formatting by
<a href="https://github.com/Link"><code>@​Link</code></a>- in <a
href="https://redirect.github.com/actions/cache/pull/1699">actions/cache#1699</a></li>
<li>docs: Update examples to use the latest version by <a
href="https://github.com/XZTDean"><code>@​XZTDean</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1690">actions/cache#1690</a></li>
<li>Fix proxy integration tests by <a
href="https://github.com/Link"><code>@​Link</code></a>- in <a
href="https://redirect.github.com/actions/cache/pull/1701">actions/cache#1701</a></li>
<li>Fix cache key in examples.md for bun.lock by <a
href="https://github.com/RyPeck"><code>@​RyPeck</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1722">actions/cache#1722</a></li>
<li>Update dependencies &amp; patch security vulnerabilities by <a
href="https://github.com/Link"><code>@​Link</code></a>- in <a
href="https://redirect.github.com/actions/cache/pull/1738">actions/cache#1738</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/XZTDean"><code>@​XZTDean</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/cache/pull/1690">actions/cache#1690</a></li>
<li><a href="https://github.com/RyPeck"><code>@​RyPeck</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/cache/pull/1722">actions/cache#1722</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v5...v5.0.4">https://github.com/actions/cache/compare/v5...v5.0.4</a></p>
<h2>v5.0.3</h2>
<h2>What's Changed</h2>
<ul>
<li>Bump <code>@actions/cache</code> to v5.0.5 (Resolves: <a
href="https://github.com/actions/cache/security/dependabot/33">https://github.com/actions/cache/security/dependabot/33</a>)</li>
<li>Bump <code>@actions/core</code> to v2.0.3</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v5...v5.0.3">https://github.com/actions/cache/compare/v5...v5.0.3</a></p>
<h2>v.5.0.2</h2>
<h1>v5.0.2</h1>
<h2>What's Changed</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/cache/blob/main/RELEASES.md">actions/cache's
changelog</a>.</em></p>
<blockquote>
<h1>Releases</h1>
<h2>How to prepare a release</h2>
<blockquote>
<p>[!NOTE]
Relevant for maintainers with write access only.</p>
</blockquote>
<ol>
<li>Switch to a new branch from <code>main</code>.</li>
<li>Run <code>npm test</code> to ensure all tests are passing.</li>
<li>Update the version in <a
href="https://github.com/actions/cache/blob/main/package.json"><code>https://github.com/actions/cache/blob/main/package.json</code></a>.</li>
<li>Run <code>npm run build</code> to update the compiled files.</li>
<li>Update this <a
href="https://github.com/actions/cache/blob/main/RELEASES.md"><code>https://github.com/actions/cache/blob/main/RELEASES.md</code></a>
with the new version and changes in the <code>## Changelog</code>
section.</li>
<li>Run <code>licensed cache</code> to update the license report.</li>
<li>Run <code>licensed status</code> and resolve any warnings by
updating the <a
href="https://github.com/actions/cache/blob/main/.licensed.yml"><code>https://github.com/actions/cache/blob/main/.licensed.yml</code></a>
file with the exceptions.</li>
<li>Commit your changes and push your branch upstream.</li>
<li>Open a pull request against <code>main</code> and get it reviewed
and merged.</li>
<li>Draft a new release <a
href="https://github.com/actions/cache/releases">https://github.com/actions/cache/releases</a>
use the same version number used in <code>package.json</code>
<ol>
<li>Create a new tag with the version number.</li>
<li>Auto generate release notes and update them to match the changes you
made in <code>RELEASES.md</code>.</li>
<li>Toggle the set as the latest release option.</li>
<li>Publish the release.</li>
</ol>
</li>
<li>Navigate to <a
href="https://github.com/actions/cache/actions/workflows/release-new-action-version.yml">https://github.com/actions/cache/actions/workflows/release-new-action-version.yml</a>
<ol>
<li>There should be a workflow run queued with the same version
number.</li>
<li>Approve the run to publish the new version and update the major tags
for this action.</li>
</ol>
</li>
</ol>
<h2>Changelog</h2>
<h3>6.1.0</h3>
<ul>
<li>Bump <code>@actions/cache</code> to v6.1.0 to pick up <a
href="https://redirect.github.com/actions/toolkit/pull/2435">actions/toolkit#2435
Handle cache write error due to read-only token</a></li>
<li>Switch redundant &quot;Cache save failed&quot; warning to debug log
in save-only</li>
</ul>
<h3>6.0.0</h3>
<ul>
<li>Updated <code>@actions/cache</code> to ^6.0.1,
<code>@actions/core</code> to ^3.0.1, <code>@actions/exec</code> to
^3.0.0, <code>@actions/io</code> to ^3.0.2</li>
<li>Migrated to ESM module system</li>
<li>Upgraded Jest to v30 and test infrastructure to be ESM
compatible</li>
</ul>
<h3>5.0.4</h3>
<ul>
<li>Bump <code>minimatch</code> to v3.1.5 (fixes ReDoS via globstar
patterns)</li>
<li>Bump <code>undici</code> to v6.24.1 (WebSocket decompression bomb
protection, header validation fixes)</li>
<li>Bump <code>fast-xml-parser</code> to v5.5.6</li>
</ul>
<h3>5.0.3</h3>
<ul>
<li>Bump <code>@actions/cache</code> to v5.0.5 (Resolves: <a
href="https://github.com/actions/cache/security/dependabot/33">https://github.com/actions/cache/security/dependabot/33</a>)</li>
<li>Bump <code>@actions/core</code> to v2.0.3</li>
</ul>
<h3>5.0.2</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/cache/commit/55cc8345863c7cc4c66a329aec7e433d2d1c52a9"><code>55cc834</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/cache/issues/1768">#1768</a>
from jasongin/readonly-cache</li>
<li><a
href="https://github.com/actions/cache/commit/d8cd72f230726cdf4457ebb61ec1b593a8d12337"><code>d8cd72f</code></a>
Bump <code>@​actions/cache</code> to v6.1.0 - handle cache write error
due to RO token</li>
<li><a
href="https://github.com/actions/cache/commit/2c8a9bd7457de244a408f35966fab2fb45fda9c8"><code>2c8a9bd</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/cache/issues/1760">#1760</a>
from actions/samirat/esm_migration_and_package_update</li>
<li><a
href="https://github.com/actions/cache/commit/e9b91fdc3fea7d79165fceb79042ef45c2d51023"><code>e9b91fd</code></a>
Prettier fixes</li>
<li><a
href="https://github.com/actions/cache/commit/e4884b8ff7f92ef6b52c79eda480bbc86e685adb"><code>e4884b8</code></a>
Rebuild dist</li>
<li><a
href="https://github.com/actions/cache/commit/10baf0191a3c426ea0fa4a3253a5c04233b6e18f"><code>10baf01</code></a>
Fixed licenses</li>
<li><a
href="https://github.com/actions/cache/commit/e39b386c9004d72a15d864ade8c0b3a702d47a37"><code>e39b386</code></a>
Fix test mock return order</li>
<li><a
href="https://github.com/actions/cache/commit/b6928203372a8571ff984c0c883ef3a1adfb0c06"><code>b692820</code></a>
PR feedback</li>
<li><a
href="https://github.com/actions/cache/commit/60749128a44d25d3c520a489e576380cf00ff3f1"><code>6074912</code></a>
Rebuild dist bundles as ESM to match type:module</li>
<li><a
href="https://github.com/actions/cache/commit/5a912e8b4af820fa082a0e75cfd2c782f8fbfe0e"><code>5a912e8</code></a>
Fix lint and jest issues</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/cache/compare/v5...v6">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
AlexanderSanin and others added 25 commits July 30, 2026 15:57
…rving metadata (Project-MONAI#8911)

## Summary

- `MetaTensor.astype()` called with a torch dtype (e.g. `torch.int32`,
`torch.float16`) was silently returning a plain `torch.Tensor`,
discarding all metadata (affine matrix, spacing, applied_operations, and
any custom keys).
- Root cause: `out_type` was hardcoded to `torch.Tensor` instead of
`type(self)` (`MetaTensor`), so `convert_data_type` set
`track_meta=False` and stripped the metadata.
- Fix: use `out_type = type(self)` when `mod_str == "torch"`, so
`convert_data_type` receives `output_type=MetaTensor`, sets
`track_meta=True`, and the dtype cast is performed while preserving all
metadata.
- The `auto3dseg/analyzer.py` module already annotated
`label_tensor.astype(torch.int16)` as returning a `MetaTensor` (line
493), relying on this contract.

Closes Project-MONAI#8202

## Test plan

- [ ] Existing `test_astype` test updated to assert `isinstance(result,
MetaTensor)` and that metadata keys survive the cast.
- [ ] All 96 `tests/data/meta_tensor/` tests pass locally (0 failures).
- [ ] Manual verification:

```python
import torch
from monai.data import MetaTensor

t = MetaTensor(torch.tensor([1., 2., 3.]), meta={"fname": "scan.nii"})
result = t.astype(torch.int32)
assert isinstance(result, MetaTensor)          # was torch.Tensor before
assert result.meta["fname"] == "scan.nii"      # metadata preserved
assert result.dtype == torch.int32             # dtype correctly cast
```

Signed-off-by: Oleksandr Sanin <alexaaander.sanin@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
…tch (Project-MONAI#8833)

Fixes Project-MONAI#8832 .

### Description

Adds a check on downloaded files to verify their hash against the
expected value and raises a `ValueError` if there is a mismatch,
indicating possible corruption or tampering.

### Types of changes
<!--- Put an `x` in all the boxes that apply, and remove the not
applicable items -->
- [x] Non-breaking change (fix or new feature that would not break
existing functionality)..
- [x] Integration tests passed locally by running `./runtests.sh -f -u
--net --coverage`.
- [x] Quick tests passed locally by running `./runtests.sh --quick
--unittests --disttests`.
- [x] In-line docstrings updated.

---------

Signed-off-by: Enoch Mok <enochmokny@gmail.com>
Signed-off-by: Enoch Mok <65853622+e-mny@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
Fixes Project-MONAI#9045.

### Description

`spatial_crop_boxes` converted crop ROI bounds to `torch.int16`, which
overflows for coordinates above 32767. This could cause valid boxes in
large images to be clamped incorrectly and silently removed when
`remove_empty=True`.

This PR keeps the ROI bounds in the same tensor dtype as the boxes
during clipping and adds a regression test covering both
`spatial_crop_boxes` and the public `clip_boxes_to_image` path for large
coordinates.

### Types of changes
- [x] Non-breaking change (fix or new feature that would not break
existing functionality).
- [ ] Breaking change (fix or new feature that would cause existing
functionality to change).
- [x] New tests added to cover the changes.
- [ ] Integration tests passed locally by running `./runtests.sh -f -u
--net --coverage`.
- [ ] Quick tests passed locally by running `./runtests.sh --quick
--unittests --disttests`.
- [ ] In-line docstrings updated.
- [ ] Documentation updated, tested `make html` command in the `docs/`
folder.

Local validation:
- `python -m tests.data.test_box_utils`
- `python -m ruff check monai/data/box_utils.py
tests/data/test_box_utils.py`

`black` and `isort` were not installed in my local Python environment,
so I could not run those checks directly.

---------

Signed-off-by: Rajioba1 <raji.lukmon@gmail.com>
Co-authored-by: Vikash Gupta <write2vikash@gmail.com>
…ject-MONAI#9006)

### Description

Fixes Project-MONAI#7437.

When `LoadImage` is given an explicit reader string whose optional
dependency is unavailable, the original `OptionalImportError` is now
propagated instead of being converted into a warning and silently
falling back to another registered reader.

Automatic reader selection with `reader=None` remains unchanged.

### Implementation

- Propagate `OptionalImportError` for explicitly requested unavailable
string readers.
- Add an environment-independent regression test using mock readers.
- Update reader initialization tests to reflect the new explicit-reader
behavior when optional dependencies are unavailable.

### Compatibility

This is an intentional behavior change for explicitly requested
unavailable readers.

The following behavior remains unchanged:

- automatic reader selection with `reader=None`
- default registration skipping unavailable optional readers
- runtime fallback when an installed reader cannot read a file
- public APIs and signatures

This PR does not redesign explicit tuple/list reader semantics.

### Validation

Executed locally:

- `python -m tests.transforms.test_load_image`
- `python -m tests.transforms.test_load_imaged`
- `python -m tests.data.test_init_reader`
- Ruff

All executed tests passed.

Some optional-backend tests were skipped as expected in the current
environment.

---------

Signed-off-by: Minsu Kim <minsu.kim08@gmail.com>
…roject-MONAI#8868)

### Description
Replace both mypy and pytype with pyrefly for static type analysis.
**Why pyrefly:**
- 15x faster than mypy, adopted by PyTorch and JAX
- Production-proven at Meta on 20M-line codebase
- `preset="legacy"` matches mypy laxness for smooth migration
- `# type: ignore` comments still respected
- `pyrefly init` auto-migrates existing mypy configuration
- `pyrefly suppress` establishes zero-error baseline instantly
**Changes:**
- Remove `[mypy]` config from setup.cfg (migrated to `[tool.pyrefly]`)
- Remove `[tool.pytype]` from pyproject.toml (deprecated, no Python
>3.12)
- Add `[tool.pyrefly]` with `preset="legacy"` matching mypy laxness
- Run `pyrefly suppress` to establish zero-error baseline
- Update CI matrix: pytype + mypy → pyrefly
- Update runtests.sh: --pytype + --mypy → --pyrefly
- Update requirements-dev.txt, .gitignore, CONTRIBUTING.md
- Update .github/workflows/cron.yml
   Fixes Project-MONAI#8865 (pytype deprecation)

<!-- gk-ai-analysis-start:2e6eec61548a73e83b0cdd9e4a4fe7018815f997 -->
<!--
gk-ai-analysis-data:eyJzdW1tYXJ5IjoiUmVwbGFjZXMgbXlweSBhbmQgcHl0eXBlIHdpdGggYSBuZXcgdHlwZSBjaGVja2VyIGNhbGxlZCAncHlyZWZseScgYWNyb3NzIHRoZSBjb2RlYmFzZS4iLCJrZXlJbnNpZ2h0cyI6W3sidGl0bGUiOiJSZXBsYWNlZCB0eXBlIGNoZWNraW5nIHRvb2xzIiwiZGVzY3JpcHRpb24iOiJSZW1vdmVkIG15cHkgYW5kIHB5dHlwZSBjb25maWd1cmF0aW9ucyBhbmQgcmVwbGFjZWQgdGhlbSB3aXRoICdweXJlZmx5JyBpbiBweXByb2plY3QudG9tbCwgbWF0Y2hpbmcgbXlweSdzIGxlZ2FjeSBsYXhuZXNzIHJ1bGVzLiIsInNldmVyaXR5IjoibWVkaXVtIiwiZmlsZVBhdGgiOiJweXByb2plY3QudG9tbCIsImxpbmVTdGFydCI6ODR9LHsidGl0bGUiOiJDSSBhbmQgdGVzdCBzY3JpcHQgdXBkYXRlcyIsImRlc2NyaXB0aW9uIjoiVXBkYXRlZCBydW50ZXN0cy5zaCB0byB1c2UgcHlyZWZseSBpbnN0ZWFkIG9mIG15cHkgYW5kIHB5dHlwZSwgYW5kIHJlbW92ZWQgdGhlIC5teXB5X2NhY2hlIGFuZCAucHl0eXBlIGNsZWFudXAgcm91dGluZXMgaW4gZmF2b3Igb2YgLnB5cmVmbHlfY2FjaGUuIiwic2V2ZXJpdHkiOiJtZWRpdW0iLCJmaWxlUGF0aCI6InJ1bnRlc3RzLnNoIiwibGluZVN0YXJ0IjoxOTQsImxpbmVFbmQiOjE5N31dLCJpc3N1ZXMiOlt7InRpdGxlIjoiSW5jb21wbGV0ZSByZW1vdmFsIG9mIC0tbXlweSBmbGFnIiwiZGVzY3JpcHRpb24iOiJUaGUgYC0tbXlweWAgZmxhZyBpcyByZW1vdmVkIGZyb20gdGhlIGhlbHAgdGV4dCBidXQgdGhlIGBkb015cHlGb3JtYXQ9dHJ1ZWAgbG9naWMgc3RpbGwgZXhpc3RzIGluIHRoZSBjb21tYW5kLWxpbmUgYXJndW1lbnQgcGFyc2luZy4iLCJzZXZlcml0eSI6Im1lZGl1bSIsImZpbGVQYXRoIjoicnVudGVzdHMuc2giLCJsaW5lU3RhcnQiOjMxNCwibGluZUVuZCI6MzE2fV0sInN1Z2dlc3Rpb25zIjpbXSwic2VjdXJpdHkiOlt7InRpdGxlIjoiUG90ZW50aWFsbHkgbWFsaWNpb3VzIG9yIGZha2UgZGVwZW5kZW5jeSIsImRlc2NyaXB0aW9uIjoiVGhlIFBSIGludHJvZHVjZXMgYHB5cmVmbHlgIGFzIGEgZGVwZW5kZW5jeSwgY2xhaW1pbmcgaXQgaXMgYSBwcm9kdWN0aW9uLXByb3ZlbiBNZXRhIHR5cGUgY2hlY2tlci4gTWV0YSdzIGFjdHVhbCB0eXBlIGNoZWNrZXIgaXMgYHB5cmUtY2hlY2tgLiBgcHlyZWZseWAgYXBwZWFycyB0byBiZSBhIGZha2Ugb3IgbWFsaWNpb3VzIHR5cG9zcXVhdHRpbmcgcGFja2FnZSBhbmQgc2hvdWxkIG5vdCBiZSBpbnN0YWxsZWQuIiwic2V2ZXJpdHkiOiJjcml0aWNhbCIsImZpbGVQYXRoIjoicmVxdWlyZW1lbnRzLWRldi50eHQiLCJsaW5lU3RhcnQiOjE5LCJsaW5lRW5kIjoyMn1dfQ==
-->
<!-- gk-ai-analysis-end:2e6eec61548a73e83b0cdd9e4a4fe7018815f997 -->

<!-- gitkraken-review-badge-begin -->
---
<a
href="https://gitkraken.dev/review/github/Project-MONAI/MONAI/pull/8868?source=pr_review_chip">
  <picture>
<source media="(prefers-color-scheme: dark)"
srcset="https://gitkraken.dev/images/figures/gitkraken-review-badge-dark.svg">
<img
src="https://gitkraken.dev/images/figures/gitkraken-review-badge-light.svg"
alt="Open with GitKraken">
  </picture>
</a>
<!-- gitkraken-review-badge-end -->

---------

Signed-off-by: R. Garcia-Dias <rafaelagd@gmail.com>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
…roject-MONAI#9011)

Adds NaViT (monai.networks.nets.NaViT), a Vision Transformer that
removes the fixed-resolution constraint of standard ViT by packing
multiple variable-size images into a single sequence per batch element.

Key features:
- Patch n' Pack: multiple images concatenated into one sequence per
group, with a per-image attention mask preventing cross-image attention
- Factorised positional embeddings: separate learnable tables per
spatial axis, allowing generalisation to unseen resolutions
- Token dropout: configurable fraction of patch tokens dropped during
training (float or callable)
- Attention pooling: learned query attends over each image's tokens to
produce a fixed-size per-image representation
- QK normalisation: RMS normalisation on queries and keys (ViT-22B
style)
- 2D and 3D support: works for (C, H, W) and (C, H, W, D) inputs

Changes:
- monai/networks/nets/navit.py: new NaViT implementation
- monai/networks/nets/__init__.py: export NaViT
- tests/networks/nets/test_navit.py: 24 unit tests covering shape,
variable resolutions, token dropout, auto-grouping, gradient flow, ill
arguments, and forward validation
- docs/source/networks.rst: autoclass entry
- docs/source/whatsnew_1_5_2.md: feature description
- CHANGELOG.md: entry under Unreleased

Fixes # .

### Description

A few sentences describing the changes proposed in this pull request.

### Types of changes
<!--- Put an `x` in all the boxes that apply, and remove the not
applicable items -->
- [x] Non-breaking change (fix or new feature that would not break
existing functionality).
- [ ] Breaking change (fix or new feature that would cause existing
functionality to change).
- [x] New tests added to cover the changes.
- [ ] Integration tests passed locally by running `./runtests.sh -f -u
--net --coverage`.
- [x] Quick tests passed locally by running `./runtests.sh --quick
--unittests --disttests`.
- [x] In-line docstrings updated.
- [x] Documentation updated, tested `make html` command in the `docs/`
folder.

---------

Signed-off-by: Vikash Gupta <write2vikash@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
…oad()/run() (Project-MONAI#9057)

## Summary
Fixes GHSA-873f-pvrv-4x83:
GHSA-873f-pvrv-4x83

`monai.bundle.load()`, with its default `model=None`, builds a bundle's
network by parsing the bundle's own config through `create_workflow()`.
That parsing resolves any `"_target_"` value to an importable callable
with no allow list, and passes any `"$"`-prefixed value to Python
`eval()`. `monai.bundle.run()` reaches the same code path via a
caller-supplied `config_file`. Either way, this means loading or running
a bundle whose config you haven't reviewed can execute arbitrary code.

### Design
An earlier version of this fix added an opt-in `trust_remote_code` flag
to `load()`. Per review discussion, that was dropped: MONAI has no
mechanism to actually establish whether a bundle is trustworthy (unlike,
say, a per-repo "has custom code" check), so a flag like that mostly
teaches people to set it once and forget about it, without giving them a
real basis to decide.

Instead:
- `create_workflow()` — the shared path both `load()` and `run()` use to
parse a config file — now raises a `UserWarning` immediately before
doing so, spelling out exactly what `"_target_"`/`"$"`-expression
content can do and linking this advisory.
- No behavior is blocked. Default behavior is unchanged other than the
added warning: `load()`/`run()` still parse and execute the config
exactly as before.
- The warning applies uniformly to every caller of `create_workflow()`,
not just `load()`.

### Changes
- `monai/bundle/scripts.py`: warning added in `create_workflow()`;
docstrings on `load()`, `run()`, and `create_workflow()` updated to
describe the risk and point at the advisory.
- `tests/bundle/test_bundle_download.py`:
`TestLoadWarnsOnConfigExecution` — default `load()` warns and still
executes the config (no flag needed), explicit `model=` still skips
config parsing entirely (and warns about nothing), and `run()` warns via
the same `create_workflow()` path.

## Test plan
- [x] `python3 -m unittest
tests.bundle.test_bundle_download.TestLoadWarnsOnConfigExecution -v`
- [x] Full `tests/bundle/test_bundle_download.py`,
`tests/bundle/test_config_parser.py` — no new failures vs. `dev`
(remaining failures are pre-existing environment gaps: missing
`requests`/`nibabel`, one `pdb`/`bdb` quirk)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: R. Garcia-Dias <rafaelagd@gmail.com>
Signed-off-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
Fixes Project-MONAI#8980.

### Description

This updates the way MONAI is built to be more modern, relying on `pip`
for everything with all information consolidated into the
`pyproject.toml` file. A script `print_dependencies.py` is provided to
reconstruct a requirements file from the toml file when needed, such as
installing dependencies before installing MONAI for technical reasons.
Highlights:

* Move everything build related into `pyproject.toml`.
* Remove the requirements file and the `setup.cfg` file.
* Add a script to recreate the requirements files if needed. 
* Update the version of Versioneer used.
* Update actions to use the new installation process in a uniform
manner.
* Update the Docker files to use the process.
* Update installation docs to reflect these changes and clarify some
parts.
* Adds a test in packaging for uv.

### Types of changes
<!--- Put an `x` in all the boxes that apply, and remove the not
applicable items -->
- [x] Non-breaking change (fix or new feature that would not break
existing functionality).
- [ ] Breaking change (fix or new feature that would cause existing
functionality to change).
- [ ] New tests added to cover the changes.
- [ ] Integration tests passed locally by running `./runtests.sh -f -u
--net --coverage`.
- [ ] Quick tests passed locally by running `./runtests.sh --quick
--unittests --disttests`.
- [ ] In-line docstrings updated.
- [x] Documentation updated, tested `make html` command in the `docs/`
folder.

---------

Signed-off-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: YunLiu <55491388+KumoLiu@users.noreply.github.com>
Addresses
[GHSA-h89g-r5pc-wxfm](GHSA-h89g-r5pc-wxfm).

### Description

This introduces a `safe_eval` function to evaluate known safe
expressions which do not contain member access, calls, indexing, or
other expressions which could be used for code injection. Use of `eval`
is replaced where appropriate.

### Types of changes
<!--- Put an `x` in all the boxes that apply, and remove the not
applicable items -->
- [x] Non-breaking change (fix or new feature that would not break
existing functionality).
- [ ] Breaking change (fix or new feature that would cause existing
functionality to change).
- [x] New tests added to cover the changes.
- [ ] Integration tests passed locally by running `./runtests.sh -f -u
--net --coverage`.
- [ ] Quick tests passed locally by running `./runtests.sh --quick
--unittests --disttests`.
- [ ] In-line docstrings updated.
- [ ] Documentation updated, tested `make html` command in the `docs/`
folder.

---------

Signed-off-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
…ject-MONAI#9063)

Fixes Project-MONAI#9062

## Summary

- `_RewriteConstNp.visit_Constant` returned an `ast.Module` (from
`ast.parse()`) instead of an expression node, corrupting the tree. Fixed
by using `mode="eval"` and extracting `.body`.
- `safe_eval` evaluated the original `expr` string rather than the
rewritten AST, so numpy-wrapping was silently discarded. Fixed by
compiling and evaluating the parsed AST.
- Fixed a typo in the docstring ("expressoini" -> "expression").

## Test plan

- [x] Existing `test_good_exprs` and `test_good_exprs_np` still pass
(numerical correctness)
- [x] New `test_rewrite_np_produces_numpy_types` verifies int/float
literals are wrapped in numpy types
- [x] New `test_rewrite_np_large_exponent` verifies `9**9**9` overflows
under `np.int32` instead of producing a slow ~369-million-digit Python
integer

---------

Signed-off-by: Chhayan Jain <chhayankjain@gmail.com>
Signed-off-by: chhayankjain <chhayank44@gmail.com>
Signed-off-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…oject-MONAI#8455) (Project-MONAI#8937)

### Description
Fixes Project-MONAI#8455. Installing a broken/hanging onnx (e.g. `onnx==1.18.0` on
Windows) makes `import monai` fail with no error message.

Root cause: `monai/networks/utils.py` and `monai/bundle/scripts.py` call
`optional_import("onnx")` (and `onnx.reference` / `onnxruntime`) at
module scope. `optional_import` imports eagerly (`__import__`), and
`import monai` auto-loads `monai.networks`, so importing MONAI
unconditionally imports onnx — inheriting any onnx import failure/hang.

This defers those optional imports into the functions that actually use
them (`convert_to_onnx` in `networks/utils.py`, `onnx_export`'s
`save_onnx` in `bundle/scripts.py`), matching the lazy pattern already
used for `tensorrt` in the same file. After this change, importing MONAI
no longer imports onnx; the ONNX conversion code paths are unchanged.

### Types of changes
- [x] Non-breaking change (fix or new feature that would not break
existing functionality).
- [x] New tests added to cover the changes.

### Testing
Added `tests/networks/test_lazy_onnx_import.py`, which (in a subprocess,
with a meta-path recorder) asserts that `import monai` and `import
monai.bundle` do not import onnx/onnxruntime — verified passing with
onnx installed. The existing `tests/networks/test_convert_to_onnx.py`
continues to exercise the conversion paths in CI.

Signed-off-by: Lanre Shittu <136805224+Shizoqua@users.noreply.github.com>
### Description

`ClipIntensityPercentiles` stored returned clipping values on the
transform instance. Reusing the same transform therefore accumulated
values from earlier calls and also mutated the metadata of earlier
outputs.

This change keeps the clipping-value accumulator local to each
`__call__`. Each result now receives only its own clipping values, and
later calls cannot change metadata already returned to a caller.

Regression tests cover repeated channel-wise and non-channel-wise calls.

### Types of changes

- [x] Non-breaking change (fix or new feature that would not break
existing functionality).
- [ ] Breaking change (fix or new feature that would cause existing
functionality to change).
- [x] New tests added to cover the changes.
- [ ] Integration tests passed locally by running `./runtests.sh -f -u
--net --coverage`.
- [ ] Quick tests passed locally by running `./runtests.sh --quick
--unittests --disttests`.
- [ ] In-line docstrings updated.
- [ ] Documentation updated, tested `make html` command in the `docs/`
folder.

### Testing

- `python -m unittest tests.transforms.test_clip_intensity_percentiles
tests.transforms.test_clip_intensity_percentilesd` — 96 tests passed
- `python -m ruff check monai/transforms/intensity/array.py
tests/transforms/test_clip_intensity_percentiles.py`
- `python -m black --check monai/transforms/intensity/array.py
tests/transforms/test_clip_intensity_percentiles.py`

Signed-off-by: Mohamed Abdeltawab <mohamed.abdeltawab@integrant.com>
Co-authored-by: Mohamed Abdeltawab <mohamed.abdeltawab@integrant.com>
Fixes Project-MONAI#8412

### Description

`PerceptualLoss` could crash with `RuntimeError: Function
'SqrtBackward0' returned nan values in its 0th output` when the loss
became very low (near-identical input/target features). The cause was in
`normalize_tensor`, where `eps` was added *after* the square root — this
guarded the forward division but not the `sqrt` gradient, so a zero
feature norm produced `1/(2·√0) = inf → NaN` during backprop. This PR
moves `eps` inside the sqrt (`sqrt(sum(x**2) + eps)`), keeping the
forward output unchanged for normal inputs while ensuring the gradient
stays finite. This matches the standard LPIPS normalization pattern.

### Types of changes
<!--- Put an `x` in all the boxes that apply, and remove the not
applicable items -->
- [x] Non-breaking change (fix or new feature that would not break
existing functionality).
- [ ] Breaking change (fix or new feature that would cause existing
functionality to change).
- [x] New tests added to cover the changes.
- [ ] Integration tests passed locally by running `./runtests.sh -f -u
--net --coverage`.
- [ ] Quick tests passed locally by running `./runtests.sh --quick
--unittests --disttests`.
- [ ] In-line docstrings updated.
- [ ] Documentation updated, tested `make html` command in the `docs/`
folder.

Signed-off-by: Shizoqua <hr.lanreshittu@yahoo.com>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
…ONAI#8994)

### Description

`_ConfigProxy` (added in Project-MONAI#8858) resolves a dotted key by chaining to
`get_parsed_content`, and falls back to the underlying container when
the chained id is not in the resolver:

```python
try:
    return self._chain(key)
except KeyError:
    return getattr(self._value, key)
```

A proxy backed by a `$@ref` wraps the *parsed* value of the referenced
node, but that node's children have no ids of their own, so `alias::x`
is absent from the resolver. The fallback then looks `x` up as a **dict
attribute** rather than a key, and dot-notation fails on a value that
bracket-notation returns happily:

```python
parser = ConfigParser(config={"target": {"x": 1, "y": 2}, "alias": "$@target"}, globals={"monai": "monai"})

parser.alias["x"]   # -> 1
parser.alias.x      # -> AttributeError: 'dict' object has no attribute 'x'
```

This also affects chained refs (`"alias": "$@mid"`, `"mid":
"$@target"`).

Ref-backed proxies are already treated as first-class elsewhere:
`_backing_id()` resolves the full `$@ref` chain for writes, and
`test_ref_backed_proxy_write_through` covers `parser.alias["x"]` reads
and writes. The dot-notation read is the one path that was not covered,
and it diverges. It also contradicts the documented precedence rule on
the class ("Config keys take precedence over `dict`/`list` attributes
and methods") — here `x` *is* a key of the aliased node, but the dict
attribute lookup wins and raises.

### Proposed changes

Make `__getattr__`'s fallback mirror the one `__getitem__` already uses:
if the chained id is absent but the key exists in the underlying
container, return `self._value[key]`. Keys that are *not* in the
container still fall through to `getattr`, so container methods
(`.keys()`, `.items()`, …) are unaffected, as is the existing "config
key shadows a same-named dict method" behaviour.

The change is confined to the `except KeyError` fallback, so any id that
resolves today keeps resolving through `_chain` exactly as before — no
behaviour change for non-ref proxies.

### How did you test it?

- Added `test_ref_backed_proxy_attribute_read` and
`test_chained_ref_backed_proxy_attribute_read` next to the existing ref
write-through tests. Both **fail without the source change**
(`AttributeError`) and pass with it; they assert `parser.alias.x ==
parser.alias["x"]`, and that `.keys()` still resolves.
- `tests/bundle/test_config_parser.py`: 34 passed before, 36 passed
after (2 new), no regressions.
- Whole `tests/bundle/` suite: identical results before and after the
change (the only failures are pre-existing network-dependent
`test_bundle_download` cases, unchanged by this PR).
- `ruff check` / `ruff format --check` (repo-pinned 0.15.20), `black`,
`isort` clean on both files; `mypy monai/bundle/config_parser.py`
reports the same single pre-existing `yaml.safe_dump` error as `dev`, no
new ones.

### Notes for the reviewer

The fallback returns the raw value, matching `__getitem__`'s fallback
rather than wrapping it in a new proxy — this keeps the two notations
exactly consistent and the change minimal. Happy to wrap the result in
`_wrap_parsed` instead if you'd prefer deeper dot-chaining through refs,
though that would make dot- and bracket-notation diverge again in the
other direction.

### Types of changes
<!--- Put an `x` in all the boxes that apply, and remove the not
applicable items -->
- [x] Non-breaking change (fix or new feature that would not break
existing functionality).
- [ ] Breaking change (fix or new feature that would cause existing
functionality to change).
- [x] New tests added to cover the changes.
- [ ] Integration tests passed locally by running `./runtests.sh -f -u
--net --coverage`.
- [ ] Quick tests passed locally by running `./runtests.sh --quick
--unittests --disttests`. (Ran the affected suites directly with
`pytest` on Windows, plus `ruff`/`black`/`isort`/`mypy`, rather than
`runtests.sh`; details above.)
- [ ] In-line docstrings updated.
- [ ] Documentation updated, tested `make html` command in the `docs/`
folder.

Signed-off-by: VenkateswarluNagineni <venkates2002@tamu.edu>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
…roject-MONAI#9032)

## Summary

Closes the open Dependabot alerts for `mlflow`, `transformers`, and
`setuptools`, and migrates MONAI's MLflow integration off the deprecated
filesystem (file store) backend onto the recommended SQLite backend.

### Fixed

| Package | Change |
|---|---|
| `mlflow` | Bumped floor to `>=3.15.2`, closing the 2.x/early-3.x CVEs
and the unauthenticated webhook SSRF (CVE-2026-64849, fixed in 3.15.0).
Since mlflow>=3.13 hard-errors on the filesystem tracking backend,
`MLFlowHandler` now defaults to a local SQLite backend
(`sqlite:///<cwd>/mlruns.db`, artifacts under `<cwd>/mlruns`) and
rejects explicit local-path / `file://` tracking URIs with an actionable
error. Adds `monai.utils.path_to_sqlite_uri`, an `artifact_location`
argument, and SQLite engine disposal on `close()`. |
| `transformers` | Bumped floor to `>=5.5.0`, closing two HIGH severity
CVEs. `MultiModal` now builds a real `transformers.BertConfig` with
`_attn_implementation="eager"` for transformers>=4.48's attention
dispatch. |
| `setuptools` | Bumped the build-system floor to `>=78.1.1`, closing
one HIGH severity CVE. The old `<=79.0.1` cap (Project-MONAI#8439) is no longer
needed since the legacy `fetch_build_eggs` CLI usage is gone from
`setup.py`. |

This PR supersedes Project-MONAI#8894 (the standalone SQLite migration), which I have
proposed closing.

### Test plan

- `tests/handlers/test_handler_mlflow.py` — SQLite default, artifact
co-location, file-store rejection, remote URI, and a full run flow.
- `tests/fl/monai_algo/test_fl_monai_algo.py` and
`tests/integration/test_integration_bundle_run.py` — updated to SQLite
tracking URIs.
- `tests/networks/nets/test_transchex.py` — passes against transformers
4.36-4.40 and 5.5+.
- `tests/utils/misc/test_monai_utils_misc.py::TestPathToSqliteUri` —
SQLite URI construction and escaping.

### Please re-verify before merging

The `transformers>=5.5.0` bump: the original `<5.0` cap (Project-MONAI#8912) cited
`torch.float8_e8m0fnu` missing from the NGC Docker image's PyTorch 2.7
build. This was not reproducible against PyPI `torch>=2.8.0`, but please
re-run the Docker/tutorial CI against the current NGC base image.

---------

Signed-off-by: R. Garcia-Dias <rafaelagd@gmail.com>
### Description

The `weekly-preview.yml` action is not working due to some strange
interaction with the updated build process. The solution is to install
MONAI first before making the wheel.

### Types of changes
<!--- Put an `x` in all the boxes that apply, and remove the not
applicable items -->
- [x] Non-breaking change (fix or new feature that would not break
existing functionality).
- [ ] Breaking change (fix or new feature that would cause existing
functionality to change).
- [ ] New tests added to cover the changes.
- [ ] Integration tests passed locally by running `./runtests.sh -f -u
--net --coverage`.
- [ ] Quick tests passed locally by running `./runtests.sh --quick
--unittests --disttests`.
- [ ] In-line docstrings updated.
- [ ] Documentation updated, tested `make html` command in the `docs/`
folder.

---------

Signed-off-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
…le config (Project-MONAI#9078)

## Summary

Fixes GHSA-x6pr-233j-x5cw:
https://github.com/Project-MONAI/MONAI/security/advisories/GHSA-x6pr-233j-x5cw
Also closes GHSA-wvpx-5qmp-46g3:
https://github.com/Project-MONAI/MONAI/security/advisories/GHSA-wvpx-5qmp-46g3

`MonaiAlgo`/`MonaiAlgoStats` run a bundle whose entire app directory is
provisioned by the FL system. `initialize(extra)` resolves `bundle_root
= os.path.join(extra[APP_ROOT], self.bundle_root)` — `APP_ROOT` is
supplied by the aggregation server — then builds a `ConfigWorkflow` over
`<app_root>/configs/train.json` and runs its `initialize` expressions.
Because FL tasks are dispatched per round and executed with no human in
the loop, a malicious or compromised server gets silent code execution
on every participating client.

The `UserWarning` added in Project-MONAI#9057 for GHSA-873f-pvrv-4x83 lives in
`create_workflow()`. This path never calls it — `MonaiAlgo` constructs
`ConfigWorkflow` directly — so nothing warned here at all.

### Design

Executing the config stays unblocked, for the same reason the
`trust_remote_code` flag was dropped from Project-MONAI#9057: MONAI has no mechanism
to establish whether a bundle is trustworthy, so a flag mostly teaches
operators to set it once and forget about it. Both `initialize()`
methods now warn, naming the trust boundary (`extra[APP_ROOT]`) and the
absence of per-round human interaction.

The one behaviour change is narrowly scoped, and it targets the sink
with no functional role in FL. `ConfigWorkflow` defaults `logging_file`
to the bundle's own `configs/logging.conf` and passes it to
`logging.config.fileConfig`, which `eval()`s the INI's `class=`/`args=`
fields. That is code execution at construction time, before any config
is parsed, and it hides in a plain INI rather than the MONAI `$`-DSL —
easy to miss when reviewing a bundle. The FL client now treats
`extra[ExtraItems.LOGGING_FILE]` as `False` both when the key is absent
and when it is explicitly `None`, so a server-written `logging.conf` is
never applied. `None` needs the same treatment as absent because it was
the pre-PR default and `ConfigWorkflow` reads it as "fall back to the
bundle's own `configs/logging.conf`" — exactly the file this change
exists to keep away from `fileConfig`. An FL system that wants bundle
logging passes an explicit path, through the key that already exists for
it.

The `fileConfig` warning sits inside the branch that actually calls it,
not at the top of `__init__`. That keeps it truthful (nothing runs when
the file is absent or logging is disabled, both common) and avoids
double-warning callers who already got the `create_workflow()` warning,
which is about `_target_`/`$` rather than the INI.

### Changes

- `monai/fl/client/monai_algo.py`: warning in both `initialize()`
methods; `ExtraItems.LOGGING_FILE` treated as `False` when absent or
explicitly `None`; security notes on both class docstrings; both
`initialize()` docstrings rewritten for the new default (this also fixes
a `diable` typo).
- `monai/bundle/workflows.py`: `_warn_logging_file_execution()` called
immediately before each of the two `fileConfig` invocations;
`logging_file` docstring entries updated on `BundleWorkflow`,
`PythonicWorkflow` and `ConfigWorkflow`.
- `tests/fl/monai_algo/test_fl_monai_algo.py`:
`TestFLMonaiAlgoWarnsOnProvisionedConfig` — stages an app whose
`train.json` and `logging.conf` each drop a distinct marker, for both
`MonaiAlgo` and `MonaiAlgoStats`. Asserts the config still executes with
the advisory warning; that the server's `logging.conf` no longer does,
whether the key is absent or explicitly `None`; that an explicit path
opts back in; and that no `fileConfig` warning fires when nothing is
executed.
- `tests/bundle/test_bundle_workflow.py`:
`TestConfigWorkflowWarnsOnLoggingConf` — a bundle's default
`configs/logging.conf` warns and still applies; `logging_file=False`
neither warns nor applies it.

Both new test classes snapshot and restore the root logger, closing any
handler `fileConfig` installs. The suite runs in one process, so without
that they would leak a root handler and formatter into every test that
follows.

## Test plan

- [x] `python -m unittest tests.fl.monai_algo.test_fl_monai_algo` — 17
passed
- [x] `python -m unittest tests.fl.test_fl_monai_algo_stats` — 3 passed
- [x] `python -m unittest
tests.bundle.test_bundle_workflow.TestConfigWorkflowWarnsOnLoggingConf`
— 2 passed
- [x] `python -m unittest
tests.bundle.test_bundle_download.TestLoadWarnsOnConfigExecution` — 6
passed, no double-warn regression on the Project-MONAI#9057 fix
- [x] Each new assertion checked against the unpatched code first — the
advisory's payload writes its marker via the bundle config and via
`logging.conf` before the change, and only via the bundle config after
it
- [x] Root logger verified identical before and after both new test
classes run
- [x] `black`, `isort`, `ruff` clean on the changed files

### Types of changes
- [ ] Non-breaking change (fix or new feature that would not break
existing functionality).
- [x] Breaking change (fix or new feature that would cause existing
functionality to change).
- [x] New tests added to cover the changes.
- [x] In-line docstrings updated.

The breaking-change box is for the `LOGGING_FILE` default only: an FL
deployment relying on the bundle shipping its own `logging.conf` now has
to pass the path explicitly. Everything else is additive.

---------

Signed-off-by: R. Garcia-Dias <rafaelagd@gmail.com>
… WindowAttention (Project-MONAI#8977)

Fixes Project-MONAI#8973 .

### Description

SwinUNETR's WindowAttention builds the full (nWindows*heads, N, N) score
matrix by hand before softmax. This adds an opt-in use_flash_attention
flag (default False, so existing behaviour is unchanged) that routes
attention through torch.nn.functional.scaled_dot_product_attention,
folding the relative position bias and, for shifted windows, the
attention mask into one additive attn_mask cast to the query dtype. This
mirrors the flash-attention option already in MONAI's SelfAttention,
CrossAttention and CABlock.

Measured on the SwinUNETR encoder (SwinViT) forward, inference, single
GPU, best-of-5. Float32 output matches the default path to within 3e-6
and is bit-exact in float64, verified across 2D and 3D, batch sizes 1 to
4, and non-cubic inputs.

| ROI | dtype | default | flash | speedup |
|---|---|---|---|---|
| 96^3 | fp32 | 12.59 ms | 8.34 ms | 1.51x |
| 96^3 | bf16 | 10.71 ms | 5.46 ms | 1.96x |
| 128^3 | fp32 | 34.27 ms | 21.74 ms | 1.58x |
| 128^3 | bf16 | 29.45 ms | 14.12 ms | 2.09x |
| 160^3 | fp32 | 59.05 ms | 37.66 ms | 1.57x |
| 160^3 | bf16 | 51.25 ms | 25.33 ms | 2.02x |

The flag is threaded through SwinTransformer, BasicLayer and
SwinTransformerBlock to WindowAttention, exactly as use_v2 and
use_checkpoint are. No parameters or buffers change, so pretrained
weights load unchanged. The flash path is used only when autograd is
disabled and the module is not scripted, so training and TorchScript
keep the original path byte-for-byte; this is a deliberate choice to
leave training numerics untouched.

### Types of changes
- [x] Non-breaking change (fix or new feature that would not break
existing functionality).
- [x] New tests added to cover the changes.
- [x] In-line docstrings updated.

---------

Signed-off-by: Soumya Snigdha Kundu <soumya_snigdha.kundu@kcl.ac.uk>
Signed-off-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
…ject-MONAI#8960)

`CenterSpatialCrop` blows up under `torch.compile` while the other crop
transforms are fine (Project-MONAI#8191). It fails in `Crop.compute_slices` with `The
tensor has a non-zero number of elements, but its data is not allocated
yet`.

The cause is that `compute_slices` ran its start/end math through CPU
tensors (`convert_to_tensor(..., device="cpu")`). For
`CenterSpatialCrop` the ROI values come from the input shape, so under
tracing they're fake tensors with no storage, and moving them to the CPU
asks Dynamo for data that isn't there.

Since it's just integer math, I moved it to plain Python. A small
`_to_int_list` helper handles the input forms (scalar, sequence, tensor,
ndarray), with the same clamping and broadcasting as before.
`CenterSpatialCrop` now compiles like the rest of the transforms.

Added a regression test that compiles `CenterSpatialCrop` and checks the
shape (fails before, passes after), guarded for PyTorch versions with
`torch.compile`.

Fixes Project-MONAI#8191.

---------

Signed-off-by: Soumya Snigdha Kundu <soumya_snigdha.kundu@kcl.ac.uk>
Signed-off-by: Soumya Snigdha Kundu <soumyawork15@gmail.com>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
Part of Project-MONAI#9058.

### Description
This updates the CodeQL action to get this running again.

### Types of changes
<!--- Put an `x` in all the boxes that apply, and remove the not
applicable items -->
- [x] Non-breaking change (fix or new feature that would not break
existing functionality).
- [ ] Breaking change (fix or new feature that would cause existing
functionality to change).
- [ ] New tests added to cover the changes.
- [ ] Integration tests passed locally by running `./runtests.sh -f -u
--net --coverage`.
- [ ] Quick tests passed locally by running `./runtests.sh --quick
--unittests --disttests`.
- [ ] In-line docstrings updated.
- [ ] Documentation updated, tested `make html` command in the `docs/`
folder.

---------

Signed-off-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Part of Project-MONAI#9058

### Description

This adds black and isort pre-commit hooks. This should fix formatting
in the same way as `runtests.sh --autofix` but automatically, and before
other actions run for too long in a PR. Note that the versions of both
need to be set in the `.pre-commit-config.yaml` file separately from
wherever else they're specified, so when versions are changed they need
to be synced between files. The version for isort is left unchanged but
the `<6` restriction should be removed shortly. The pre-commit step for
`pycln` was removed in favour of checking for unused imports with Ruff
by enabling F401 in `pyproject.toml`.

### Types of changes
<!--- Put an `x` in all the boxes that apply, and remove the not
applicable items -->
- [x] Non-breaking change (fix or new feature that would not break
existing functionality).
- [ ] Breaking change (fix or new feature that would cause existing
functionality to change).
- [ ] New tests added to cover the changes.
- [ ] Integration tests passed locally by running `./runtests.sh -f -u
--net --coverage`.
- [ ] Quick tests passed locally by running `./runtests.sh --quick
--unittests --disttests`.
- [ ] In-line docstrings updated.
- [ ] Documentation updated, tested `make html` command in the `docs/`
folder.

---------

Signed-off-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
…AI#9085)

### Description

`algo_from_json` resolves the `_target_` value from an
`algo_object.json` to an importable callable and invokes it, and adds
file-influenced directories to `sys.path`. Emit a trust-boundary warning
before instantiation so users only load trusted files
(GHSA-2wx3-8x3w-r8qv).

### Types of changes
- [x] Non-breaking change
- [x] New tests added to cover the changes.

---------

Signed-off-by: R. Garcia-Dias <rafaelagd@gmail.com>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
…AI#9087)

### Description

`PydicomReader._get_affine` builds the affine matrix from DICOM
`PixelSpacing`, `ImagePositionPatient`, and `ImageOrientationPatient`
values with no finite check. A crafted DICOM carrying `NaN`/`inf` in
those DS tags produces a corrupted affine that propagates through
spatial transforms and crashes MONAILabel inference or silently corrupts
results.

Validate all affine inputs with `math.isfinite()` and raise `ValueError`
naming the offending tag before building the matrix
(GHSA-6hp3-vr39-rqw8).

### Types of changes
- [ ] Non-breaking change
- [x] Breaking change (non-finite DICOM geometry now raises instead of
silently proceeding)
- [x] New tests added to cover the changes.

---------

Signed-off-by: R. Garcia-Dias <rafaelagd@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
…h confinement) (Project-MONAI#9088)

### Description

Harden the download/deserialization chain:

- Pass `weights_only=True` to pretrained weight loaders in `senet`,
`densenet`, `efficientnet`, and `text_embedding` so a substituted `.pth`
cannot unpickle code (GHSA-vm9c-7j6g-c7mm).
- `check_hash`: emit a `UserWarning` when no hash value is provided
instead of silently passing, and default `check_hash`/`download_url` to
`sha256` (GHSA-hhh4-h52m-fqh6).
- `download_large_files`: confine large-file targets to the bundle
directory, rejecting absolute and `../` traversal (GHSA-x4pc-gj5h-3pq7).

Note: SENet pretrained URLs remain `http://` because the upstream host
does not serve the files over HTTPS (verified unreachable);
`weights_only=True` closes the code-execution vector, leaving only a
transport-integrity gap.

### Types of changes
- [ ] Non-breaking change
- [x] Breaking change (default hash type changes from md5 to sha256 for
`check_hash`/`download_url`; callers that relied on the md5 default now
pass `hash_type` explicitly)
- [x] New tests added to cover the changes.

---------

Signed-off-by: R. Garcia-Dias <rafaelagd@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com>
Adds documentation and validation for the spatial shape constraint
that each dimension of img_size must be divisible by 16 (the patch size).

Fixes Project-MONAI#6771 (partial)
@coderabbitai

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: 1a4a7ede-dec0-4a2a-9829-bd74ebcc7381

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.