[PyOV] Make openvino properties behave as python property object (#20007)

* properties as property

* working prototype

* another attempt

* fix for test

* cosmetic changes

* generate properties

* test upste

* add comments

* update submodules

* apply comments
This commit is contained in:
Anastasia Kuporosova 2023-09-26 21:38:53 +02:00 committed by GitHub
parent 2742752747
commit 9dfed28aed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 124 additions and 95 deletions

View File

@ -6,25 +6,9 @@
from openvino._pyopenvino.properties import Affinity from openvino._pyopenvino.properties import Affinity
# Properties # Properties
from openvino._pyopenvino.properties import enable_profiling import openvino._pyopenvino.properties as __properties
from openvino._pyopenvino.properties import cache_dir from openvino.properties._properties import __make_properties
from openvino._pyopenvino.properties import auto_batch_timeout __make_properties(__properties, __name__)
from openvino._pyopenvino.properties import num_streams
from openvino._pyopenvino.properties import inference_num_threads
from openvino._pyopenvino.properties import compilation_num_threads
from openvino._pyopenvino.properties import affinity
from openvino._pyopenvino.properties import force_tbb_terminate
from openvino._pyopenvino.properties import enable_mmap
from openvino._pyopenvino.properties import supported_properties
from openvino._pyopenvino.properties import available_devices
from openvino._pyopenvino.properties import model_name
from openvino._pyopenvino.properties import optimal_number_of_infer_requests
from openvino._pyopenvino.properties import range_for_streams
from openvino._pyopenvino.properties import optimal_batch_size
from openvino._pyopenvino.properties import max_batch_size
from openvino._pyopenvino.properties import range_for_async_infer_requests
from openvino._pyopenvino.properties import execution_devices
from openvino._pyopenvino.properties import loaded_from_cache
# Submodules # Submodules
from openvino.runtime.properties import hint from openvino.runtime.properties import hint

View File

@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2018-2023 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
import sys
from types import BuiltinFunctionType, ModuleType
from typing import Callable, Any, Union
class Property(str):
"""This class allows to make a string object callable. Call returns underlying string's data."""
def __new__(cls, prop: Callable[..., Any]): # type: ignore
instance = super().__new__(cls, prop())
instance.prop = prop
return instance
def __call__(self, *args: Any) -> Callable[..., Any]:
if args is not None:
return self.prop(*args)
return self.prop()
def __append_property_to_module(func: Callable[..., Any], target_module_name: str) -> None:
"""Modifies the target module's __getattr__ method to expose a python property wrapper by the function's name.
:param func: the function which will be transformed to behave as python property.
:param target_module_name: the name of the module to which properties are added.
"""
module = sys.modules[target_module_name]
def base_getattr(name: str) -> None:
raise AttributeError(
f"Module '{module.__name__}' doesn't have the attribute with name '{name}'.")
getattr_old = getattr(module, "__getattr__", base_getattr)
def getattr_new(name: str) -> Union[Callable[..., Any], Any]:
if func.__name__ == name:
return Property(func)
else:
return getattr_old(name)
module.__getattr__ = getattr_new # type: ignore
def __make_properties(source_module_of_properties: ModuleType, target_module_name: str) -> None:
"""Makes python properties in target module from functions found in the source module.
:param source_module_of_properties: the source module from which functions should be taken.
:param target_module_name: the name of the module to which properties are added.
"""
for attr in dir(source_module_of_properties):
func = getattr(source_module_of_properties, attr)
if isinstance(func, BuiltinFunctionType):
__append_property_to_module(func, target_module_name)

View File

@ -6,17 +6,9 @@
from openvino._pyopenvino.properties.device import Type from openvino._pyopenvino.properties.device import Type
# Properties # Properties
from openvino._pyopenvino.properties.device import priorities import openvino._pyopenvino.properties.device as __device
from openvino._pyopenvino.properties.device import id from openvino.properties._properties import __make_properties
from openvino._pyopenvino.properties.device import full_name __make_properties(__device, __name__)
from openvino._pyopenvino.properties.device import architecture
from openvino._pyopenvino.properties.device import type
from openvino._pyopenvino.properties.device import gops
from openvino._pyopenvino.properties.device import thermal
from openvino._pyopenvino.properties.device import capabilities
from openvino._pyopenvino.properties.device import uuid
from openvino._pyopenvino.properties.device import luid
from openvino._pyopenvino.properties.device import properties
# Classes # Classes
from openvino._pyopenvino.properties.device import Capability from openvino._pyopenvino.properties.device import Capability

View File

@ -9,13 +9,6 @@ from openvino._pyopenvino.properties.hint import ExecutionMode
from openvino.runtime.properties.hint.overloads import PerformanceMode from openvino.runtime.properties.hint.overloads import PerformanceMode
# Properties # Properties
from openvino._pyopenvino.properties.hint import inference_precision import openvino._pyopenvino.properties.hint as __hint
from openvino._pyopenvino.properties.hint import model_priority from openvino.properties._properties import __make_properties
from openvino._pyopenvino.properties.hint import performance_mode __make_properties(__hint, __name__)
from openvino._pyopenvino.properties.hint import enable_cpu_pinning
from openvino._pyopenvino.properties.hint import scheduling_core_type
from openvino._pyopenvino.properties.hint import enable_hyper_threading
from openvino._pyopenvino.properties.hint import execution_mode
from openvino._pyopenvino.properties.hint import num_requests
from openvino._pyopenvino.properties.hint import model
from openvino._pyopenvino.properties.hint import allow_auto_batching

View File

@ -2,6 +2,7 @@
# Copyright (C) 2018-2023 Intel Corporation # Copyright (C) 2018-2023 Intel Corporation
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
from openvino._pyopenvino.properties.intel_auto import device_bind_buffer # Properties
from openvino._pyopenvino.properties.intel_auto import enable_startup_fallback import openvino._pyopenvino.properties.intel_auto as __intel_auto
from openvino._pyopenvino.properties.intel_auto import enable_runtime_fallback from openvino.properties._properties import __make_properties
__make_properties(__intel_auto, __name__)

View File

@ -2,5 +2,7 @@
# Copyright (C) 2018-2023 Intel Corporation # Copyright (C) 2018-2023 Intel Corporation
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
from openvino._pyopenvino.properties.intel_cpu import denormals_optimization # Properties
from openvino._pyopenvino.properties.intel_cpu import sparse_weights_decompression_rate import openvino._pyopenvino.properties.intel_cpu as __intel_cpu
from openvino.properties._properties import __make_properties
__make_properties(__intel_cpu, __name__)

View File

@ -3,12 +3,9 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# Properties # Properties
from openvino._pyopenvino.properties.intel_gpu import device_total_mem_size import openvino._pyopenvino.properties.intel_gpu as __intel_gpu
from openvino._pyopenvino.properties.intel_gpu import uarch_version from openvino.properties._properties import __make_properties
from openvino._pyopenvino.properties.intel_gpu import execution_units_count __make_properties(__intel_gpu, __name__)
from openvino._pyopenvino.properties.intel_gpu import memory_statistics
from openvino._pyopenvino.properties.intel_gpu import enable_loop_unrolling
from openvino._pyopenvino.properties.intel_gpu import disable_winograd_convolution
# Classes # Classes
from openvino._pyopenvino.properties.intel_gpu import MemoryType from openvino._pyopenvino.properties.intel_gpu import MemoryType

View File

@ -3,10 +3,9 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# Properties # Properties
from openvino._pyopenvino.properties.intel_gpu.hint import queue_throttle import openvino._pyopenvino.properties.intel_gpu.hint as __hint
from openvino._pyopenvino.properties.intel_gpu.hint import queue_priority from openvino.properties._properties import __make_properties
from openvino._pyopenvino.properties.intel_gpu.hint import host_task_priority __make_properties(__hint, __name__)
from openvino._pyopenvino.properties.intel_gpu.hint import available_device_mem
# Classes # Classes
from openvino._pyopenvino.properties.intel_gpu.hint import ThrottleLevel from openvino._pyopenvino.properties.intel_gpu.hint import ThrottleLevel

View File

@ -6,4 +6,6 @@
from openvino._pyopenvino.properties.log import Level from openvino._pyopenvino.properties.log import Level
# Properties # Properties
from openvino._pyopenvino.properties.log import level import openvino._pyopenvino.properties.log as __log
from openvino.properties._properties import __make_properties
__make_properties(__log, __name__)

View File

@ -2,8 +2,10 @@
# Copyright (C) 2018-2023 Intel Corporation # Copyright (C) 2018-2023 Intel Corporation
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# Properties
from openvino._pyopenvino.properties.streams import num
# Classes # Classes
from openvino._pyopenvino.properties.streams import Num from openvino._pyopenvino.properties.streams import Num
# Properties
import openvino._pyopenvino.properties.streams as __streams
from openvino.properties._properties import __make_properties
__make_properties(__streams, __name__)

View File

@ -1,11 +1,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (C) 2022 Intel Corporation # Copyright (C) 2018-2023 Intel Corporation
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
import pytest import pytest
import numpy as np import numpy as np
import os import os
import openvino as ov
import openvino.properties as props import openvino.properties as props
import openvino.properties.hint as hints import openvino.properties.hint as hints
import openvino.properties.intel_cpu as intel_cpu import openvino.properties.intel_cpu as intel_cpu
@ -28,7 +29,7 @@ def test_properties_ro_base():
def test_properties_rw_base(): def test_properties_rw_base():
assert props.cache_dir() == "CACHE_DIR" assert ov.properties.cache_dir == "CACHE_DIR"
assert props.cache_dir("./test_dir") == ("CACHE_DIR", OVAny("./test_dir")) assert props.cache_dir("./test_dir") == ("CACHE_DIR", OVAny("./test_dir"))
with pytest.raises(TypeError) as e: with pytest.raises(TypeError) as e:
@ -181,6 +182,7 @@ def test_conflicting_enum(proxy_enums, expected_values):
def test_properties_ro(ov_property_ro, expected_value): def test_properties_ro(ov_property_ro, expected_value):
# Test if property is correctly registered # Test if property is correctly registered
assert ov_property_ro() == expected_value assert ov_property_ro() == expected_value
assert ov_property_ro == expected_value
### ###
@ -369,6 +371,7 @@ def test_properties_ro(ov_property_ro, expected_value):
def test_properties_rw(ov_property_rw, expected_value, test_values): def test_properties_rw(ov_property_rw, expected_value, test_values):
# Test if property is correctly registered # Test if property is correctly registered
assert ov_property_rw() == expected_value assert ov_property_rw() == expected_value
assert ov_property_rw == expected_value
# Test if property process values correctly # Test if property process values correctly
for values in test_values: for values in test_values:
@ -381,7 +384,7 @@ def test_properties_rw(ov_property_rw, expected_value, test_values):
# Special cases # Special cases
### ###
def test_properties_device_priorities(): def test_properties_device_priorities():
assert device.priorities() == "MULTI_DEVICE_PRIORITIES" assert device.priorities == "MULTI_DEVICE_PRIORITIES"
assert device.priorities("CPU,GPU") == ("MULTI_DEVICE_PRIORITIES", OVAny("CPU,GPU,")) assert device.priorities("CPU,GPU") == ("MULTI_DEVICE_PRIORITIES", OVAny("CPU,GPU,"))
assert device.priorities("CPU", "GPU") == ("MULTI_DEVICE_PRIORITIES", OVAny("CPU,GPU,")) assert device.priorities("CPU", "GPU") == ("MULTI_DEVICE_PRIORITIES", OVAny("CPU,GPU,"))
@ -401,7 +404,7 @@ def test_properties_device_properties():
def check(value1, value2): def check(value1, value2):
assert device.properties(value1) == ("DEVICE_PROPERTIES", OVAny(value2)) assert device.properties(value1) == ("DEVICE_PROPERTIES", OVAny(value2))
check({"CPU": {streams.num(): 2}}, check({"CPU": {streams.num: 2}},
{"CPU": {"NUM_STREAMS": 2}}) {"CPU": {"NUM_STREAMS": 2}})
check({"CPU": make_dict(streams.num(2))}, check({"CPU": make_dict(streams.num(2))},
{"CPU": {"NUM_STREAMS": streams.Num(2)}}) {"CPU": {"NUM_STREAMS": streams.Num(2)}})
@ -457,7 +460,7 @@ def test_properties_hint_model():
model = generate_add_model() model = generate_add_model()
assert hints.model() == "MODEL_PTR" assert hints.model == "MODEL_PTR"
property_tuple = hints.model(model) property_tuple = hints.model(model)
assert property_tuple[0] == "MODEL_PTR" assert property_tuple[0] == "MODEL_PTR"
@ -468,7 +471,7 @@ def test_single_property_setting(device):
core.set_property(device, streams.num(streams.Num.AUTO)) core.set_property(device, streams.num(streams.Num.AUTO))
assert streams.Num.AUTO.to_integer() == -1 assert props.streams.Num.AUTO.to_integer() == -1
assert type(core.get_property(device, streams.num())) == int assert type(core.get_property(device, streams.num())) == int
@ -494,28 +497,28 @@ def test_single_property_setting(device):
), ),
# Pure dict # Pure dict
{ {
props.enable_profiling(): True, props.enable_profiling: True,
props.cache_dir(): "./", props.cache_dir: "./",
props.inference_num_threads(): 9, props.inference_num_threads: 9,
props.affinity(): props.Affinity.NONE, props.affinity: props.Affinity.NONE,
hints.inference_precision(): Type.f32, hints.inference_precision: Type.f32,
hints.performance_mode(): hints.PerformanceMode.LATENCY, hints.performance_mode: hints.PerformanceMode.LATENCY,
hints.enable_cpu_pinning(): True, hints.enable_cpu_pinning: True,
hints.scheduling_core_type(): hints.SchedulingCoreType.PCORE_ONLY, hints.scheduling_core_type: hints.SchedulingCoreType.PCORE_ONLY,
hints.enable_hyper_threading(): True, hints.enable_hyper_threading: True,
hints.num_requests(): 12, hints.num_requests: 12,
streams.num(): 5, streams.num: 5,
}, },
# Mixed dict # Mixed dict
{ {
props.enable_profiling(): True, props.enable_profiling: True,
"CACHE_DIR": "./", "CACHE_DIR": "./",
props.inference_num_threads(): 9, props.inference_num_threads: 9,
props.affinity(): "NONE", props.affinity: "NONE",
"INFERENCE_PRECISION_HINT": Type.f32, "INFERENCE_PRECISION_HINT": Type.f32,
hints.performance_mode(): hints.PerformanceMode.LATENCY, hints.performance_mode: hints.PerformanceMode.LATENCY,
hints.scheduling_core_type(): hints.SchedulingCoreType.PCORE_ONLY, hints.scheduling_core_type: hints.SchedulingCoreType.PCORE_ONLY,
hints.num_requests(): 12, hints.num_requests: 12,
"NUM_STREAMS": streams.Num(5), "NUM_STREAMS": streams.Num(5),
"ENABLE_MMAP": "NO", "ENABLE_MMAP": "NO",
}, },
@ -526,21 +529,20 @@ def test_core_cpu_properties(properties_to_set):
if "Intel" not in core.get_property("CPU", "FULL_DEVICE_NAME"): if "Intel" not in core.get_property("CPU", "FULL_DEVICE_NAME"):
pytest.skip("This test runs only on openvino intel cpu plugin") pytest.skip("This test runs only on openvino intel cpu plugin")
core.set_property(properties_to_set) core.set_property(properties_to_set)
# RW properties # RW properties
assert core.get_property("CPU", props.enable_profiling()) is True assert core.get_property("CPU", props.enable_profiling) is True
assert core.get_property("CPU", props.cache_dir()) == "./" assert core.get_property("CPU", props.cache_dir) == "./"
assert core.get_property("CPU", props.inference_num_threads()) == 9 assert core.get_property("CPU", props.inference_num_threads) == 9
assert core.get_property("CPU", props.affinity()) == props.Affinity.NONE assert core.get_property("CPU", props.affinity) == props.Affinity.NONE
assert core.get_property("CPU", streams.num()) == 5 assert core.get_property("CPU", streams.num) == 5
# RO properties # RO properties
assert type(core.get_property("CPU", props.supported_properties())) == dict assert type(core.get_property("CPU", props.supported_properties)) == dict
assert type(core.get_property("CPU", props.available_devices())) == list assert type(core.get_property("CPU", props.available_devices)) == list
assert type(core.get_property("CPU", props.optimal_number_of_infer_requests())) == int assert type(core.get_property("CPU", props.optimal_number_of_infer_requests)) == int
assert type(core.get_property("CPU", props.range_for_streams())) == tuple assert type(core.get_property("CPU", props.range_for_streams)) == tuple
assert type(core.get_property("CPU", props.range_for_async_infer_requests())) == tuple assert type(core.get_property("CPU", props.range_for_async_infer_requests)) == tuple
assert type(core.get_property("CPU", device.full_name())) == str assert type(core.get_property("CPU", device.full_name)) == str
assert type(core.get_property("CPU", device.capabilities())) == list assert type(core.get_property("CPU", device.capabilities)) == list