Skip to content

Commit fdd07f3

Browse files
authored
Consistent usage of annotation syntax (#5836)
Fixes #5835. ### Description Use `from __future__ import annotations` in all source files using annotations, so we have consistent usage (and not only in ~5 files). The new annotations are also more readable e.g. `Optional[Union[List[str], str]]` vs. `list[str] | str | None`. Secondly, this issue includes changing `from typing import Callable, Sequence, ...` to `from collections.abc import Callable, Sequence, ...` since the ones in the `typing` module are deprecated. They are interchangeable even for `isinstance` checks (see also [this stackoverflow thread](https://stackoverflow.com/questions/62547848/should-isinstance-check-against-typing-or-collections-abc)). ### 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] Quick tests passed locally by running `./runtests.sh --quick --unittests --disttests`. Signed-off-by: Felix Schnabel <[email protected]>
1 parent 6060a47 commit fdd07f3

File tree

1,015 files changed

+5277
-3483
lines changed

Some content is hidden

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

1,015 files changed

+5277
-3483
lines changed

monai/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
# See the License for the specific language governing permissions and
1010
# limitations under the License.
1111

12+
from __future__ import annotations
13+
1214
import os
1315
import sys
1416

monai/_extensions/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,6 @@
99
# See the License for the specific language governing permissions and
1010
# limitations under the License.
1111

12+
from __future__ import annotations
13+
1214
from .loader import load_module

monai/_extensions/loader.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@
99
# See the License for the specific language governing permissions and
1010
# limitations under the License.
1111

12+
from __future__ import annotations
13+
1214
import platform
1315
from _thread import interrupt_main
1416
from contextlib import contextmanager
1517
from glob import glob
1618
from os import path
1719
from threading import Timer
18-
from typing import Optional
1920

2021
import torch
2122

@@ -44,9 +45,7 @@ def timeout(time, message):
4445
pass
4546

4647

47-
def load_module(
48-
module_name: str, defines: Optional[dict] = None, verbose_build: bool = False, build_timeout: int = 300
49-
):
48+
def load_module(module_name: str, defines: dict | None = None, verbose_build: bool = False, build_timeout: int = 300):
5049
"""
5150
Handles the loading of c++ extension modules.
5251

monai/apps/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
# See the License for the specific language governing permissions and
1010
# limitations under the License.
1111

12+
from __future__ import annotations
13+
1214
from .datasets import CrossValidation, DecathlonDataset, MedNISTDataset, TciaDataset
1315
from .mmars import MODEL_DESC, RemoteMMARKeys, download_mmar, get_model_spec, load_from_mmar
1416
from .utils import SUPPORTED_HASH_TYPES, check_hash, download_and_extract, download_url, extractall, get_logger, logger

monai/apps/auto3dseg/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
# See the License for the specific language governing permissions and
1010
# limitations under the License.
1111

12+
from __future__ import annotations
13+
1214
from .auto_runner import AutoRunner
1315
from .bundle_gen import BundleAlgo, BundleGen
1416
from .data_analyzer import DataAnalyzer

monai/apps/auto3dseg/__main__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
# See the License for the specific language governing permissions and
1010
# limitations under the License.
1111

12+
from __future__ import annotations
13+
1214
from monai.apps.auto3dseg.auto_runner import AutoRunner
1315
from monai.apps.auto3dseg.bundle_gen import BundleAlgo, BundleGen
1416
from monai.apps.auto3dseg.data_analyzer import DataAnalyzer

monai/apps/auto3dseg/auto_runner.py

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@
99
# See the License for the specific language governing permissions and
1010
# limitations under the License.
1111

12+
from __future__ import annotations
13+
1214
import os
1315
import shutil
1416
import subprocess
1517
from copy import deepcopy
1618
from time import sleep
17-
from typing import Any, Dict, List, Optional, Union, cast
19+
from typing import Any, cast
1820

1921
import numpy as np
2022
import torch
@@ -204,21 +206,21 @@ class AutoRunner:
204206
205207
"""
206208

207-
analyze_params: Optional[Dict]
209+
analyze_params: dict | None
208210

209211
def __init__(
210212
self,
211213
work_dir: str = "./work_dir",
212-
input: Union[Dict[str, Any], str, None] = None,
213-
algos: Optional[Union[Dict, List, str]] = None,
214-
analyze: Optional[bool] = None,
215-
algo_gen: Optional[bool] = None,
216-
train: Optional[bool] = None,
214+
input: dict[str, Any] | str | None = None,
215+
algos: dict | list | str | None = None,
216+
analyze: bool | None = None,
217+
algo_gen: bool | None = None,
218+
train: bool | None = None,
217219
hpo: bool = False,
218220
hpo_backend: str = "nni",
219221
ensemble: bool = True,
220222
not_use_cache: bool = False,
221-
templates_path_or_url: Optional[str] = None,
223+
templates_path_or_url: str | None = None,
222224
**kwargs,
223225
):
224226

@@ -234,7 +236,7 @@ def __init__(
234236
input = self.data_src_cfg_name
235237
logger.info(f"Input config is not provided, using the default {input}")
236238

237-
if isinstance(input, Dict):
239+
if isinstance(input, dict):
238240
self.data_src_cfg = input
239241
ConfigParser.export_config_file(
240242
config=input, filepath=self.data_src_cfg_name, fmt="yaml", default_flow_style=None, sort_keys=False
@@ -279,14 +281,14 @@ def __init__(
279281
self.set_num_fold(num_fold=self.num_fold)
280282

281283
self.gpu_customization = False
282-
self.gpu_customization_specs: Dict[str, Any] = {}
284+
self.gpu_customization_specs: dict[str, Any] = {}
283285

284286
# hpo
285287
if hpo_backend.lower() != "nni":
286288
raise NotImplementedError("HPOGen backend only supports NNI")
287289
self.hpo = hpo and has_nni
288290
self.set_hpo_params()
289-
self.search_space: Dict[str, Dict[str, Any]] = {}
291+
self.search_space: dict[str, dict[str, Any]] = {}
290292
self.hpo_tasks = 0
291293

292294
def read_cache(self):
@@ -336,7 +338,7 @@ def export_cache(self, **kwargs):
336338
)
337339

338340
def set_gpu_customization(
339-
self, gpu_customization: bool = False, gpu_customization_specs: Optional[Dict[str, Any]] = None
341+
self, gpu_customization: bool = False, gpu_customization_specs: dict[str, Any] | None = None
340342
):
341343
"""
342344
Set options for GPU-based parameter customization/optimization.
@@ -389,7 +391,7 @@ def set_num_fold(self, num_fold: int = 5):
389391
if self.ensemble_method_name == "AlgoEnsembleBestByFold":
390392
self.ensemble_method.n_fold = self.num_fold # type: ignore
391393

392-
def set_training_params(self, params: Optional[Dict[str, Any]] = None):
394+
def set_training_params(self, params: dict[str, Any] | None = None):
393395
"""
394396
Set the training params for all algos.
395397
@@ -404,7 +406,7 @@ def set_training_params(self, params: Optional[Dict[str, Any]] = None):
404406
"""
405407
self.train_params = deepcopy(params) if params is not None else {}
406408

407-
def set_prediction_params(self, params: Optional[Dict[str, Any]] = None):
409+
def set_prediction_params(self, params: dict[str, Any] | None = None):
408410
"""
409411
Set the prediction params for all algos.
410412
@@ -420,7 +422,7 @@ def set_prediction_params(self, params: Optional[Dict[str, Any]] = None):
420422
"""
421423
self.pred_params = deepcopy(params) if params is not None else {}
422424

423-
def set_analyze_params(self, params: Optional[Dict[str, Any]] = None):
425+
def set_analyze_params(self, params: dict[str, Any] | None = None):
424426
"""
425427
Set the data analysis extra params.
426428
@@ -438,7 +440,7 @@ def set_analyze_params(self, params: Optional[Dict[str, Any]] = None):
438440
else:
439441
self.analyze_params = deepcopy(params)
440442

441-
def set_hpo_params(self, params: Optional[Dict[str, Any]] = None):
443+
def set_hpo_params(self, params: dict[str, Any] | None = None):
442444
"""
443445
Set parameters for the HPO module and the algos before the training. It will attempt to (1) override bundle
444446
templates with the key-value pairs in ``params`` (2) change the config of the HPO module (e.g. NNI) if the
@@ -536,7 +538,7 @@ def set_ensemble_method(self, ensemble_method_name: str = "AlgoEnsembleBestByFol
536538
else:
537539
raise NotImplementedError(f"Ensemble method {self.ensemble_method_name} is not implemented.")
538540

539-
def _train_algo_in_sequence(self, history: List[Dict[str, Any]]):
541+
def _train_algo_in_sequence(self, history: list[dict[str, Any]]):
540542
"""
541543
Train the Algos in a sequential scheme. The order of training is randomized.
542544

monai/apps/auto3dseg/bundle_gen.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,20 @@
99
# See the License for the specific language governing permissions and
1010
# limitations under the License.
1111

12+
from __future__ import annotations
13+
1214
import importlib
1315
import os
1416
import shutil
1517
import subprocess
1618
import sys
1719
import time
1820
import warnings
21+
from collections.abc import Mapping
1922
from copy import deepcopy
2023
from pathlib import Path
2124
from tempfile import TemporaryDirectory
22-
from typing import Any, Dict, List, Mapping, Optional, Union
25+
from typing import Any
2326
from urllib.parse import urlparse
2427

2528
import torch
@@ -369,10 +372,10 @@ class BundleGen(AlgoGen):
369372
def __init__(
370373
self,
371374
algo_path: str = ".",
372-
algos: Optional[Union[Dict, List, str]] = None,
373-
templates_path_or_url: Optional[str] = None,
374-
data_stats_filename: Optional[str] = None,
375-
data_src_cfg_name: Optional[str] = None,
375+
algos: dict | list | str | None = None,
376+
templates_path_or_url: str | None = None,
377+
data_stats_filename: str | None = None,
378+
data_src_cfg_name: str | None = None,
376379
):
377380

378381
if algos is None or isinstance(algos, (list, tuple, str)):
@@ -426,7 +429,7 @@ def __init__(
426429

427430
self.data_stats_filename = data_stats_filename
428431
self.data_src_cfg_filename = data_src_cfg_name
429-
self.history: List[Dict] = []
432+
self.history: list[dict] = []
430433

431434
def set_data_stats(self, data_stats_filename: str):
432435
"""
@@ -454,7 +457,7 @@ def get_data_src(self):
454457
"""Get the data source filename"""
455458
return self.data_src_cfg_filename
456459

457-
def get_history(self) -> List:
460+
def get_history(self) -> list:
458461
"""get the history of the bundleAlgo object with their names/identifiers"""
459462
return self.history
460463

@@ -463,7 +466,7 @@ def generate(
463466
output_folder=".",
464467
num_fold: int = 5,
465468
gpu_customization: bool = False,
466-
gpu_customization_specs: Optional[Dict[str, Any]] = None,
469+
gpu_customization_specs: dict[str, Any] | None = None,
467470
):
468471
"""
469472
Generate the bundle scripts/configs for each bundleAlgo

monai/apps/auto3dseg/data_analyzer.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
# See the License for the specific language governing permissions and
1010
# limitations under the License.
1111

12+
from __future__ import annotations
13+
1214
import warnings
1315
from os import path
14-
from typing import Any, Dict, List, Optional, Union, cast
16+
from typing import Any, cast
1517

1618
import numpy as np
1719
import torch
@@ -111,18 +113,18 @@ class DataAnalyzer:
111113

112114
def __init__(
113115
self,
114-
datalist: Union[str, Dict],
116+
datalist: str | dict,
115117
dataroot: str = "",
116118
output_path: str = "./data_stats.yaml",
117119
average: bool = True,
118120
do_ccp: bool = False,
119-
device: Union[str, torch.device] = "cpu",
121+
device: str | torch.device = "cpu",
120122
worker: int = 2,
121123
image_key: str = "image",
122-
label_key: Optional[str] = "label",
123-
hist_bins: Optional[Union[list, int]] = 0,
124-
hist_range: Optional[list] = None,
125-
fmt: Optional[str] = "yaml",
124+
label_key: str | None = "label",
125+
hist_bins: list | int | None = 0,
126+
hist_range: list | None = None,
127+
fmt: str | None = "yaml",
126128
histogram_only: bool = False,
127129
**extra_params,
128130
):
@@ -146,7 +148,7 @@ def __init__(
146148
self.extra_params = extra_params
147149

148150
@staticmethod
149-
def _check_data_uniformity(keys: List[str], result: Dict):
151+
def _check_data_uniformity(keys: list[str], result: dict):
150152
"""
151153
Check data uniformity since DataAnalyzer provides no support to multi-modal images with different
152154
affine matrices/spacings due to monai transforms.
@@ -227,7 +229,7 @@ def get_all_case_stats(self, key="training", transform_list=None):
227229
files, _ = datafold_read(datalist=self.datalist, basedir=self.dataroot, fold=-1, key=key)
228230
dataset = Dataset(data=files, transform=transform)
229231
dataloader = DataLoader(dataset, batch_size=1, shuffle=False, num_workers=self.worker, collate_fn=no_collation)
230-
result: Dict[DataStatsKeys, Any] = {DataStatsKeys.SUMMARY: {}, DataStatsKeys.BY_CASE: []}
232+
result: dict[DataStatsKeys, Any] = {DataStatsKeys.SUMMARY: {}, DataStatsKeys.BY_CASE: []}
231233

232234
if not has_tqdm:
233235
warnings.warn("tqdm is not installed. not displaying the caching progress.")
@@ -261,7 +263,7 @@ def get_all_case_stats(self, key="training", transform_list=None):
261263
)
262264
result[DataStatsKeys.BY_CASE].append(stats_by_cases)
263265

264-
result[DataStatsKeys.SUMMARY] = summarizer.summarize(cast(List, result[DataStatsKeys.BY_CASE]))
266+
result[DataStatsKeys.SUMMARY] = summarizer.summarize(cast(list, result[DataStatsKeys.BY_CASE]))
265267

266268
if not self._check_data_uniformity([ImageStatsKeys.SPACING], result):
267269
print("Data spacing is not completely uniform. MONAI transforms may provide unexpected result")

monai/apps/auto3dseg/ensemble_builder.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@
99
# See the License for the specific language governing permissions and
1010
# limitations under the License.
1111

12+
from __future__ import annotations
13+
1214
import os
1315
from abc import ABC, abstractmethod
16+
from collections.abc import Sequence
1417
from copy import deepcopy
15-
from typing import Any, Dict, List, Optional, Sequence, Union
18+
from typing import Any
1619
from warnings import warn
1720

1821
import numpy as np
@@ -67,7 +70,7 @@ def get_algo_ensemble(self):
6770
"""
6871
return self.algo_ensemble
6972

70-
def set_infer_files(self, dataroot: str, data_list_or_path: Union[str, List], data_key: str = "testing"):
73+
def set_infer_files(self, dataroot: str, data_list_or_path: str | list, data_key: str = "testing"):
7174
"""
7275
Set the files to perform model inference.
7376
@@ -78,7 +81,7 @@ def set_infer_files(self, dataroot: str, data_list_or_path: Union[str, List], da
7881

7982
self.infer_files = []
8083

81-
if isinstance(data_list_or_path, List):
84+
if isinstance(data_list_or_path, list):
8285
self.infer_files = data_list_or_path
8386
elif isinstance(data_list_or_path, str):
8487
datalist = ConfigParser.load_config_file(data_list_or_path)
@@ -113,7 +116,7 @@ def ensemble_pred(self, preds, sigmoid=False):
113116
else:
114117
return VoteEnsemble(num_classes=preds[0].shape[0])(classes)
115118

116-
def __call__(self, pred_param: Optional[Dict[str, Any]] = None):
119+
def __call__(self, pred_param: dict[str, Any] | None = None):
117120
"""
118121
Use the ensembled model to predict result.
119122
@@ -233,7 +236,7 @@ def collect_algos(self) -> None:
233236
self.algo_ensemble = []
234237
for f_idx in range(self.n_fold):
235238
best_score = -1.0
236-
best_model: Optional[BundleAlgo] = None
239+
best_model: BundleAlgo | None = None
237240
for algo in self.algos:
238241
# algorithm folder: {net}_{fold_index}_{other}
239242
identifier = algo[AlgoEnsembleKeys.ID].split("_")[1]
@@ -264,8 +267,8 @@ class AlgoEnsembleBuilder:
264267
265268
"""
266269

267-
def __init__(self, history: Sequence[Dict], data_src_cfg_filename: Optional[str] = None):
268-
self.infer_algos: List[Dict[AlgoEnsembleKeys, Any]] = []
270+
def __init__(self, history: Sequence[dict], data_src_cfg_filename: str | None = None):
271+
self.infer_algos: list[dict[AlgoEnsembleKeys, Any]] = []
269272
self.ensemble: AlgoEnsemble
270273
self.data_src_cfg = ConfigParser(globals=False)
271274

@@ -292,7 +295,7 @@ def __init__(self, history: Sequence[Dict], data_src_cfg_filename: Optional[str]
292295

293296
self.add_inferer(name, gen_algo, best_metric)
294297

295-
def add_inferer(self, identifier: str, gen_algo: BundleAlgo, best_metric: Optional[float] = None):
298+
def add_inferer(self, identifier: str, gen_algo: BundleAlgo, best_metric: float | None = None):
296299
"""
297300
Add model inferer to the builder.
298301

0 commit comments

Comments
 (0)