Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
ba56a6d
Move test_image_filter.py
garciadias Feb 5, 2025
5216b7a
Merge remote-tracking branch 'origin/dev' into dev
garciadias Feb 12, 2025
eacd783
Merge remote-tracking branch 'origin/dev' into dev
garciadias Feb 14, 2025
c64825f
Merge remote-tracking branch 'upstream/dev' into dev
garciadias Feb 19, 2025
66b6c17
Merge remote-tracking branch 'origin/dev' into dev
garciadias Feb 27, 2025
19cab57
Merge remote-tracking branch 'upstream/dev' into dev
garciadias Apr 11, 2025
4b8086b
feat: replace mypy with ty for static type analysis
garciadias May 22, 2026
763b7ff
fix: restore mypy config and tune ty to match zero-error baseline
garciadias May 22, 2026
ae31bb2
chore: pin ty dev dependency to ty>=0.0.38
garciadias May 22, 2026
42ec9b2
fix: restore --mypy flag alongside --ty in runtests.sh
garciadias May 22, 2026
6cf89d0
Update .github/workflows/pythonapp.yml
garciadias May 29, 2026
b76fd6e
Update .github/workflows/weekly-preview.yml
garciadias May 29, 2026
8c5c242
feat: replace mypy and pytype with pyrefly for static type analysis
garciadias May 29, 2026
0b1017e
chore: remove dead doPytypeFormat variable from runtests.sh
garciadias May 29, 2026
60723b7
fix: run pyrefly without file args to respect project-includes config
garciadias May 29, 2026
3ec99c8
fix: update cron.yml to use --pyrefly instead of deprecated --pytype
garciadias May 29, 2026
29a9cdc
Merge branch 'upstream/dev' into 1760-replace-mypy-with-ty-type-checker
garciadias May 29, 2026
1cb1735
fix(ci): resolve pipeline failures on PR #8868
garciadias Jun 11, 2026
0f77891
fix: add pyrefly to --codeformat shorthand in runtests.sh (PR #8868)
garciadias Jun 11, 2026
1f01a21
DCO Remediation Commit for R. Garcia-Dias <rafaelagd@gmail.com>
garciadias Jun 11, 2026
b36d10d
DCO Remediation Commit for R. Garcia-Dias <rafaelagd@gmail.com>
garciadias Jun 11, 2026
583baed
Merge branch 'dev' of https://github.com/Project-MONAI/MONAI into 176…
garciadias Jun 11, 2026
db377e0
fix: resolve lingering merge conflict markers in workflows and CONTRI…
garciadias Jun 11, 2026
7b0a669
DCO Remediation Commit for R. Garcia-Dias <rafaelagd@gmail.com>
garciadias Jun 11, 2026
f800d21
fix: add least-privilege permissions block to premerge workflow
garciadias Jun 11, 2026
dfb1048
fix: suppress pre-existing pyrefly errors and fix import ordering
garciadias Jun 11, 2026
4514a0a
fix: remove pyrefly ignore comment causing isort failure in config/__…
garciadias Jun 11, 2026
24ddc21
fix: add deprecated rule suppression to pyrefly config
garciadias Jun 11, 2026
d5e50e0
fix: pin setuptools<70 in packaging jobs to keep pkg_resources for Me…
garciadias Jun 11, 2026
36afece
fix: use --no-build-isolation in packaging installs for MetricsReload…
garciadias Jun 11, 2026
8e4bbf1
fix: move pyrefly comments inline to avoid black reformat issues
garciadias Jun 11, 2026
a1dbe27
autofix
garciadias Jun 11, 2026
a526d94
fix: revert formatting change in bundle/utils.py that black rejected
garciadias Jun 11, 2026
d42b78a
fix: revert to torch==2.4.1 on Windows for gloo compat
garciadias Jun 12, 2026
69bd1e6
fix: skip distributed tests on Windows due to gloo backend unavailabi…
garciadias Jun 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/cicd_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
opt: ["codeformat", "mypy"] # "pytype" omitted for being essentially deprecated, see #8865
opt: ["codeformat", "pyrefly"]
steps:
- name: Clean unused tools
run: |
Expand Down Expand Up @@ -259,7 +259,7 @@ jobs:
cache: 'pip'
- name: Install dependencies
run: |
python -m pip install --user --upgrade pip setuptools wheel twine packaging
python -m pip install --user --upgrade pip "setuptools<70" wheel twine packaging
# install the latest pytorch for testing
# however, "pip install monai*.tar.gz" will build cpp/cuda with an isolated
# fresh torch installation according to pyproject.toml
Expand Down Expand Up @@ -291,8 +291,8 @@ jobs:
- name: Install wheel file
working-directory: ${{ steps.mktemp.outputs.tmp_dir }}
run: |
# install from wheel
python -m pip install monai*.whl --extra-index-url https://download.pytorch.org/whl/cpu
# install from wheel (use --no-build-isolation to keep system setuptools with pkg_resources)
python -m pip install monai*.whl --no-build-isolation --extra-index-url https://download.pytorch.org/whl/cpu
python -c 'import monai; monai.config.print_config()' 2>&1 | grep -iv "unknown"
python -c 'import monai; print(monai.__file__)'
python -m pip uninstall -y monai
Expand All @@ -302,6 +302,6 @@ jobs:
run: |
for name in *.tar.gz; do break; done
echo $name
python -m pip install ${name}[all] --extra-index-url https://download.pytorch.org/whl/cpu
python -m pip install ${name}[all] --no-build-isolation --extra-index-url https://download.pytorch.org/whl/cpu
python -c 'import monai; monai.config.print_config()' 2>&1 | grep -iv "unknown"
python -c 'import monai; print(monai.__file__)'
2 changes: 1 addition & 1 deletion .github/workflows/cron.yml
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ jobs:
python -c "import torch; print(torch.__version__); print('{} of GPUs available'.format(torch.cuda.device_count()))"
python -c 'import torch; print(torch.rand(5,3, device=torch.device("cuda:0")))'
ngc --version
BUILD_MONAI=1 ./runtests.sh --build --coverage --unittests --disttests # unit tests with pytype checks, coverage report
BUILD_MONAI=1 ./runtests.sh --build --coverage --pyrefly --unittests --disttests # unit tests with pyrefly checks, coverage report
BUILD_MONAI=1 ./runtests.sh --build --coverage --net # integration tests with coverage report
coverage xml --ignore-errors
if pgrep python; then pkill python; fi
Expand Down
213 changes: 213 additions & 0 deletions .github/workflows/pythonapp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
# Jenkinsfile.monai-premerge
name: premerge

permissions:
contents: read

on:
# quick tests for pull requests and the releasing branches
push:
branches:
- dev
- main
- releasing/*
pull_request:
head_ref-ignore:
- dev

concurrency:
# automatically cancel the previously triggered workflows when there's a newer version
group: build-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
# caching of these jobs:
# - docker-py3-pip- (shared)
# - ubuntu py37 pip-
# - os-latest-pip- (shared)
flake8-py3:
runs-on: ubuntu-latest
strategy:
matrix:
opt: ["codeformat", "pyrefly"]
steps:
- uses: actions/checkout@v6
- name: Set up Python ${{ env.PYTHON_VER1 || '3.10' }}
uses: actions/setup-python@v6
with:
python-version: ${{ env.PYTHON_VER1 || '3.10' }}
cache: 'pip'
- name: Install dependencies
run: |
find /opt/hostedtoolcache/* -maxdepth 0 ! -name 'Python' -exec rm -rf {} \;
python -m pip install --upgrade pip wheel
python -m pip install --no-build-isolation -r requirements-dev.txt
- name: Lint and type check
run: |
# clean up temporary files
$(pwd)/runtests.sh --build --clean
$(pwd)/runtests.sh --build --${{ matrix.opt }}

quick-py3: # full dependencies installed tests for different OS
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [windows-latest, macOS-latest, ubuntu-latest]
timeout-minutes: 120
steps:
- if: runner.os == 'windows'
name: Config pagefile (Windows only)
uses: al-cheb/configure-pagefile-action@v1.4
with:
minimum-size: 8GB
maximum-size: 16GB
disk-root: "D:"
- uses: actions/checkout@v6
- name: Set up Python ${{ env.PYTHON_VER1 || '3.10' }}
uses: actions/setup-python@v6
with:
python-version: ${{ env.PYTHON_VER1 || '3.10' }}
cache: 'pip'
- name: Prepare pip wheel
run: |
which python
python -m pip install --upgrade pip wheel
- if: runner.os == 'windows'
name: Install torch cpu from pytorch.org (Windows only)
run: |
python -m pip install torch==2.4.1 torchvision==0.19.1+cpu --index-url https://download.pytorch.org/whl/cpu
shell: bash
- if: runner.os == 'Linux'
name: Install itk pre-release (Linux only)
run: |
python -m pip install --pre -U itk
find /opt/hostedtoolcache/* -maxdepth 0 ! -name 'Python' -exec rm -rf {} \;
- name: Install the dependencies
run: |
python -m pip install --user --upgrade pip wheel
TORCH_VER=${{ env.PYTORCH_VER1 || '2.8.0' }}
TORCHVISION_VER=${{ env.TORCHVISION_VER1 || '0.23.0' }}
if [ "${{ runner.os }}" = "windows" ]; then
TORCH_VER="2.4.1"
TORCHVISION_VER="0.19.1"
fi
python -m pip install torch==${TORCH_VER} torchvision==${TORCHVISION_VER}
cat "requirements-dev.txt"
python -m pip install --no-build-isolation -r requirements-dev.txt
python -m pip list
BUILD_MONAI=0 python -m pip install -e . # test no compile installation
shell: bash
- name: Run compiled (${{ runner.os }})
run: |
python -m pip uninstall -y monai
BUILD_MONAI=1 python -m pip install -e . # compile the cpp extensions
shell: bash
- name: Run quick tests (CPU ${{ runner.os }})
run: |
python -c 'import torch; print(torch.__version__); print(torch.rand(5,3))'
python -c "import monai; monai.config.print_config()"
# Skip distributed tests on Windows where gloo backend is unsupported
./runtests.sh --unittests --timeout 240
env:
QUICKTEST: True
PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION: python # https://github.com/Project-MONAI/MONAI/issues/4354

packaging:
runs-on: ubuntu-latest
env:
QUICKTEST: True
shell: bash
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Set up Python ${{ env.PYTHON_VER1 || '3.10' }}
uses: actions/setup-python@v6
with:
python-version: ${{ env.PYTHON_VER1 || '3.10' }}
cache: 'pip'
- name: Install dependencies
run: |
find /opt/hostedtoolcache/* -maxdepth 0 ! -name 'Python' -exec rm -rf {} \;
python -m pip install --user --upgrade pip "setuptools<70" wheel twine packaging
# install the latest pytorch for testing
# however, "pip install monai*.tar.gz" will build cpp/cuda with an isolated
# fresh torch installation according to pyproject.toml
python -m pip install torch==${{ env.PYTORCH_VER1 || '2.8.0' }} torchvision --extra-index-url https://download.pytorch.org/whl/cpu
- name: Check packages
run: |
pip uninstall monai
pip list | grep -iv monai
git fetch --depth=1 origin +refs/tags/*:refs/tags/*
set -e

# build tar.gz and wheel
python setup.py check -m -s
python setup.py sdist bdist_wheel
python -m twine check dist/*
- run: echo "pwd=$PWD" >> $GITHUB_OUTPUT
id: root
- run: echo "tmp_dir=$(mktemp -d)" >> $GITHUB_OUTPUT
id: mktemp
- name: Move packages
run: |
printf ${{ steps.root.outputs.pwd }}
printf ${{ steps.mktemp.outputs.tmp_dir }}
# move packages to a temp dir
cp dist/monai* "${{ steps.mktemp.outputs.tmp_dir }}"
rm -r build dist monai.egg-info
cd "${{ steps.mktemp.outputs.tmp_dir }}"
ls -al
- name: Install wheel file
working-directory: ${{ steps.mktemp.outputs.tmp_dir }}
run: |
# install from wheel (use --no-build-isolation to keep system setuptools with pkg_resources)
python -m pip install monai*.whl --no-build-isolation
python -c 'import monai; monai.config.print_config()' 2>&1 | grep -iv "unknown"
python -c 'import monai; print(monai.__file__)'
python -m pip uninstall -y monai
rm monai*.whl
- name: Install source archive
working-directory: ${{ steps.mktemp.outputs.tmp_dir }}
run: |
# install from tar.gz (use --no-build-isolation to keep system setuptools with pkg_resources)
name=$(ls *.tar.gz | head -n1)
echo $name
python -m pip install $name[all] --no-build-isolation
python -c 'import monai; monai.config.print_config()' 2>&1 | grep -iv "unknown"
python -c 'import monai; print(monai.__file__)'
- name: Quick test
working-directory: ${{ steps.mktemp.outputs.tmp_dir }}
run: |
# run min tests
cp ${{ steps.root.outputs.pwd }}/requirements*.txt .
cp -r ${{ steps.root.outputs.pwd }}/tests .
ls -al
python -m pip install --no-build-isolation -r requirements-dev.txt
python -m unittest -v
env:
PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION: python # https://github.com/Project-MONAI/MONAI/issues/4354

build-docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Python ${{ env.PYTHON_VER1 || '3.10' }}
uses: actions/setup-python@v6
with:
python-version: ${{ env.PYTHON_VER1 || '3.10' }}
cache: 'pip'
- name: Install dependencies
run: |
python -m pip install --upgrade pip wheel
python -m pip install -r docs/requirements.txt --extra-index-url https://download.pytorch.org/whl/cpu
- name: Make html
run: |
cd docs/
make clean
make html 2>&1 | tee tmp_log
if [[ $(grep -c "ERROR:" tmp_log) != 0 ]]; then echo "found errors"; grep "ERROR:" tmp_log; exit 1; fi
sed '/WARNING.*pip/d' tmp_log > tmp_log1; mv tmp_log1 tmp_log # monai#7133
if [[ $(grep -c "WARNING:" tmp_log) != 0 ]]; then echo "found warnings"; grep "WARNING:" tmp_log; exit 1; fi
shell: bash
2 changes: 1 addition & 1 deletion .github/workflows/weekly-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
opt: ["codeformat", "mypy"]
opt: ["codeformat", "pyrefly"]
steps:
- name: Clean unused tools
run: |
Expand Down
8 changes: 2 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,11 @@ venv.bak/
# mkdocs documentation
/site

# pytype cache
.pytype/

# mypy
.mypy_cache/
# pyrefly cache
.pyrefly_cache/
examples/scd_lvsegs.npz
temp/
.idea/
.dmypy.json

*~

Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Please note that, as per PyTorch, MONAI uses American English spelling. This mea
### Preparing pull requests

To ensure the code quality, MONAI relies on several linting tools ([black](https://github.com/psf/black), [isort](https://github.com/timothycrosley/isort), [ruff](https://github.com/astral-sh/ruff)),
static type analysis tools ([mypy](https://github.com/python/mypy), [pytype](https://github.com/google/pytype)), as well as a set of unit/integration tests.
static type analysis tools ([pyrefly](https://github.com/facebook/pyrefly)), as well as a set of unit/integration tests.

This section highlights all the necessary preparation steps required before sending a pull request.
To collaborate efficiently, please read through this section and follow them.
Expand Down
3 changes: 3 additions & 0 deletions monai/apps/auto3dseg/auto_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,7 @@ def inspect_datalist_folds(self, datalist_filename: str) -> int:

datalist = ConfigParser.load_config_file(datalist_filename)
if "training" not in datalist:
# pyrefly: ignore [unnecessary-type-conversion]
raise ValueError("Datalist files has no training key:" + str(datalist_filename))

fold_list = [int(d["fold"]) for d in datalist["training"] if "fold" in d]
Expand Down Expand Up @@ -790,6 +791,7 @@ def _train_algo_in_nni(self, history: list[dict[str, Any]]) -> None:
nni_config_filename = os.path.abspath(os.path.join(self.work_dir, f"{name}_nni_config.yaml"))
ConfigParser.export_config_file(nni_config, nni_config_filename, fmt="yaml", default_flow_style=None)

# pyrefly: ignore [redundant-cast]
max_trial = min(self.hpo_tasks, cast(int, default_nni_config["maxTrialNumber"]))
cmd = "nnictl create --config " + nni_config_filename + " --port 8088"

Expand All @@ -805,6 +807,7 @@ def _train_algo_in_nni(self, history: list[dict[str, Any]]) -> None:
n_trainings = len(import_bundle_algo_history(self.work_dir, only_trained=True))

cmd = "nnictl stop --all"
# pyrefly: ignore [bad-argument-type]
run_cmd(cmd.split(), check=True)
logger.info(f"NNI completes HPO on {name}")
last_total_tasks = n_trainings
Expand Down
1 change: 1 addition & 0 deletions monai/apps/auto3dseg/bundle_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ def infer(self, image_file):
config_dir = os.path.join(self.output_path, "configs")
configs_path = [os.path.join(config_dir, f) for f in os.listdir(config_dir)]

# pyrefly: ignore [implicit-import]
spec = importlib.util.spec_from_file_location("InferClass", infer_py)
infer_class = importlib.util.module_from_spec(spec) # type: ignore
sys.modules["InferClass"] = infer_class
Expand Down
1 change: 1 addition & 0 deletions monai/apps/auto3dseg/ensemble_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ def __init__(self, history: Sequence[dict[str, Any]], data_src_cfg_name: str | N
self.ensemble: AlgoEnsemble
self.data_src_cfg = ConfigParser(globals=False)

# pyrefly: ignore [unnecessary-type-conversion]
if data_src_cfg_name is not None and os.path.exists(str(data_src_cfg_name)):
self.data_src_cfg.read_config(data_src_cfg_name)

Expand Down
3 changes: 3 additions & 0 deletions monai/apps/deepedit/transforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,7 @@ def _randomize(self, d, key_label):
else:
logger.info(f"Not slice IDs for label: {key_label}")
sid = None
# pyrefly: ignore [unsupported-operation]
self.sid[key_label] = sid

def __call__(self, data: Mapping[Hashable, np.ndarray]) -> dict[Hashable, np.ndarray]:
Expand Down Expand Up @@ -561,6 +562,7 @@ def __init__(
self.guidance: dict[str, list[list[int]]] = {}

def randomize(self, data=None):
# pyrefly: ignore [unsupported-operation]
probability = data[self.probability]
self._will_interact = self.R.choice([True, False], p=[probability, 1.0 - probability])

Expand Down Expand Up @@ -885,6 +887,7 @@ def _randomize(self, d, key_label):
else:
logger.info(f"Not slice IDs for label: {key_label}")
sid = None
# pyrefly: ignore [unsupported-operation]
self.sid[key_label] = sid

def __call__(self, data: Mapping[Hashable, np.ndarray]) -> dict[Hashable, np.ndarray]:
Expand Down
1 change: 1 addition & 0 deletions monai/apps/deepgrow/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ def _save_data_2d(vol_idx, vol_image, vol_label, dataset_dir, relative_path):
continue

# For all Labels
# pyrefly: ignore [missing-attribute]
unique_labels = np.unique(label.flatten())
unique_labels = unique_labels[unique_labels != 0]
unique_labels_count = max(unique_labels_count, len(unique_labels))
Expand Down
1 change: 1 addition & 0 deletions monai/apps/deepgrow/transforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ def __init__(self, guidance: str = "guidance", discrepancy: str = "discrepancy",
self._will_interact = None

def randomize(self, data=None):
# pyrefly: ignore [unsupported-operation]
probability = data[self.probability]
self._will_interact = self.R.choice([True, False], p=[probability, 1.0 - probability])

Expand Down
2 changes: 2 additions & 0 deletions monai/apps/detection/networks/retinanet_detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,7 @@ def forward(
)

# 4. Generate anchors and store it in self.anchors: List[Tensor]
# pyrefly: ignore [bad-argument-type]
self.generate_anchors(images, head_outputs)
# num_anchor_locs_per_level: List[int], list of HW or HWD for each level
num_anchor_locs_per_level = [x.shape[2:].numel() for x in head_outputs[self.cls_key]]
Expand All @@ -535,6 +536,7 @@ def forward(
# reshape to Tensor sized(B, sum(HWA), self.num_classes) for self.cls_key
# or (B, sum(HWA), 2* self.spatial_dims) for self.box_reg_key
# A = self.num_anchors_per_loc
# pyrefly: ignore [bad-argument-type]
head_outputs[key] = self._reshape_maps(head_outputs[key])

# 6(1). If during training, return losses
Expand Down
Loading
Loading