[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
# Properties
from openvino._pyopenvino.properties import enable_profiling
from openvino._pyopenvino.properties import cache_dir
from openvino._pyopenvino.properties import auto_batch_timeout
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
import openvino._pyopenvino.properties as __properties
from openvino.properties._properties import __make_properties
__make_properties(__properties, __name__)
# Submodules
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
# Properties
from openvino._pyopenvino.properties.device import priorities
from openvino._pyopenvino.properties.device import id
from openvino._pyopenvino.properties.device import full_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
import openvino._pyopenvino.properties.device as __device
from openvino.properties._properties import __make_properties
__make_properties(__device, __name__)
# Classes
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
# Properties
from openvino._pyopenvino.properties.hint import inference_precision
from openvino._pyopenvino.properties.hint import model_priority
from openvino._pyopenvino.properties.hint import performance_mode
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
import openvino._pyopenvino.properties.hint as __hint
from openvino.properties._properties import __make_properties
__make_properties(__hint, __name__)

View File

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

View File

@ -2,5 +2,7 @@
# Copyright (C) 2018-2023 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
from openvino._pyopenvino.properties.intel_cpu import denormals_optimization
from openvino._pyopenvino.properties.intel_cpu import sparse_weights_decompression_rate
# Properties
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
# Properties
from openvino._pyopenvino.properties.intel_gpu import device_total_mem_size
from openvino._pyopenvino.properties.intel_gpu import uarch_version
from openvino._pyopenvino.properties.intel_gpu import execution_units_count
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
import openvino._pyopenvino.properties.intel_gpu as __intel_gpu
from openvino.properties._properties import __make_properties
__make_properties(__intel_gpu, __name__)
# Classes
from openvino._pyopenvino.properties.intel_gpu import MemoryType

View File

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

View File

@ -6,4 +6,6 @@
from openvino._pyopenvino.properties.log import Level
# 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
# SPDX-License-Identifier: Apache-2.0
# Properties
from openvino._pyopenvino.properties.streams import num
# Classes
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 -*-
# Copyright (C) 2022 Intel Corporation
# Copyright (C) 2018-2023 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
import pytest
import numpy as np
import os
import openvino as ov
import openvino.properties as props
import openvino.properties.hint as hints
import openvino.properties.intel_cpu as intel_cpu
@ -28,7 +29,7 @@ def test_properties_ro_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"))
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):
# Test if property is correctly registered
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):
# Test if property is correctly registered
assert ov_property_rw() == expected_value
assert ov_property_rw == expected_value
# Test if property process values correctly
for values in test_values:
@ -381,7 +384,7 @@ def test_properties_rw(ov_property_rw, expected_value, test_values):
# Special cases
###
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,"))
@ -401,7 +404,7 @@ def test_properties_device_properties():
def check(value1, value2):
assert device.properties(value1) == ("DEVICE_PROPERTIES", OVAny(value2))
check({"CPU": {streams.num(): 2}},
check({"CPU": {streams.num: 2}},
{"CPU": {"NUM_STREAMS": 2}})
check({"CPU": make_dict(streams.num(2))},
{"CPU": {"NUM_STREAMS": streams.Num(2)}})
@ -457,7 +460,7 @@ def test_properties_hint_model():
model = generate_add_model()
assert hints.model() == "MODEL_PTR"
assert hints.model == "MODEL_PTR"
property_tuple = hints.model(model)
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))
assert streams.Num.AUTO.to_integer() == -1
assert props.streams.Num.AUTO.to_integer() == -1
assert type(core.get_property(device, streams.num())) == int
@ -494,28 +497,28 @@ def test_single_property_setting(device):
),
# Pure dict
{
props.enable_profiling(): True,
props.cache_dir(): "./",
props.inference_num_threads(): 9,
props.affinity(): props.Affinity.NONE,
hints.inference_precision(): Type.f32,
hints.performance_mode(): hints.PerformanceMode.LATENCY,
hints.enable_cpu_pinning(): True,
hints.scheduling_core_type(): hints.SchedulingCoreType.PCORE_ONLY,
hints.enable_hyper_threading(): True,
hints.num_requests(): 12,
streams.num(): 5,
props.enable_profiling: True,
props.cache_dir: "./",
props.inference_num_threads: 9,
props.affinity: props.Affinity.NONE,
hints.inference_precision: Type.f32,
hints.performance_mode: hints.PerformanceMode.LATENCY,
hints.enable_cpu_pinning: True,
hints.scheduling_core_type: hints.SchedulingCoreType.PCORE_ONLY,
hints.enable_hyper_threading: True,
hints.num_requests: 12,
streams.num: 5,
},
# Mixed dict
{
props.enable_profiling(): True,
props.enable_profiling: True,
"CACHE_DIR": "./",
props.inference_num_threads(): 9,
props.affinity(): "NONE",
props.inference_num_threads: 9,
props.affinity: "NONE",
"INFERENCE_PRECISION_HINT": Type.f32,
hints.performance_mode(): hints.PerformanceMode.LATENCY,
hints.scheduling_core_type(): hints.SchedulingCoreType.PCORE_ONLY,
hints.num_requests(): 12,
hints.performance_mode: hints.PerformanceMode.LATENCY,
hints.scheduling_core_type: hints.SchedulingCoreType.PCORE_ONLY,
hints.num_requests: 12,
"NUM_STREAMS": streams.Num(5),
"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"):
pytest.skip("This test runs only on openvino intel cpu plugin")
core.set_property(properties_to_set)
# RW properties
assert core.get_property("CPU", props.enable_profiling()) is True
assert core.get_property("CPU", props.cache_dir()) == "./"
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", streams.num()) == 5
assert core.get_property("CPU", props.enable_profiling) is True
assert core.get_property("CPU", props.cache_dir) == "./"
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", streams.num) == 5
# RO properties
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.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_async_infer_requests())) == tuple
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", props.supported_properties)) == dict
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.range_for_streams)) == 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.capabilities)) == list