Skip to content

Commit 7f6bf2d

Browse files
garciadiasericspod
andauthored
feat: replace mypy and pytype with pyrefly for static type analysis (#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 #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>
1 parent 1a165c9 commit 7f6bf2d

55 files changed

Lines changed: 184 additions & 41 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/cicd_tests.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ jobs:
5656
runs-on: ubuntu-latest
5757
strategy:
5858
matrix:
59-
opt: ["codeformat", "mypy"] # "pytype" omitted for being essentially deprecated, see #8865
59+
opt: ["codeformat", "pyrefly"]
6060
steps:
6161
- name: Clean unused tools
6262
run: |
@@ -80,8 +80,7 @@ jobs:
8080
run: |
8181
# clean up temporary files
8282
$(pwd)/runtests.sh --build --clean
83-
# Github actions have multiple cores, so parallelize pytype
84-
$(pwd)/runtests.sh --build --${{ matrix.opt }} -j $(nproc --all)
83+
$(pwd)/runtests.sh --build --${{ matrix.opt }}
8584
8685
min-dep: # Test with minumum dependencies installed for different OS, Python, and PyTorch combinations
8786
runs-on: ${{ matrix.os }}

.github/workflows/cron.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ jobs:
214214
python -c "import torch; print(torch.__version__); print('{} of GPUs available'.format(torch.cuda.device_count()))"
215215
python -c 'import torch; print(torch.rand(5,3, device=torch.device("cuda:0")))'
216216
ngc --version
217-
BUILD_MONAI=1 ./runtests.sh --build --coverage --unittests --disttests # unit tests with pytype checks, coverage report
217+
BUILD_MONAI=1 ./runtests.sh --build --coverage --pyrefly --unittests --disttests # unit tests with pyrefly checks, coverage report
218218
BUILD_MONAI=1 ./runtests.sh --build --coverage --net # integration tests with coverage report
219219
coverage xml --ignore-errors
220220
if pgrep python; then pkill python; fi

.github/workflows/weekly-preview.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
runs-on: ubuntu-latest
1313
strategy:
1414
matrix:
15-
opt: ["codeformat", "mypy"]
15+
opt: ["codeformat", "pyrefly"]
1616
steps:
1717
- name: Clean unused tools
1818
run: |

.gitignore

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,17 @@ venv.bak/
110110
# pytype cache
111111
.pytype/
112112

113+
# pyrefly cache
114+
.pyrefly_cache/
115+
113116
# mypy
114117
.mypy_cache/
118+
.dmypy.json
119+
115120
examples/scd_lvsegs.npz
116121
temp/
117122
.idea/
118-
.dmypy.json
123+
.plans/
119124

120125
*~
121126

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ Please note that, as per PyTorch, MONAI uses American English spelling. This mea
3838
### Preparing pull requests
3939

4040
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)),
41-
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.
41+
static type analysis tools ([pyrefly](https://github.com/facebook/pyrefly)), as well as a set of unit/integration tests.
4242

4343
This section highlights all the necessary preparation steps required before sending a pull request.
4444
To collaborate efficiently, please read through this section and follow them.

monai/apps/auto3dseg/auto_runner.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,7 @@ def _train_algo_in_nni(self, history: list[dict[str, Any]]) -> None:
790790
nni_config_filename = os.path.abspath(os.path.join(self.work_dir, f"{name}_nni_config.yaml"))
791791
ConfigParser.export_config_file(nni_config, nni_config_filename, fmt="yaml", default_flow_style=None)
792792

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

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

807808
cmd = "nnictl stop --all"
809+
# pyrefly: ignore [bad-argument-type]
808810
run_cmd(cmd.split(), check=True)
809811
logger.info(f"NNI completes HPO on {name}")
810812
last_total_tasks = n_trainings

monai/apps/deepedit/transforms.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,7 @@ def _randomize(self, d, key_label):
434434
else:
435435
logger.info(f"Not slice IDs for label: {key_label}")
436436
sid = None
437+
# pyrefly: ignore [unsupported-operation]
437438
self.sid[key_label] = sid
438439

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

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

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

890893
def __call__(self, data: Mapping[Hashable, np.ndarray]) -> dict[Hashable, np.ndarray]:

monai/apps/deepgrow/dataset.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ def _save_data_2d(vol_idx, vol_image, vol_label, dataset_dir, relative_path):
175175
continue
176176

177177
# For all Labels
178+
# pyrefly: ignore [missing-attribute]
178179
unique_labels = np.unique(label.flatten())
179180
unique_labels = unique_labels[unique_labels != 0]
180181
unique_labels_count = max(unique_labels_count, len(unique_labels))

monai/apps/deepgrow/transforms.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ def __init__(self, guidance: str = "guidance", discrepancy: str = "discrepancy",
288288
self._will_interact = None
289289

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

monai/apps/detection/networks/retinanet_detector.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,7 @@ def forward(
525525
)
526526

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

540542
# 6(1). If during training, return losses

0 commit comments

Comments
 (0)