Skip to content

Fix issue 410 where the latest typeguard version 3.x is incompatible #411

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Mar 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,12 @@ class LiverTumorSegOperator(Operator):
"""

def __init__(self):

self.logger = logging.getLogger("{}.{}".format(__name__, type(self).__name__))
super().__init__()
self._input_dataset_key = "image"
self._pred_dataset_key = "pred"

def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):

input_image = op_input.get("image")
if not input_image:
raise ValueError("Input image is not found.")
Expand Down
2 changes: 0 additions & 2 deletions examples/apps/ai_unetr_seg_app/unetr_seg_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,12 @@ class UnetrSegOperator(Operator):
"""

def __init__(self):

self.logger = logging.getLogger("{}.{}".format(__name__, type(self).__name__))
super().__init__()
self._input_dataset_key = "image"
self._pred_dataset_key = "pred"

def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):

input_image = op_input.get("image")
if not input_image:
raise ValueError("Input image is not found.")
Expand Down
2 changes: 1 addition & 1 deletion monai/deploy/core/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def __init__(
self.description = get_docstring(self.__class__)
if not self.version:
try:
from _version import get_versions
from monai.deploy._version import get_versions

self.version = get_versions()["version"]
except ImportError:
Expand Down
2 changes: 1 addition & 1 deletion monai/deploy/core/executors/single_process_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def run(self):
)

next_op_exec_context = ExecutionContext(exec_context, next_op)
for (out_label, in_labels) in io_map.items():
for out_label, in_labels in io_map.items():
output = op_exec_context.output_context.get(out_label)
for in_label in in_labels:
next_op_exec_context.input_context.set(output, in_label)
Expand Down
2 changes: 1 addition & 1 deletion monai/deploy/core/graphs/nx_digraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,5 @@ def gen_worklist(self) -> Generator[Optional[Operator], None, None]:
return worklist

def gen_next_operators(self, op: Operator) -> Generator[Optional[Operator], None, None]:
for (_, v) in self._graph.out_edges(op):
for _, v in self._graph.out_edges(op):
yield v
1 change: 0 additions & 1 deletion monai/deploy/operators/dicom_data_loader_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ def _load_data(self, files: List[str]):
logging.warning(f"Ignored {file}, reason being: {ex}")

for sop_instance in sop_instances:

study_instance_uid = sop_instance[0x0020, 0x000D].value.name # name is the UID as str

if study_instance_uid not in study_dict:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
@md.output("dicom_instance", DataPath, IOType.DISK)
@md.env(pip_packages=["pydicom >= 1.4.2", "PyPDF2 >= 2.11.1", "monai"])
class DICOMEncapsulatedPDFWriterOperator(Operator):

DCM_EXTENSION = ".dcm"

def __init__(
Expand Down
1 change: 1 addition & 0 deletions monai/deploy/operators/dicom_seg_writer_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import datetime
import logging
import os
from pathlib import Path
from random import randint
from typing import TYPE_CHECKING, Dict, List, Optional, Sequence, Union
Expand Down
1 change: 0 additions & 1 deletion monai/deploy/operators/dicom_series_to_volume_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,6 @@ def _get_instance_properties(obj: object, not_none: bool = True) -> Dict:


def test():

from pathlib import Path

from monai.deploy.operators.dicom_data_loader_operator import DICOMDataLoaderOperator
Expand Down
1 change: 0 additions & 1 deletion monai/deploy/operators/dicom_text_sr_writer_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
@md.output("dicom_instance", DataPath, IOType.DISK)
@md.env(pip_packages=["pydicom >= 1.4.2", "monai"])
class DICOMTextSRWriterOperator(Operator):

# File extension for the generated DICOM Part 10 file.
DCM_EXTENSION = ".dcm"

Expand Down
2 changes: 0 additions & 2 deletions monai/deploy/operators/dicom_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ class ModelInfo(object):
"""

def __init__(self, creator: str = "", name: str = "", version: str = "", uid: str = ""):

self.creator = creator if isinstance(creator, str) else ""
self.name = name if isinstance(name, str) else ""
self.version = version if isinstance(version, str) else ""
Expand All @@ -77,7 +76,6 @@ def __init__(
series_number: str = "0000",
software_version_number: str = "",
):

self.manufacturer = manufacturer if isinstance(manufacturer, str) else ""
self.manufacturer_model = manufacturer_model if isinstance(manufacturer_model, str) else ""
self.series_number = series_number if isinstance(series_number, str) else ""
Expand Down
4 changes: 2 additions & 2 deletions monai/deploy/operators/monai_bundle_inference_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ def _read_from_archive(archive, root_name: str, config_name: str, do_search=True

# Try directly read with constructed and expected path into the archive
for suffix in bundle_suffixes:
path = Path(root_name, config_folder, config_name).with_suffix(suffix)
try:
path = Path(root_name, config_folder, config_name).with_suffix(suffix)
logging.debug(f"Trying to read config '{config_name}' content from {path}.")
content_text = archive.read(str(path))
break
Expand Down Expand Up @@ -268,6 +268,7 @@ def _ensure_str_list(config_names):

DEFAULT_BundleConfigNames = BundleConfigNames()


# The operator env decorator defines the required pip packages commonly used in the Bundles.
# The MONAI Deploy App SDK packager currently relies on the App to consolidate all required packages in order to
# install them in the MAP Docker image.
Expand Down Expand Up @@ -768,7 +769,6 @@ def _convert_from_image(self, img: Image) -> Tuple[np.ndarray, Dict]:
or ("spacing" in img_meta_dict and "original_affine" in img_meta_dict)
or "row_pixel_spacing" not in img_meta_dict
):

return img.asnumpy(), img_meta_dict
else:
return self._convert_from_image_dicom_source(img)
Expand Down
2 changes: 1 addition & 1 deletion monai/deploy/utils/importutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ def exact_version(the_module, version_str: str = "") -> bool:
Returns True if the module's __version__ matches version_str
"""
if not hasattr(the_module, "__version__"):
warnings.warn(f"{the_module} has no attribute __version__ in exact_version check.")
warnings.warn(f"{the_module} has no attribute __version__ in exact_version check.", stacklevel=2)
return False
return bool(the_module.__version__ == version_str)

Expand Down
2 changes: 1 addition & 1 deletion notebooks/tutorials/02_mednist_app-prebuilt.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
"Collecting networkx>=2.4\n",
" Downloading networkx-2.5.1-py3-none-any.whl (1.6 MB)\n",
"\u001b[K |████████████████████████████████| 1.6 MB 12.8 MB/s eta 0:00:01\n",
"\u001b[?25hCollecting typeguard>=2.12.1\n",
"\u001b[?25hCollecting typeguard~=2.12.1\n",
" Downloading typeguard-2.12.1-py3-none-any.whl (17 kB)\n",
"Collecting numpy>=1.17\n",
" Downloading numpy-1.19.5-cp36-cp36m-manylinux2010_x86_64.whl (14.8 MB)\n",
Expand Down
2 changes: 1 addition & 1 deletion notebooks/tutorials/03_segmentation_app.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@
"!python -c \"import pydicom\" || pip install -q \"pydicom>=1.4.2\"\n",
"!python -c \"import highdicom\" || pip install -q \"highdicom>=0.18.2\"\n",
"!python -c \"import SimpleITK\" || pip install -q \"SimpleITK>=2.0.0\"\n",
"!python -c \"import typeguard\" || pip install -q \"typeguard>=2.12.1\"\n",
"!python -c \"import typeguard\" || pip install -q \"typeguard~=2.12.1\"\n",
"\n",
"# Install MONAI Deploy App SDK package\n",
"!python -c \"import monai.deploy\" || pip install --upgrade -q \"monai-deploy-app-sdk\""
Expand Down
2 changes: 1 addition & 1 deletion notebooks/tutorials/03_segmentation_viz_app.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@
"!python -c \"import pydicom\" || pip install -q \"pydicom>=1.4.2\"\n",
"!python -c \"import highdicom\" || pip install -q \"highdicom>=0.18.2\"\n",
"!python -c \"import SimpleITK\" || pip install -q \"SimpleITK>=2.0.0\"\n",
"!python -c \"import typeguard\" || pip install -q \"typeguard>=2.12.1\"\n",
"!python -c \"import typeguard\" || pip install -q \"typeguard~=2.12.1\"\n",
"\n",
"# Install MONAI Deploy App SDK package\n",
"!python -c \"import monai.deploy\" || pip install --upgrade -q \"monai-deploy-app-sdk\"\n",
Expand Down
2 changes: 1 addition & 1 deletion notebooks/tutorials/06_monai_bundle_app.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@
"!python -c \"import pydicom\" || pip install -q \"pydicom>=1.4.2\"\n",
"!python -c \"import highdicom\" || pip install -q \"highdicom>=0.18.2\"\n",
"!python -c \"import SimpleITK\" || pip install -q \"SimpleITK>=2.0.0\"\n",
"!python -c \"import typeguard\" || pip install -q \"typeguard>=2.12.1\"\n",
"!python -c \"import typeguard\" || pip install -q \"typeguard~=2.12.1\"\n",
"\n",
"# Install MONAI Deploy App SDK package\n",
"!python -c \"import monai.deploy\" || pip install --upgrade -q \"monai-deploy-app-sdk\""
Expand Down
2 changes: 1 addition & 1 deletion notebooks/tutorials/07_multi_model_app.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@
"!python -c \"import pydicom\" || pip install -q \"pydicom>=1.4.2\"\n",
"!python -c \"import highdicom\" || pip install -q \"highdicom>=0.18.2\"\n",
"!python -c \"import SimpleITK\" || pip install -q \"SimpleITK>=2.0.0\"\n",
"!python -c \"import typeguard\" || pip install -q \"typeguard>=2.12.1\"\n",
"!python -c \"import typeguard\" || pip install -q \"typeguard~=2.12.1\"\n",
"\n",
"# Install MONAI Deploy App SDK package\n",
"!python -c \"import monai.deploy\" || pip install --upgrade -q \"monai-deploy-app-sdk\""
Expand Down
2 changes: 0 additions & 2 deletions platforms/nuance_pin/app/inference.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ def detection_list(self):
@md.env(pip_packages=["monai>=0.8.1", "torch>=1.5", "numpy>=1.21", "nibabel"])
class LungNoduleInferenceOperator(Operator):
def __init__(self, model_path: str = "model/model.ts"):

self.logger = logging.getLogger("{}.{}".format(__name__, type(self).__name__))
super().__init__()
self._input_dataset_key = "image"
Expand Down Expand Up @@ -125,7 +124,6 @@ def __init__(self, model_path: str = "model/model.ts"):
self.detector.eval()

def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):

input_image = op_input.get("image")
if not input_image:
raise ValueError("Input image not found.")
Expand Down
4 changes: 0 additions & 4 deletions platforms/nuance_pin/app/post_inference_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ def __init__(self, pin_processor: Optional[AiJobProcessor], *args, **kwargs):
self.pin_processor = pin_processor

def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):

selected_study = op_input.get("original_dicom")[0] # assuming a single study
selected_series = selected_study.selected_series[0] # assuming a single series
detection_result: DetectionResult = op_input.get("detection_predictions").detection_list[0]
Expand All @@ -60,7 +59,6 @@ def compute(self, op_input: InputContext, op_output: OutputContext, context: Exe
accession = all_ref_images[0].AccessionNumber

for inst_num, (box_data, box_score) in enumerate(zip(detection_result.box_data, detection_result.score_data)):

tracking_id = f"{accession}_nodule_{inst_num}" # site-specific ID
tracking_uid = hd.UID()

Expand Down Expand Up @@ -160,7 +158,6 @@ def __init__(self, pin_processor: Optional[AiJobProcessor], *args, **kwargs):
self.pin_processor = pin_processor

def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):

selected_study = op_input.get("original_dicom")[0] # assuming a single study
selected_series = selected_study.selected_series[0] # assuming a single series
detection_result: DetectionResult = op_input.get("detection_predictions").detection_list[0]
Expand Down Expand Up @@ -190,7 +187,6 @@ def compute(self, op_input: InputContext, op_output: OutputContext, context: Exe
slice_coords = list(range(len(selected_series.series.get_sop_instances())))

for box_data, box_score in zip(detection_result.box_data, detection_result.score_data):

affected_slice_idx = [
idx
for idx, slice_coord in enumerate(slice_coords)
Expand Down
1 change: 0 additions & 1 deletion platforms/nuance_pin/app_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@


class MONAIAppWrapper(AiJobProcessor):

partner_name = os.environ["AI_PARTNER_NAME"]
service_name = os.environ["AI_SVC_NAME"]
service_version = os.environ["AI_SVC_VERSION"]
Expand Down
75 changes: 74 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,78 @@ exclude = '''
'''

# https://github.com/microsoft/pyright/blob/main/docs/configuration.md
# NOTE: All relative paths are relative to the location of this file.
[tool.pyright]
ignore = ["versioneer.py", "_version.py"]
ignore = ["versioneer.py", "_version.py"]

# https://google.github.io/pytype/
[tool.pytype]
# Space-separated list of files or directories to exclude.
exclude = [
'versioneer.py',
'_version.py',
'**/_version.py',
]
# Space-separated list of files or directories to process.
inputs = [
'monai',
]
# Keep going past errors to analyze as many files as possible.
keep_going = true
# Run N jobs in parallel. When 'auto' is used, this will be equivalent to the
# number of CPUs on the host system.
jobs = 8
# All pytype output goes here.
output = '.pytype'
# Platform (e.g., "linux", "win32") that the target code runs on.
platform = 'linux'
# Paths to source code directories, separated by ':'.
pythonpath = '.'

# Always use function return type annotations. This flag is temporary and will
# be removed once this behavior is enabled by default.
always_use_return_annotations = false

# Enable parameter count checks for overriding methods. This flag is temporary
# and will be removed once this behavior is enabled by default.
overriding_parameter_count_checks = false

# Enable return type checks for overriding methods. This flag is temporary and
# will be removed once this behavior is enabled by default.
overriding_return_type_checks = true

# Use the enum overlay for more precise enum checking. This flag is temporary
# and will be removed once this behavior is enabled by default.
use_enum_overlay = false

# Opt-in: Do not allow Any as a return type.
no_return_any = false

# Experimental: Support pyglib's @cached.property.
enable_cached_property = false

# Experimental: Infer precise return types even for invalid function calls.
precise_return = false

# Experimental: Solve unknown types to label with structural types.
protocols = false

# Experimental: Only load submodules that are explicitly imported.
strict_import = false

# Experimental: Enable exhaustive checking of function parameter types.
strict_parameter_checks = false

# Experimental: Emit errors for comparisons between incompatible primitive
# types.
strict_primitive_comparisons = false

# Space-separated list of error names to ignore.
disable = [
'pyi-error',
'container-type-mismatch',
'attribute-error',
]

# Don't report errors.
report_errors = true
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
numpy>=1.21.6
networkx>=2.4
colorama>=0.4.1
typeguard>=2.12.1
typeguard~=2.12.1
43 changes: 8 additions & 35 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ install_requires =
numpy>=1.21.6
networkx>=2.4
colorama>=0.4.1
typeguard>=2.12.1
typeguard~=2.12.1

[options.extras_require]
all =
Expand All @@ -43,8 +43,13 @@ ignore =
E203,E305,E402,E501,E721,E741,F821,F841,F999,W503,W504,C408,E302,W291,E303,
# N812 lowercase 'torch.nn.functional' imported as non lowercase 'F'
N812,
B024, #abstract base class, but it has no abstract methods
B027 #method in base class with no implementation
#B024, abstract base class, but it has no abstract methods
B024,
# B027, #method in base class with no implementation
B027,
# B905 `zip()` without an explicit `strict=` parameter, but conflicting with pytype
B905

per_file_ignores =
__init__.py: F401
# Allow using camel case for variable/argument names for the sake of readability.
Expand Down Expand Up @@ -105,38 +110,6 @@ ignore_errors = True
# Ignores all non-fatal errors.
ignore_errors = True

[pytype]
# Space-separated list of files or directories to exclude.
exclude = versioneer.py _version.py
# Space-separated list of files or directories to process.
inputs = monai
# Keep going past errors to analyze as many files as possible.
keep_going = True
# Run N jobs in parallel.
jobs = 8
# All pytype output goes here.
output = .pytype
# Paths to source code directories, separated by ':'.
pythonpath = .
# Check attribute values against their annotations.
check_attribute_types = True
# Check container mutations against their annotations.
check_container_types = True
# Check parameter defaults and assignments against their annotations.
check_parameter_types = True
# Check variable values against their annotations.
check_variable_types = True
# Comma or space separated list of error names to ignore.
disable = pyi-error
# Report errors.
report_errors = True
# Experimental: Infer precise return types even for invalid function calls.
precise_return = True
# Experimental: solve unknown types to label with structural types.
protocols = True
# Experimental: Only load submodules that are explicitly imported.
strict_import = False

[tool:pytest]
# If a pytest section is found in one of the possible config files
# (pytest.ini, tox.ini or setup.cfg), then pytest will not look for any others,
Expand Down