mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
597 lines
20 KiB
Python
597 lines
20 KiB
Python
import copy
|
|
from .input_entities import InputEntity
|
|
from .exceptions import EntitySchemaError
|
|
from .lib import (
|
|
NOT_SET,
|
|
STRING_TYPE
|
|
)
|
|
|
|
|
|
class BaseEnumEntity(InputEntity):
|
|
def _item_initialization(self):
|
|
self.multiselection = True
|
|
self.value_on_not_set = None
|
|
self.enum_items = None
|
|
self.valid_keys = None
|
|
self.valid_value_types = None
|
|
self.placeholder = None
|
|
|
|
def schema_validations(self):
|
|
if not isinstance(self.enum_items, list):
|
|
raise EntitySchemaError(
|
|
self, "Enum item must have defined `enum_items` as list."
|
|
)
|
|
|
|
enum_keys = set()
|
|
for item in self.enum_items:
|
|
key = tuple(item.keys())[0]
|
|
if key in enum_keys:
|
|
reason = "Key \"{}\" is more than once in enum items.".format(
|
|
key
|
|
)
|
|
raise EntitySchemaError(self, reason)
|
|
|
|
enum_keys.add(key)
|
|
|
|
if not isinstance(key, STRING_TYPE):
|
|
reason = "Key \"{}\" has invalid type {}, expected {}.".format(
|
|
key, type(key), STRING_TYPE
|
|
)
|
|
raise EntitySchemaError(self, reason)
|
|
|
|
super(BaseEnumEntity, self).schema_validations()
|
|
|
|
def _convert_to_valid_type(self, value):
|
|
if self.multiselection:
|
|
if isinstance(value, (set, tuple)):
|
|
return list(value)
|
|
elif isinstance(value, (int, float)):
|
|
return str(value)
|
|
return NOT_SET
|
|
|
|
def set(self, value):
|
|
new_value = self.convert_to_valid_type(value)
|
|
if self.multiselection:
|
|
check_values = new_value
|
|
else:
|
|
check_values = [new_value]
|
|
|
|
for item in check_values:
|
|
if item not in self.valid_keys:
|
|
raise ValueError(
|
|
"{} Invalid value \"{}\". Expected one of: {}".format(
|
|
self.path, item, self.valid_keys
|
|
)
|
|
)
|
|
self._current_value = new_value
|
|
self._on_value_change()
|
|
|
|
|
|
class EnumEntity(BaseEnumEntity):
|
|
schema_types = ["enum"]
|
|
|
|
def _item_initialization(self):
|
|
self.multiselection = self.schema_data.get("multiselection", False)
|
|
self.enum_items = self.schema_data.get("enum_items")
|
|
# Default is optional and non breaking attribute
|
|
enum_default = self.schema_data.get("default")
|
|
|
|
all_keys = []
|
|
for item in self.enum_items or []:
|
|
key = tuple(item.keys())[0]
|
|
all_keys.append(key)
|
|
|
|
self.valid_keys = set(all_keys)
|
|
|
|
if self.multiselection:
|
|
self.valid_value_types = (list, )
|
|
value_on_not_set = []
|
|
if enum_default:
|
|
if not isinstance(enum_default, list):
|
|
enum_default = [enum_default]
|
|
|
|
for item in enum_default:
|
|
if item in all_keys:
|
|
value_on_not_set.append(item)
|
|
|
|
self.value_on_not_set = value_on_not_set
|
|
|
|
else:
|
|
if isinstance(enum_default, list) and enum_default:
|
|
enum_default = enum_default[0]
|
|
|
|
if enum_default in self.valid_keys:
|
|
self.value_on_not_set = enum_default
|
|
|
|
else:
|
|
for key in all_keys:
|
|
if self.value_on_not_set is NOT_SET:
|
|
self.value_on_not_set = key
|
|
break
|
|
|
|
self.valid_value_types = (STRING_TYPE, )
|
|
|
|
# GUI attribute
|
|
self.placeholder = self.schema_data.get("placeholder")
|
|
|
|
def schema_validations(self):
|
|
if not self.enum_items and "enum_items" not in self.schema_data:
|
|
raise EntitySchemaError(
|
|
self, "Enum item must have defined `enum_items`"
|
|
)
|
|
super(EnumEntity, self).schema_validations()
|
|
|
|
def set_override_state(self, *args, **kwargs):
|
|
super(EnumEntity, self).set_override_state(*args, **kwargs)
|
|
|
|
# Make sure current value is valid
|
|
if self.multiselection:
|
|
new_value = []
|
|
for key in self._current_value:
|
|
if key in self.valid_keys:
|
|
new_value.append(key)
|
|
self._current_value = new_value
|
|
|
|
elif self._current_value not in self.valid_keys:
|
|
self._current_value = self.value_on_not_set
|
|
|
|
|
|
class HostsEnumEntity(BaseEnumEntity):
|
|
"""Enumeration of host names.
|
|
|
|
Enum items are hardcoded in definition of the entity.
|
|
|
|
Hosts enum can have defined empty value as valid option which is
|
|
represented by empty string. Schema key to set this option is
|
|
`use_empty_value` (true/false). And to set label of empty value set
|
|
`empty_label` (string).
|
|
|
|
Enum can have single and multiselection.
|
|
|
|
NOTE:
|
|
Host name is not the same as application name. Host name defines
|
|
implementation instead of application name.
|
|
"""
|
|
schema_types = ["hosts-enum"]
|
|
all_host_names = [
|
|
"aftereffects",
|
|
"blender",
|
|
"celaction",
|
|
"flame",
|
|
"fusion",
|
|
"harmony",
|
|
"hiero",
|
|
"houdini",
|
|
"maya",
|
|
"nuke",
|
|
"photoshop",
|
|
"resolve",
|
|
"tvpaint",
|
|
"unreal",
|
|
"standalonepublisher",
|
|
"traypublisher",
|
|
"webpublisher"
|
|
]
|
|
|
|
def _item_initialization(self):
|
|
self.multiselection = self.schema_data.get("multiselection", True)
|
|
use_empty_value = False
|
|
if not self.multiselection:
|
|
use_empty_value = self.schema_data.get(
|
|
"use_empty_value", use_empty_value
|
|
)
|
|
self.use_empty_value = use_empty_value
|
|
|
|
hosts_filter = self.schema_data.get("hosts_filter") or []
|
|
self.hosts_filter = hosts_filter
|
|
|
|
custom_labels = self.schema_data.get("custom_labels") or {}
|
|
|
|
host_names = copy.deepcopy(self.all_host_names)
|
|
if hosts_filter:
|
|
for host_name in tuple(host_names):
|
|
if host_name not in hosts_filter:
|
|
host_names.remove(host_name)
|
|
|
|
if self.use_empty_value:
|
|
host_names.insert(0, "")
|
|
# Add default label for empty value if not available
|
|
if "" not in custom_labels:
|
|
custom_labels[""] = "< without host >"
|
|
|
|
# These are hardcoded there is not list of available host in OpenPype
|
|
enum_items = []
|
|
valid_keys = set()
|
|
for key in host_names:
|
|
label = custom_labels.get(key, key)
|
|
valid_keys.add(key)
|
|
enum_items.append({key: label})
|
|
|
|
self.enum_items = enum_items
|
|
self.valid_keys = valid_keys
|
|
|
|
if self.multiselection:
|
|
self.valid_value_types = (list, )
|
|
self.value_on_not_set = []
|
|
else:
|
|
for key in valid_keys:
|
|
if self.value_on_not_set is NOT_SET:
|
|
self.value_on_not_set = key
|
|
break
|
|
|
|
self.valid_value_types = (STRING_TYPE, )
|
|
|
|
# GUI attribute
|
|
self.placeholder = self.schema_data.get("placeholder")
|
|
|
|
def schema_validations(self):
|
|
if self.hosts_filter:
|
|
enum_len = len(self.enum_items)
|
|
if (
|
|
enum_len == 0
|
|
or (enum_len == 1 and self.use_empty_value)
|
|
):
|
|
joined_filters = ", ".join([
|
|
'"{}"'.format(item)
|
|
for item in self.hosts_filter
|
|
])
|
|
reason = (
|
|
"All host names were removed after applying"
|
|
" host filters. {}"
|
|
).format(joined_filters)
|
|
raise EntitySchemaError(self, reason)
|
|
|
|
invalid_filters = set()
|
|
for item in self.hosts_filter:
|
|
if item not in self.all_host_names:
|
|
invalid_filters.add(item)
|
|
|
|
if invalid_filters:
|
|
joined_filters = ", ".join([
|
|
'"{}"'.format(item)
|
|
for item in self.hosts_filter
|
|
])
|
|
expected_hosts = ", ".join([
|
|
'"{}"'.format(item)
|
|
for item in self.all_host_names
|
|
])
|
|
self.log.warning((
|
|
"Host filters containt invalid host names:"
|
|
" \"{}\" Expected values are {}"
|
|
).format(joined_filters, expected_hosts))
|
|
|
|
super(HostsEnumEntity, self).schema_validations()
|
|
|
|
|
|
class AppsEnumEntity(BaseEnumEntity):
|
|
"""Enum of applications for project anatomy attributes."""
|
|
schema_types = ["apps-enum"]
|
|
|
|
def _item_initialization(self):
|
|
self.multiselection = True
|
|
self.value_on_not_set = []
|
|
self.enum_items = []
|
|
self.valid_keys = set()
|
|
self.valid_value_types = (list, )
|
|
self.placeholder = None
|
|
|
|
def _get_enum_values(self):
|
|
system_settings_entity = self.get_entity_from_path("system_settings")
|
|
|
|
valid_keys = set()
|
|
enum_items_list = []
|
|
applications_entity = system_settings_entity["applications"]
|
|
app_entities = {}
|
|
additional_app_names = set()
|
|
additional_apps_entity = None
|
|
for group_name, app_group in applications_entity.items():
|
|
if group_name != "additional_apps":
|
|
app_entities[group_name] = app_group
|
|
continue
|
|
|
|
additional_apps_entity = app_group
|
|
for _group_name, _group in app_group.items():
|
|
additional_app_names.add(_group_name)
|
|
app_entities[_group_name] = _group
|
|
|
|
for group_name, app_group in app_entities.items():
|
|
enabled_entity = app_group.get("enabled")
|
|
if enabled_entity and not enabled_entity.value:
|
|
continue
|
|
|
|
if group_name in additional_app_names:
|
|
group_label = additional_apps_entity.get_key_label(group_name)
|
|
if not group_label:
|
|
group_label = group_name
|
|
else:
|
|
group_label = app_group["label"].value
|
|
variants_entity = app_group["variants"]
|
|
for variant_name, variant_entity in variants_entity.items():
|
|
enabled_entity = variant_entity.get("enabled")
|
|
if enabled_entity and not enabled_entity.value:
|
|
continue
|
|
|
|
variant_label = None
|
|
if "variant_label" in variant_entity:
|
|
variant_label = variant_entity["variant_label"].value
|
|
elif hasattr(variants_entity, "get_key_label"):
|
|
variant_label = variants_entity.get_key_label(variant_name)
|
|
|
|
if not variant_label:
|
|
variant_label = variant_name
|
|
|
|
if group_label:
|
|
full_label = "{} {}".format(group_label, variant_label)
|
|
else:
|
|
full_label = variant_label
|
|
|
|
full_name = "/".join((group_name, variant_name))
|
|
enum_items_list.append((full_name, full_label))
|
|
valid_keys.add(full_name)
|
|
|
|
enum_items = []
|
|
for key, value in sorted(enum_items_list, key=lambda item: item[1]):
|
|
enum_items.append({key: value})
|
|
return enum_items, valid_keys
|
|
|
|
def set_override_state(self, *args, **kwargs):
|
|
super(AppsEnumEntity, self).set_override_state(*args, **kwargs)
|
|
|
|
self.enum_items, self.valid_keys = self._get_enum_values()
|
|
new_value = []
|
|
for key in self._current_value:
|
|
if key in self.valid_keys:
|
|
new_value.append(key)
|
|
self._current_value = new_value
|
|
|
|
|
|
class ToolsEnumEntity(BaseEnumEntity):
|
|
schema_types = ["tools-enum"]
|
|
|
|
def _item_initialization(self):
|
|
self.multiselection = True
|
|
self.value_on_not_set = []
|
|
self.enum_items = []
|
|
self.valid_keys = set()
|
|
self.valid_value_types = (list, )
|
|
self.placeholder = None
|
|
|
|
def _get_enum_values(self):
|
|
system_settings_entity = self.get_entity_from_path("system_settings")
|
|
|
|
valid_keys = set()
|
|
enum_items_list = []
|
|
tool_groups_entity = system_settings_entity["tools"]["tool_groups"]
|
|
for group_name, tool_group in tool_groups_entity.items():
|
|
# Try to get group label from entity
|
|
group_label = None
|
|
if hasattr(tool_groups_entity, "get_key_label"):
|
|
group_label = tool_groups_entity.get_key_label(group_name)
|
|
|
|
variants_entity = tool_group["variants"]
|
|
for variant_name in variants_entity.keys():
|
|
# Prepare tool name (used as value)
|
|
tool_name = "/".join((group_name, variant_name))
|
|
|
|
# Try to get variant label from entity
|
|
variant_label = None
|
|
if hasattr(variants_entity, "get_key_label"):
|
|
variant_label = variants_entity.get_key_label(variant_name)
|
|
|
|
# Tool label that will be shown
|
|
# - use tool name itself if labels are not filled
|
|
if group_label and variant_label:
|
|
tool_label = " ".join((group_label, variant_label))
|
|
else:
|
|
tool_label = tool_name
|
|
|
|
enum_items_list.append((tool_name, tool_label))
|
|
valid_keys.add(tool_name)
|
|
|
|
enum_items = []
|
|
for key, value in sorted(enum_items_list, key=lambda item: item[1]):
|
|
enum_items.append({key: value})
|
|
return enum_items, valid_keys
|
|
|
|
def set_override_state(self, *args, **kwargs):
|
|
super(ToolsEnumEntity, self).set_override_state(*args, **kwargs)
|
|
|
|
self.enum_items, self.valid_keys = self._get_enum_values()
|
|
new_value = []
|
|
for key in self._current_value:
|
|
if key in self.valid_keys:
|
|
new_value.append(key)
|
|
self._current_value = new_value
|
|
|
|
|
|
class TaskTypeEnumEntity(BaseEnumEntity):
|
|
schema_types = ["task-types-enum"]
|
|
|
|
def _item_initialization(self):
|
|
self.multiselection = self.schema_data.get("multiselection", True)
|
|
if self.multiselection:
|
|
self.valid_value_types = (list, )
|
|
self.value_on_not_set = []
|
|
else:
|
|
self.valid_value_types = (STRING_TYPE, )
|
|
self.value_on_not_set = ""
|
|
|
|
self.enum_items = []
|
|
self.valid_keys = set()
|
|
self.placeholder = None
|
|
|
|
def _get_enum_values(self):
|
|
anatomy_entity = self.get_entity_from_path(
|
|
"project_settings/project_anatomy"
|
|
)
|
|
|
|
valid_keys = set()
|
|
enum_items = []
|
|
for task_type in anatomy_entity["tasks"].keys():
|
|
enum_items.append({task_type: task_type})
|
|
valid_keys.add(task_type)
|
|
|
|
return enum_items, valid_keys
|
|
|
|
def _convert_value_for_current_state(self, source_value):
|
|
if self.multiselection:
|
|
output = []
|
|
for key in source_value:
|
|
if key in self.valid_keys:
|
|
output.append(key)
|
|
return output
|
|
|
|
if source_value not in self.valid_keys:
|
|
# Take first item from enum items
|
|
for item in self.enum_items:
|
|
for key in item.keys():
|
|
source_value = key
|
|
break
|
|
return source_value
|
|
|
|
def set_override_state(self, *args, **kwargs):
|
|
super(TaskTypeEnumEntity, self).set_override_state(*args, **kwargs)
|
|
|
|
self.enum_items, self.valid_keys = self._get_enum_values()
|
|
|
|
if self.multiselection:
|
|
new_value = []
|
|
for key in self._current_value:
|
|
if key in self.valid_keys:
|
|
new_value.append(key)
|
|
|
|
if self._current_value != new_value:
|
|
self.set(new_value)
|
|
else:
|
|
if not self.enum_items:
|
|
self.valid_keys.add("")
|
|
self.enum_items.append({"": "< Empty >"})
|
|
|
|
for item in self.enum_items:
|
|
for key in item.keys():
|
|
value_on_not_set = key
|
|
break
|
|
|
|
self.value_on_not_set = value_on_not_set
|
|
if (
|
|
self._current_value is NOT_SET
|
|
or self._current_value not in self.valid_keys
|
|
):
|
|
self.set(value_on_not_set)
|
|
|
|
|
|
class DeadlineUrlEnumEntity(BaseEnumEntity):
|
|
schema_types = ["deadline_url-enum"]
|
|
|
|
def _item_initialization(self):
|
|
self.multiselection = self.schema_data.get("multiselection", True)
|
|
|
|
self.enum_items = []
|
|
self.valid_keys = set()
|
|
|
|
if self.multiselection:
|
|
self.valid_value_types = (list,)
|
|
self.value_on_not_set = []
|
|
else:
|
|
self.valid_value_types = (STRING_TYPE,)
|
|
self.value_on_not_set = ""
|
|
|
|
# GUI attribute
|
|
self.placeholder = self.schema_data.get("placeholder")
|
|
|
|
def _get_enum_values(self):
|
|
deadline_urls_entity = self.get_entity_from_path(
|
|
"system_settings/modules/deadline/deadline_urls"
|
|
)
|
|
|
|
valid_keys = set()
|
|
enum_items_list = []
|
|
for server_name, url_entity in deadline_urls_entity.items():
|
|
enum_items_list.append(
|
|
{server_name: "{}: {}".format(server_name, url_entity.value)})
|
|
valid_keys.add(server_name)
|
|
return enum_items_list, valid_keys
|
|
|
|
def set_override_state(self, *args, **kwargs):
|
|
super(DeadlineUrlEnumEntity, self).set_override_state(*args, **kwargs)
|
|
|
|
self.enum_items, self.valid_keys = self._get_enum_values()
|
|
if self.multiselection:
|
|
new_value = []
|
|
for key in self._current_value:
|
|
if key in self.valid_keys:
|
|
new_value.append(key)
|
|
self._current_value = new_value
|
|
|
|
else:
|
|
if not self.valid_keys:
|
|
self._current_value = ""
|
|
|
|
elif self._current_value not in self.valid_keys:
|
|
self._current_value = tuple(self.valid_keys)[0]
|
|
|
|
|
|
class AnatomyTemplatesEnumEntity(BaseEnumEntity):
|
|
schema_types = ["anatomy-templates-enum"]
|
|
|
|
def _item_initialization(self):
|
|
self.multiselection = False
|
|
|
|
self.enum_items = []
|
|
self.valid_keys = set()
|
|
|
|
enum_default = self.schema_data.get("default") or "work"
|
|
|
|
self.value_on_not_set = enum_default
|
|
self.valid_value_types = (STRING_TYPE,)
|
|
|
|
# GUI attribute
|
|
self.placeholder = self.schema_data.get("placeholder")
|
|
|
|
def _get_enum_values(self):
|
|
templates_entity = self.get_entity_from_path(
|
|
"project_anatomy/templates"
|
|
)
|
|
|
|
valid_keys = set()
|
|
enum_items_list = []
|
|
|
|
others_entity = None
|
|
for key, entity in templates_entity.items():
|
|
# Skip defaults key
|
|
if key == "defaults":
|
|
continue
|
|
|
|
if key == "others":
|
|
others_entity = entity
|
|
continue
|
|
|
|
label = key
|
|
if hasattr(entity, "label"):
|
|
label = entity.label or label
|
|
|
|
enum_items_list.append({key: label})
|
|
valid_keys.add(key)
|
|
|
|
if others_entity is not None:
|
|
get_child_label_func = getattr(
|
|
others_entity, "get_child_label", None
|
|
)
|
|
for key, child_entity in others_entity.items():
|
|
label = key
|
|
if callable(get_child_label_func):
|
|
label = get_child_label_func(child_entity) or label
|
|
|
|
enum_items_list.append({key: label})
|
|
valid_keys.add(key)
|
|
|
|
return enum_items_list, valid_keys
|
|
|
|
def set_override_state(self, *args, **kwargs):
|
|
super(AnatomyTemplatesEnumEntity, self).set_override_state(
|
|
*args, **kwargs
|
|
)
|
|
|
|
self.enum_items, self.valid_keys = self._get_enum_values()
|
|
if self._current_value not in self.valid_keys:
|
|
self._current_value = self.value_on_not_set
|