634 lines
24 KiB
Python
634 lines
24 KiB
Python
# Copyright (C) 2018-2025 Intel Corporation
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
import argparse
|
|
import inspect
|
|
import os
|
|
import pathlib
|
|
import re
|
|
from collections import OrderedDict, namedtuple
|
|
from typing import Union
|
|
|
|
import openvino
|
|
from openvino import PartialShape, Dimension, Type # pylint: disable=no-name-in-module,import-error
|
|
from openvino.tools.ovc.error import Error
|
|
from openvino.tools.ovc.help import get_convert_model_help_specifics
|
|
from openvino.tools.ovc.moc_frontend.shape_utils import to_partial_shape, is_shape_type
|
|
from openvino.tools.ovc.moc_frontend.type_utils import to_ov_type, is_type
|
|
from openvino.tools.ovc.utils import get_mo_root_dir
|
|
|
|
# Helper class for storing input cut information
|
|
_InputCutInfo = namedtuple("InputCutInfo", ["name", "shape", "type", "value"], defaults=[None, None, None, None])
|
|
|
|
|
|
def single_input_to_input_cut_info(input: [str, tuple, list, PartialShape, Type, type]):
|
|
"""
|
|
Parses parameters of single input to InputCutInfo.
|
|
:param input: input cut parameters of single input
|
|
:return: InputCutInfo
|
|
"""
|
|
if isinstance(input, str):
|
|
# pylint: disable=no-member
|
|
return _InputCutInfo(input, None)
|
|
if isinstance(input, (tuple, list)) or is_shape_type(input):
|
|
# If input represents list with shape, wrap it to list. Single PartialShape also goes to this condition.
|
|
# Check of all dimensions will be in is_shape_type(val) method below
|
|
if is_shape_type(input):
|
|
input = [input]
|
|
|
|
# Check values of tuple or list and collect to InputCutInfo
|
|
name = None
|
|
inp_type = None
|
|
shape = None
|
|
for val in input:
|
|
if isinstance(val, str):
|
|
if name is not None:
|
|
raise Exception("More than one input name provided: {}".format(input))
|
|
name = val
|
|
elif is_type(val):
|
|
if inp_type is not None:
|
|
raise Exception("More than one input type provided: {}".format(input))
|
|
inp_type = to_ov_type(val)
|
|
elif is_shape_type(val) or val is None:
|
|
if shape is not None:
|
|
raise Exception("More than one input shape provided: {}".format(input))
|
|
shape = to_partial_shape(val) if val is not None else None
|
|
else:
|
|
raise Exception("Incorrect input parameters provided. Expected tuple with input name, "
|
|
"input type or input shape. Got unknown object: {}".format(val))
|
|
# pylint: disable=no-member
|
|
return _InputCutInfo(name,
|
|
PartialShape(shape) if shape is not None else None,
|
|
inp_type,
|
|
None)
|
|
# Case when only type is set
|
|
if is_type(input):
|
|
return _InputCutInfo(None, None, to_ov_type(input), None) # pylint: disable=no-member
|
|
|
|
# We don't expect here single unnamed value. If list of int is set it is considered as shape.
|
|
# Setting of value is expected only using InputCutInfo or string analog.
|
|
|
|
raise Exception(
|
|
"Unexpected object provided for input. Expected tuple, Shape, PartialShape, Type or str. Got {}".format(
|
|
type(input)))
|
|
|
|
|
|
def is_single_input(input: [tuple, list]):
|
|
"""
|
|
Checks if input has parameters for single input.
|
|
:param input: list or tuple of input parameters or input shape or input name.
|
|
:return: True if input has parameters for single input, otherwise False.
|
|
"""
|
|
name = None
|
|
inp_type = None
|
|
shape = None
|
|
for val in input:
|
|
if isinstance(val, str):
|
|
if name is not None:
|
|
return False
|
|
name = val
|
|
elif is_type(val):
|
|
if inp_type is not None:
|
|
return False
|
|
inp_type = to_ov_type(val)
|
|
elif is_shape_type(val):
|
|
if shape is not None:
|
|
return False
|
|
shape = to_partial_shape(val)
|
|
else:
|
|
return False
|
|
return True
|
|
|
|
|
|
def parse_inputs(inputs: str):
|
|
inputs_list = []
|
|
# Split to list of string
|
|
for input_value in split_inputs(inputs):
|
|
# Parse string with parameters for single input
|
|
node_name, shape = parse_input_value(input_value)
|
|
# pylint: disable=no-member
|
|
inputs_list.append((node_name, shape))
|
|
return inputs_list
|
|
|
|
|
|
def input_to_input_cut_info(input: [dict, tuple, list]):
|
|
"""
|
|
Parses 'input' to list of InputCutInfo.
|
|
:param input: input cut parameters passed by user
|
|
:return: list of InputCutInfo with input cut parameters
|
|
"""
|
|
if input is None:
|
|
return []
|
|
|
|
if isinstance(input, (tuple, list)):
|
|
if len(input) == 0:
|
|
return []
|
|
# Case when input is single shape set in tuple
|
|
if len(input) > 0 and isinstance(input[0], (int, Dimension)):
|
|
input = [input]
|
|
|
|
if is_single_input(input):
|
|
return [single_input_to_input_cut_info(input)]
|
|
|
|
inputs = []
|
|
for inp in input:
|
|
inputs.append(single_input_to_input_cut_info(inp))
|
|
return inputs
|
|
|
|
if isinstance(input, dict):
|
|
res_list = []
|
|
for name, value in input.items():
|
|
if not isinstance(name, str):
|
|
raise Exception("Incorrect operation name type. Expected string, got {}".format(type(name)))
|
|
info = single_input_to_input_cut_info(value)
|
|
if info.name is not None and info.name != name:
|
|
raise Exception("Incorrect \"input\" dictionary, got different names in key and value. "
|
|
"Got operation name {} for key {}".format(info.name, name))
|
|
res_list.append(_InputCutInfo(name, info.shape, info.type))
|
|
return res_list
|
|
# Case when single type or value is set, or unknown object
|
|
return [single_input_to_input_cut_info(input)]
|
|
|
|
|
|
ParamDescription = namedtuple("ParamData", ["description", "cli_tool_description"])
|
|
|
|
|
|
def get_mo_convert_params():
|
|
mo_convert_docs = openvino.tools.ovc.convert_model.__doc__ # pylint: disable=no-member
|
|
mo_convert_params = {}
|
|
group = "Optional parameters:" # FIXME: WA for unknown bug in this function
|
|
mo_convert_params[group] = {}
|
|
|
|
mo_convert_docs = mo_convert_docs[:mo_convert_docs.find('Returns:')]
|
|
|
|
while len(mo_convert_docs) > 0:
|
|
param_idx1 = mo_convert_docs.find(":param")
|
|
if param_idx1 == -1:
|
|
break
|
|
param_idx2 = mo_convert_docs.find(":", param_idx1 + 1)
|
|
param_name = mo_convert_docs[param_idx1 + len(':param '):param_idx2]
|
|
|
|
param_description_idx = mo_convert_docs.find(":param", param_idx2 + 1)
|
|
param_description = mo_convert_docs[param_idx2 + 1: param_description_idx]
|
|
|
|
group_name_idx = param_description.rfind('\n\n')
|
|
group_name = ''
|
|
if group_name_idx != -1:
|
|
group_name = param_description[group_name_idx:].strip()
|
|
|
|
param_description = param_description[:group_name_idx]
|
|
param_description = param_description.strip()
|
|
|
|
mo_convert_params[group][param_name] = ParamDescription(param_description, "")
|
|
|
|
mo_convert_docs = mo_convert_docs[param_description_idx:]
|
|
|
|
if group_name != '':
|
|
mo_convert_params[group_name] = {}
|
|
group = group_name
|
|
|
|
cli_tool_specific_descriptions = get_convert_model_help_specifics()
|
|
|
|
for group_name, param_group in mo_convert_params.items():
|
|
for param_name, d in param_group.items():
|
|
cli_tool_description = None
|
|
if param_name in cli_tool_specific_descriptions:
|
|
cli_tool_description = cli_tool_specific_descriptions[param_name]
|
|
|
|
desc = ParamDescription(d.description,
|
|
cli_tool_description)
|
|
mo_convert_params[group_name][param_name] = desc
|
|
|
|
return mo_convert_params
|
|
|
|
|
|
def canonicalize_and_check_paths(values: Union[str, list[str], None], param_name,
|
|
try_mo_root=False, check_existence=True) -> list[str]:
|
|
if values is not None:
|
|
list_of_values = list()
|
|
if isinstance(values, str):
|
|
if values != "":
|
|
list_of_values = values.split(',')
|
|
elif isinstance(values, list):
|
|
list_of_values = values
|
|
else:
|
|
return values
|
|
|
|
if not check_existence:
|
|
return [get_absolute_path(path) for path in list_of_values]
|
|
|
|
for idx, val in enumerate(list_of_values):
|
|
if not isinstance(val, (str, pathlib.Path)):
|
|
continue
|
|
|
|
list_of_values[idx] = val
|
|
|
|
error_msg = 'The value for parameter "{}" must be existing file/directory, ' \
|
|
'but "{}" does not exist.'.format(param_name, val)
|
|
if os.path.exists(val):
|
|
continue
|
|
elif not try_mo_root or val == '':
|
|
raise Error(error_msg)
|
|
elif try_mo_root:
|
|
path_from_mo_root = get_mo_root_dir() + '/ovc/' + val
|
|
list_of_values[idx] = path_from_mo_root
|
|
if not os.path.exists(path_from_mo_root):
|
|
raise Error(error_msg)
|
|
|
|
return [get_absolute_path(path) for path in list_of_values]
|
|
|
|
|
|
class CanonicalizePathCheckExistenceAction(argparse.Action):
|
|
"""
|
|
Expand user home directory paths and convert relative-paths to absolute and check specified file or directory
|
|
existence.
|
|
"""
|
|
check_value = canonicalize_and_check_paths
|
|
|
|
def __call__(self, parser, namespace, values, option_string=None):
|
|
list_of_paths = canonicalize_and_check_paths(values, param_name=option_string,
|
|
try_mo_root=False, check_existence=True)
|
|
setattr(namespace, self.dest, list_of_paths)
|
|
|
|
|
|
def readable_file_or_dir_or_object(path: str):
|
|
"""
|
|
Check that specified path is a readable file or directory.
|
|
:param path: path to check
|
|
:return: path if the file/directory is readable
|
|
"""
|
|
if not isinstance(path, (str, pathlib.Path)):
|
|
return path
|
|
if not os.path.isfile(path) and not os.path.isdir(path):
|
|
raise Error('The "{}" is not existing file or directory'.format(path))
|
|
elif not os.access(path, os.R_OK):
|
|
raise Error('The "{}" is not readable'.format(path))
|
|
else:
|
|
return path
|
|
|
|
|
|
def readable_dirs_or_files_or_empty(paths: [str, list, tuple]):
|
|
"""
|
|
Checks that comma separated list of paths are readable directories, files or a provided path is empty.
|
|
:param paths: comma separated list of paths.
|
|
:return: comma separated list of paths.
|
|
"""
|
|
paths_list = paths
|
|
if isinstance(paths, (list, tuple)):
|
|
paths_list = [readable_file_or_dir_or_object(path) for path in paths]
|
|
if isinstance(paths, (str, pathlib.Path)):
|
|
paths_list = [readable_file_or_dir_or_object(path) for path in str(paths).split(',')]
|
|
|
|
return paths_list[0] if isinstance(paths, (list, tuple)) and len(paths_list) == 1 else paths_list
|
|
|
|
|
|
def add_args_by_description(args_group, params_description):
|
|
signature = inspect.signature(openvino.tools.ovc.convert_model) # pylint: disable=no-member
|
|
filepath_args = get_params_with_paths_list()
|
|
cli_tool_specific_descriptions = get_convert_model_help_specifics()
|
|
for param_name, param_description in params_description.items():
|
|
if param_name in ['share_weights', 'example_input']:
|
|
continue
|
|
if param_name == 'input_model':
|
|
# input_model is not a normal key for a tool, it will collect all untagged keys
|
|
cli_param_name = param_name
|
|
else:
|
|
cli_param_name = '--' + param_name
|
|
if cli_param_name not in args_group._option_string_actions:
|
|
# Get parameter specifics
|
|
param_specifics = cli_tool_specific_descriptions[param_name] if param_name in \
|
|
cli_tool_specific_descriptions else {}
|
|
help_text = param_specifics['description'] if 'description' in param_specifics \
|
|
else param_description.description
|
|
action = param_specifics['action'] if 'action' in param_specifics else None
|
|
param_type = param_specifics['type'] if 'type' in param_specifics else None
|
|
param_alias = param_specifics[
|
|
'aliases'] if 'aliases' in param_specifics and param_name != 'input_model' else {}
|
|
param_version = param_specifics['version'] if 'version' in param_specifics else None
|
|
param_choices = param_specifics['choices'] if 'choices' in param_specifics else None
|
|
|
|
# Bool params common setting
|
|
if signature.parameters[param_name].annotation == bool and param_name != 'version':
|
|
args_group.add_argument(
|
|
cli_param_name, *param_alias,
|
|
action='store_true',
|
|
help=help_text,
|
|
default=signature.parameters[param_name].default)
|
|
# File paths common setting
|
|
elif param_name in filepath_args:
|
|
action = action if action is not None else CanonicalizePathCheckExistenceAction
|
|
args_group.add_argument(
|
|
cli_param_name, *param_alias,
|
|
type=str if param_type is None else param_type,
|
|
action=action,
|
|
help=help_text,
|
|
default=None if param_name == 'input_model' else signature.parameters[param_name].default,
|
|
metavar=param_name.upper() if param_name == 'input_model' else None)
|
|
# Other params
|
|
else:
|
|
additional_params = {}
|
|
if param_version is not None:
|
|
additional_params['version'] = param_version
|
|
if param_type is not None:
|
|
additional_params['type'] = param_type
|
|
if param_choices is not None:
|
|
additional_params['choices'] = param_choices
|
|
args_group.add_argument(
|
|
cli_param_name, *param_alias,
|
|
help=help_text,
|
|
default=signature.parameters[param_name].default,
|
|
action=action,
|
|
**additional_params
|
|
)
|
|
|
|
|
|
class Formatter(argparse.HelpFormatter):
|
|
def _format_usage(self, usage, actions, groups, prefix):
|
|
usage = argparse.HelpFormatter._format_usage(self, usage, actions, groups, prefix)
|
|
usage = usage[0:usage.find('INPUT_MODEL')].rstrip() + '\n'
|
|
insert_idx = usage.find(self._prog) + len(self._prog)
|
|
usage = usage[0: insert_idx] + ' INPUT_MODEL... ' + usage[insert_idx + 1:]
|
|
return usage
|
|
|
|
def _get_default_metavar_for_optional(self, action):
|
|
if action.option_strings == ['--compress_to_fp16']:
|
|
return "True | False"
|
|
return argparse.HelpFormatter._get_default_metavar_for_optional(self, action)
|
|
|
|
|
|
def get_common_cli_parser(parser: argparse.ArgumentParser = None):
|
|
if not parser:
|
|
parser = argparse.ArgumentParser(formatter_class=Formatter)
|
|
mo_convert_params = get_mo_convert_params()
|
|
mo_convert_params_common = mo_convert_params['Optional parameters:']
|
|
|
|
from openvino.tools.ovc.version import VersionChecker
|
|
|
|
# Command line tool specific params
|
|
parser.add_argument('--output_model',
|
|
help='This parameter is used to name output .xml/.bin files of converted model. '
|
|
'Model name or output directory can be passed. If output directory is passed, '
|
|
'the resulting .xml/.bin files are named by original model name.')
|
|
parser.add_argument('--compress_to_fp16', type=check_bool, default=True, nargs='?',
|
|
help='Compress weights in output OpenVINO model to FP16. '
|
|
'To turn off compression use "--compress_to_fp16=False" command line parameter. '
|
|
'Default value is True.')
|
|
parser.add_argument('--version', action='version',
|
|
help='Print ovc version and exit.',
|
|
version='OpenVINO Model Converter (ovc) {}'.format(VersionChecker().get_ie_version()))
|
|
add_args_by_description(parser, mo_convert_params_common)
|
|
return parser
|
|
|
|
|
|
def input_model_details(model):
|
|
if isinstance(model, (list, tuple)) and len(model) == 1:
|
|
model = model[0]
|
|
if isinstance(model, (str, pathlib.Path)):
|
|
return model
|
|
return type(model)
|
|
|
|
|
|
def get_common_cli_options(argv, is_python_api_used):
|
|
d = OrderedDict()
|
|
d['input_model'] = ['- Input Model', input_model_details]
|
|
if not is_python_api_used:
|
|
model_name = get_model_name_from_args(argv)
|
|
d['output_model'] = ['- IR output name', lambda _: model_name]
|
|
d['input'] = ['- Input layers', lambda x: x if x else 'Not specified, inherited from the model']
|
|
d['output'] = ['- Output layers', lambda x: x if x else 'Not specified, inherited from the model']
|
|
return d
|
|
|
|
|
|
def get_params_with_paths_list():
|
|
return ['input_model', 'output_model', 'extension']
|
|
|
|
|
|
def get_all_cli_parser():
|
|
"""
|
|
Specifies cli arguments for Model Conversion
|
|
|
|
Returns
|
|
-------
|
|
ArgumentParser instance
|
|
"""
|
|
parser = argparse.ArgumentParser(formatter_class=Formatter)
|
|
|
|
get_common_cli_parser(parser=parser)
|
|
|
|
return parser
|
|
|
|
|
|
def remove_shape_from_input_value(input_value: str):
|
|
"""
|
|
Removes the shape specification from the input string. The shape specification is a string enclosed with square
|
|
brackets.
|
|
:param input_value: string passed as input to the "input" command line parameter
|
|
:return: string without shape specification
|
|
"""
|
|
if '->' in input_value:
|
|
raise Error('Incorrect format of input. Got {}'.format(input_value))
|
|
return re.sub(r'[(\[]([0-9\.?, -]*)[)\]]', '', input_value)
|
|
|
|
|
|
def get_shape_from_input_value(input_value: str):
|
|
"""
|
|
Returns PartialShape corresponding to the shape specified in the input value string
|
|
:param input_value: string passed as input to the "input" command line parameter
|
|
:return: the corresponding shape and None if the shape is not specified in the input value
|
|
"""
|
|
|
|
# parse shape
|
|
shape = re.findall(r'[(\[]([0-9\.\?, -]*)[)\]]', input_value)
|
|
if len(shape) == 0:
|
|
shape = None
|
|
elif len(shape) == 1 and shape[0] in ['', ' ']:
|
|
# this shape corresponds to scalar
|
|
shape = PartialShape([])
|
|
elif len(shape) == 1:
|
|
dims = re.split(r', *| +', shape[0])
|
|
dims = list(filter(None, dims))
|
|
shape = PartialShape([Dimension(dim) for dim in dims])
|
|
else:
|
|
raise Error("Wrong syntax to specify shape. Use \"input\" "
|
|
"\"node_name[shape]\"")
|
|
return shape
|
|
|
|
|
|
def get_node_name_with_port_from_input_value(input_value: str):
|
|
"""
|
|
Returns the node name (optionally with input/output port) from the input value
|
|
:param input_value: string passed as input to the "input" command line parameter
|
|
:return: the corresponding node name with input/output port
|
|
"""
|
|
return remove_shape_from_input_value(input_value)
|
|
|
|
|
|
def parse_input_value(input_value: str):
|
|
"""
|
|
Parses a value of the "input" command line parameter and gets a node name, shape and value.
|
|
The node name includes a port if it is specified.
|
|
Shape and value is equal to None if they are not specified.
|
|
Parameters
|
|
----------
|
|
input_value
|
|
string with a specified node name and shape.
|
|
E.g. 'node_name:0[4]'
|
|
|
|
Returns
|
|
-------
|
|
Node name, shape, value, data type
|
|
E.g. 'node_name:0', '4', [1.0 2.0 3.0 4.0], np.float32
|
|
"""
|
|
node_name = get_node_name_with_port_from_input_value(input_value)
|
|
shape = get_shape_from_input_value(input_value)
|
|
|
|
return node_name if node_name else None, shape
|
|
|
|
|
|
def split_inputs(input_str):
|
|
pattern = r'^(?:[^[\]()<]*(\[[\.)-9,\-\s?]*\])*,)*[^[\]()<]*(\[[\.0-9,\-\s?]*\])*$'
|
|
if not re.match(pattern, input_str):
|
|
raise Error(f"input value '{input_str}' is incorrect. Input should be in the following format: "
|
|
f"{get_convert_model_help_specifics()['input']['description']}")
|
|
|
|
brakets_count = 0
|
|
inputs = []
|
|
while input_str:
|
|
idx = 0
|
|
for c in input_str:
|
|
if c == '[':
|
|
brakets_count += 1
|
|
if c == ']':
|
|
brakets_count -= 1
|
|
if c == ',':
|
|
if brakets_count != 0:
|
|
idx += 1
|
|
continue
|
|
else:
|
|
break
|
|
idx += 1
|
|
if idx >= len(input_str) - 1:
|
|
inputs.append(input_str)
|
|
break
|
|
inputs.append(input_str[:idx])
|
|
input_str = input_str[idx + 1:]
|
|
return inputs
|
|
|
|
|
|
def get_model_name(path_input_model: str) -> str:
|
|
"""
|
|
Deduces model name by a given path to the input model
|
|
Args:
|
|
path_input_model: path to the input model
|
|
|
|
Returns:
|
|
name of the output IR
|
|
"""
|
|
parsed_name, extension = os.path.splitext(os.path.basename(path_input_model))
|
|
return 'model' if parsed_name.startswith('.') or len(parsed_name) == 0 else parsed_name
|
|
|
|
|
|
def get_model_name_from_args(argv: argparse.Namespace):
|
|
output_dir = os.getcwd()
|
|
if hasattr(argv, 'output_model') and argv.output_model:
|
|
model_name = argv.output_model
|
|
|
|
if not os.path.isdir(argv.output_model) and not argv.output_model.endswith(os.sep):
|
|
# In this branch we assume that model name is set in 'output_model'.
|
|
if not model_name.endswith('.xml'):
|
|
model_name += '.xml'
|
|
# Logic of creating and checking directory is covered in save_model() method.
|
|
return model_name
|
|
else:
|
|
# In this branch 'output_model' has directory without name of model.
|
|
# The directory may not exist.
|
|
if os.path.isdir(argv.output_model) and not os.access(argv.output_model, os.W_OK):
|
|
# If the provided path is existing directory, but not writable, then raise error
|
|
raise Error('The directory "{}" is not writable'.format(argv.output_model))
|
|
output_dir = argv.output_model
|
|
|
|
input_model = argv.input_model
|
|
if isinstance(input_model, (tuple, list)) and len(input_model) > 0:
|
|
input_model = input_model[0]
|
|
|
|
input_model = os.path.abspath(input_model)
|
|
|
|
if not isinstance(input_model, (str, pathlib.Path)):
|
|
return output_dir
|
|
|
|
input_model_name = os.path.basename(input_model)
|
|
if input_model_name == '':
|
|
input_model_name = os.path.basename(os.path.dirname(input_model))
|
|
|
|
# remove extension if exists
|
|
input_model_name = os.path.splitext(input_model_name)[0]
|
|
|
|
# if no valid name exists in input path set name to 'model'
|
|
if input_model_name == '':
|
|
raise Exception("Could not derive model name from input model. Please provide 'output_model' parameter.")
|
|
|
|
# add .xml extension
|
|
return os.path.join(output_dir, input_model_name + ".xml")
|
|
|
|
|
|
def get_absolute_path(path_to_file: str) -> str:
|
|
"""
|
|
Deduces absolute path of the file by a given path to the file
|
|
Args:
|
|
path_to_file: path to the file
|
|
|
|
Returns:
|
|
absolute path of the file
|
|
"""
|
|
if not isinstance(path_to_file, (str, pathlib.Path)):
|
|
return path_to_file
|
|
file_path = os.path.expanduser(path_to_file)
|
|
if not os.path.isabs(file_path):
|
|
file_path = os.path.join(os.getcwd(), file_path)
|
|
return file_path
|
|
|
|
|
|
def check_bool(value):
|
|
if isinstance(value, bool):
|
|
return value
|
|
elif isinstance(value, str):
|
|
if value.lower() not in ['true', 'false']:
|
|
raise argparse.ArgumentTypeError("expected a True/False value")
|
|
return value.lower() == 'true'
|
|
else:
|
|
raise argparse.ArgumentTypeError("expected a bool or str type")
|
|
|
|
|
|
def depersonalize(value: str, key: str):
|
|
dir_keys = [
|
|
'extension'
|
|
]
|
|
if isinstance(value, list):
|
|
updated_value = []
|
|
for elem in value:
|
|
updated_value.append(depersonalize(elem, key))
|
|
return updated_value
|
|
|
|
if not isinstance(value, str):
|
|
return value
|
|
res = []
|
|
for path in value.split(','):
|
|
if os.path.isdir(path) and key in dir_keys:
|
|
res.append('DIR')
|
|
elif os.path.isfile(path):
|
|
res.append(os.path.join('DIR', os.path.split(path)[1]))
|
|
else:
|
|
res.append(path)
|
|
return ','.join(res)
|
|
|
|
|
|
def get_available_front_ends(fem=None):
|
|
# Use this function as workaround to avoid IR frontend usage by OVC
|
|
if fem is None:
|
|
return []
|
|
available_moc_front_ends = fem.get_available_front_ends()
|
|
if 'ir' in available_moc_front_ends:
|
|
available_moc_front_ends.remove('ir')
|
|
|
|
return available_moc_front_ends
|