Skip to content

Commit 1ccec81

Browse files
add mypy
Signed-off-by: Ashwin Vaidya <[email protected]>
1 parent d64d907 commit 1ccec81

File tree

17 files changed

+118
-90
lines changed

17 files changed

+118
-90
lines changed

.pre-commit-config.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ repos:
1313
- id: debug-statements
1414
- id: detect-private-key
1515

16+
# python static type checking
17+
- repo: https://github.com/pre-commit/mirrors-mypy
18+
rev: "v1.11.2"
19+
hooks:
20+
- id: mypy
21+
additional_dependencies: [types-PyYAML, types-setuptools]
22+
1623
- repo: https://github.com/pre-commit/mirrors-prettier
1724
rev: v4.0.0-alpha.8
1825
hooks:

docs/source/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
]
4343

4444
templates_path = ['_templates']
45-
exclude_patterns = []
45+
exclude_patterns: list[str] = []
4646

4747
# Automatic exclusion of prompts from the copies
4848
# https://sphinx-copybutton.readthedocs.io/en/latest/use.html#automatic-exclusion-of-prompts-from-the-copies

examples/python/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Copyright (C) 2024 Intel Corporation
2+
# SPDX-License-Identifier: Apache-2.0

model_api/python/model_api/adapters/inference_adapter.py

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
limitations under the License.
1515
"""
1616

17-
import abc
17+
from abc import ABC, abstractmethod
1818
from dataclasses import dataclass, field
19-
from typing import Dict, List, Set, Tuple
19+
from typing import Any, Dict, List, Set, Tuple
2020

2121

2222
@dataclass
@@ -29,7 +29,7 @@ class Metadata:
2929
meta: Dict = field(default_factory=dict)
3030

3131

32-
class InferenceAdapter(metaclass=abc.ABCMeta):
32+
class InferenceAdapter(ABC):
3333
"""
3434
An abstract Model Adapter with the following interface:
3535
@@ -43,20 +43,25 @@ class InferenceAdapter(metaclass=abc.ABCMeta):
4343

4444
precisions = ("FP32", "I32", "FP16", "I16", "I8", "U8")
4545

46-
@abc.abstractmethod
47-
def __init__(self):
46+
@abstractmethod
47+
def __init__(self) -> None:
4848
"""
4949
An abstract Model Adapter constructor.
5050
Reads the model from disk or other place.
5151
"""
52+
self.model: Any
5253

53-
@abc.abstractmethod
54+
@abstractmethod
5455
def load_model(self):
5556
"""
5657
Loads the model on the device.
5758
"""
5859

59-
@abc.abstractmethod
60+
@abstractmethod
61+
def get_model(self):
62+
"""Get the model."""
63+
64+
@abstractmethod
6065
def get_input_layers(self):
6166
"""
6267
Gets the names of model inputs and for each one creates the Metadata structure,
@@ -67,7 +72,7 @@ def get_input_layers(self):
6772
- the dict containing Metadata for all inputs
6873
"""
6974

70-
@abc.abstractmethod
75+
@abstractmethod
7176
def get_output_layers(self):
7277
"""
7378
Gets the names of model outputs and for each one creates the Metadata structure,
@@ -78,7 +83,7 @@ def get_output_layers(self):
7883
- the dict containing Metadata for all outputs
7984
"""
8085

81-
@abc.abstractmethod
86+
@abstractmethod
8287
def reshape_model(self, new_shape):
8388
"""
8489
Reshapes the model inputs to fit the new input shape.
@@ -93,7 +98,7 @@ def reshape_model(self, new_shape):
9398
}
9499
"""
95100

96-
@abc.abstractmethod
101+
@abstractmethod
97102
def infer_sync(self, dict_data):
98103
"""
99104
Performs the synchronous model inference. The infer is a blocking method.
@@ -115,8 +120,8 @@ def infer_sync(self, dict_data):
115120
}
116121
"""
117122

118-
@abc.abstractmethod
119-
def infer_async(self, dict_data, callback_fn, callback_data):
123+
@abstractmethod
124+
def infer_async(self, dict_data, callback_data):
120125
"""
121126
Performs the asynchronous model inference and sets
122127
the callback for inference completion. Also, it should
@@ -130,11 +135,10 @@ def infer_async(self, dict_data, callback_fn, callback_data):
130135
'input_layer_name_2': data_2,
131136
...
132137
}
133-
- callback_fn: the callback function, which is defined outside the adapter
134138
- callback_data: the data for callback, that will be taken after the model inference is ended
135139
"""
136140

137-
@abc.abstractmethod
141+
@abstractmethod
138142
def is_ready(self):
139143
"""
140144
In case of asynchronous execution checks if one can submit input data
@@ -145,27 +149,27 @@ def is_ready(self):
145149
submitted to the model for inference or not
146150
"""
147151

148-
@abc.abstractmethod
152+
@abstractmethod
149153
def await_all(self):
150154
"""
151155
In case of asynchronous execution waits the completion of all
152156
busy infer requests.
153157
"""
154158

155-
@abc.abstractmethod
159+
@abstractmethod
156160
def await_any(self):
157161
"""
158162
In case of asynchronous execution waits the completion of any
159163
busy infer request until it becomes available for the data submission.
160164
"""
161165

162-
@abc.abstractmethod
166+
@abstractmethod
163167
def get_rt_info(self, path):
164168
"""
165169
Forwards to openvino.Model.get_rt_info(path)
166170
"""
167171

168-
@abc.abstractmethod
172+
@abstractmethod
169173
def embed_preprocessing(
170174
self,
171175
layout,

model_api/python/model_api/adapters/utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
import math
1818
from functools import partial
19-
from typing import Optional
19+
from typing import Callable, Optional
2020

2121
import cv2
2222
import numpy as np
@@ -492,7 +492,7 @@ def crop_resize_ocv(image, size):
492492
return cv2.resize(cropped_frame, size)
493493

494494

495-
RESIZE_TYPES = {
495+
RESIZE_TYPES:dict[str, Callable] = {
496496
"crop": crop_resize_ocv,
497497
"standard": resize_image_ocv,
498498
"fit_to_window": resize_image_with_aspect_ocv,

model_api/python/model_api/models/action_classification.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from typing import TYPE_CHECKING, Any
2020

2121
import numpy as np
22+
2223
from model_api.adapters.utils import RESIZE_TYPES, InputTransform
2324

2425
from .model import Model
@@ -74,6 +75,14 @@ def __init__(
7475
self.image_blob_names = self._get_inputs()
7576
self.image_blob_name = self.image_blob_names[0]
7677
self.nscthw_layout = "NSCTHW" in self.inputs[self.image_blob_name].layout
78+
self.labels: list[str]
79+
self.path_to_labels: str
80+
self.mean_values:list[int|float]
81+
self.pad_value: int
82+
self.resize_type: str
83+
self.reverse_input_channels: bool
84+
self.scale_values: list[int|float]
85+
7786
if self.nscthw_layout:
7887
self.n, self.s, self.c, self.t, self.h, self.w = self.inputs[
7988
self.image_blob_name
@@ -129,7 +138,7 @@ def parameters(cls) -> dict[str, Any]:
129138
)
130139
return parameters
131140

132-
def _get_inputs(self) -> tuple[list[str], list[str]]:
141+
def _get_inputs(self) -> list[str]:
133142
"""Defines the model inputs for images and additional info.
134143
135144
Raises:

model_api/python/model_api/models/anomaly.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import cv2
2525
import numpy as np
2626

27+
from model_api.adapters.inference_adapter import InferenceAdapter
28+
2729
from .image_model import ImageModel
2830
from .types import ListValue, NumericalValue, StringValue
2931
from .utils import AnomalyResult
@@ -32,7 +34,7 @@
3234
class AnomalyDetection(ImageModel):
3335
__model__ = "AnomalyDetection"
3436

35-
def __init__(self, inference_adapter, configuration=dict(), preload=False):
37+
def __init__(self, inference_adapter:InferenceAdapter, configuration:dict=dict(), preload:bool=False) -> None:
3638
super().__init__(inference_adapter, configuration, preload)
3739
self._check_io_number(1, 1)
3840
self.normalization_scale: float
@@ -41,7 +43,7 @@ def __init__(self, inference_adapter, configuration=dict(), preload=False):
4143
self.task: str
4244
self.labels: list[str]
4345

44-
def postprocess(self, outputs: dict[str, np.ndarray], meta: dict[str, Any]):
46+
def postprocess(self, outputs: dict[str, np.ndarray], meta: dict[str, Any]) -> AnomalyResult:
4547
"""Post-processes the outputs and returns the results.
4648
4749
Args:

model_api/python/model_api/models/classification.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
from openvino.runtime import Model, Type
2626
from openvino.runtime import opset10 as opset
2727

28+
from model_api.adapters.inference_adapter import InferenceAdapter
29+
2830
from .image_model import ImageModel
2931
from .types import BooleanValue, ListValue, NumericalValue, StringValue
3032
from .utils import ClassificationResult
@@ -33,13 +35,24 @@
3335
class ClassificationModel(ImageModel):
3436
__model__ = "Classification"
3537

36-
def __init__(self, inference_adapter, configuration=dict(), preload=False):
38+
def __init__(self, inference_adapter: InferenceAdapter, configuration:dict=dict(), preload:bool=False):
3739
super().__init__(inference_adapter, configuration, preload=False)
40+
self.topk:int
41+
self.labels:list[str]
42+
self.path_to_labels:str
43+
self.multilabel: bool
44+
self.hierarchical: bool
45+
self.hierarchical_config: str
46+
self.confidence_threshold: float
47+
self.output_raw_scores: bool
48+
self.hierarchical_postproc: str
49+
self.labels_resolver: GreedyLabelsResolver | ProbabilisticLabelsResolver
50+
3851
self._check_io_number(1, (1, 2, 3, 4, 5))
3952
if self.path_to_labels:
4053
self.labels = self._load_labels(self.path_to_labels)
4154
if 1 == len(self.outputs):
42-
self._verify_signle_output()
55+
self._verify_single_output()
4356

4457
self.raw_scores_name = _raw_scores_name
4558
if self.hierarchical:
@@ -108,7 +121,7 @@ def _load_labels(self, labels_file):
108121
labels.append(s[(begin_idx + 1) : end_idx])
109122
return labels
110123

111-
def _verify_signle_output(self):
124+
def _verify_single_output(self):
112125
layer_name = next(iter(self.outputs))
113126
layer_shape = self.outputs[layer_name].shape
114127

@@ -207,7 +220,7 @@ def get_saliency_maps(self, outputs: dict) -> np.ndarray:
207220
if not self.hierarchical:
208221
return saliency_maps
209222

210-
reordered_saliency_maps = [[] for _ in range(len(saliency_maps))]
223+
reordered_saliency_maps:list[list[ np.ndarray]] = [[] for _ in range(len(saliency_maps))]
211224
model_classes = self.hierarchical_info["cls_heads_info"]["class_to_group_idx"]
212225
label_to_model_out_idx = {lbl: i for i, lbl in enumerate(model_classes.keys())}
213226
for batch in range(len(saliency_maps)):
@@ -296,7 +309,7 @@ def get_multiclass_predictions(self, outputs):
296309
return list(zip(indicesTensor, labels, scoresTensor))
297310

298311

299-
def addOrFindSoftmaxAndTopkOutputs(inference_adapter, topk, output_raw_scores):
312+
def addOrFindSoftmaxAndTopkOutputs(inference_adapter:InferenceAdapter, topk:int, output_raw_scores:bool):
300313
softmaxNode = None
301314
for i in range(len(inference_adapter.model.outputs)):
302315
output_node = (

model_api/python/model_api/models/model.py

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import logging as log
1818
import re
19+
from abc import ABC
1920
from contextlib import contextmanager
2021

2122
from model_api.adapters.inference_adapter import InferenceAdapter
@@ -35,7 +36,7 @@ def __init__(self, wrapper_name, message):
3536
super().__init__(f"{wrapper_name}: {message}")
3637

3738

38-
class Model:
39+
class Model(ABC):
3940
"""An abstract model wrapper
4041
4142
The abstract model wrapper is free from any executor dependencies.
@@ -61,7 +62,7 @@ class Model:
6162
model_loaded (bool): a flag whether the model is loaded to device
6263
"""
6364

64-
__model__ = None # Abstract wrapper has no name
65+
__model__ :str
6566

6667
def __init__(self, inference_adapter, configuration=dict(), preload=False):
6768
"""Model constructor
@@ -101,19 +102,11 @@ def __init__(self, inference_adapter, configuration=dict(), preload=False):
101102
self.callback_fn = lambda _: None
102103

103104
def get_model(self):
104-
"""Returns the ov.Model object stored in the InferenceAdapter.
105-
106-
Note: valid only for local inference
107-
108-
Returns:
109-
ov.Model object
110-
Raises:
111-
RuntimeError: in case of remote inference (serving)
112-
"""
113-
if isinstance(self.inference_adapter, OpenvinoAdapter):
114-
return self.inference_adapter.get_model()
115-
116-
raise RuntimeError("get_model() is not supported for remote inference")
105+
model = self.inference_adapter.get_model()
106+
model.set_rt_info(self.__model__, ["model_info", "model_type"])
107+
for name in self.parameters():
108+
model.set_rt_info(getattr(self, name), ["model_info", name])
109+
return model
117110

118111
@classmethod
119112
def get_model_class(cls, name):
@@ -281,8 +274,8 @@ def _load_config(self, config):
281274
errors = parameters[name].validate(value)
282275
if errors:
283276
self.logger.error(f'Error with "{name}" parameter:')
284-
for error in errors:
285-
self.logger.error(f"\t{error}")
277+
for _error in errors:
278+
self.logger.error(f"\t{_error}")
286279
self.raise_error("Incorrect user configuration")
287280
value = parameters[name].get_value(value)
288281
self.__setattr__(name, value)
@@ -359,7 +352,7 @@ def _check_io_number(self, number_of_inputs, number_of_outputs):
359352
)
360353
)
361354
else:
362-
if not len(self.inputs) in number_of_inputs:
355+
if len(self.inputs) not in number_of_inputs:
363356
self.raise_error(
364357
"Expected {} or {} input blobs, but {} found: {}".format(
365358
", ".join(str(n) for n in number_of_inputs[:-1]),
@@ -380,7 +373,7 @@ def _check_io_number(self, number_of_inputs, number_of_outputs):
380373
)
381374
)
382375
else:
383-
if not len(self.outputs) in number_of_outputs:
376+
if len(self.outputs) not in number_of_outputs:
384377
self.raise_error(
385378
"Expected {} or {} output blobs, but {} found: {}".format(
386379
", ".join(str(n) for n in number_of_outputs[:-1]),
@@ -523,12 +516,6 @@ def log_layers_info(self):
523516
)
524517
)
525518

526-
def get_model(self):
527-
model = self.inference_adapter.get_model()
528-
model.set_rt_info(self.__model__, ["model_info", "model_type"])
529-
for name in self.parameters():
530-
model.set_rt_info(getattr(self, name), ["model_info", name])
531-
return model
532519

533520
def save(self, xml_path, bin_path="", version="UNSPECIFIED"):
534521
import openvino

0 commit comments

Comments
 (0)