mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-01 16:34:53 +01:00
Merge pull request #2184 from pypeclub/feature/OP-1938_Project-roots-entity-for-settings
Settings: Dictionary based on project roots
This commit is contained in:
commit
c6b2788274
12 changed files with 226 additions and 26 deletions
|
|
@ -110,7 +110,10 @@ from .enum_entity import (
|
|||
)
|
||||
|
||||
from .list_entity import ListEntity
|
||||
from .dict_immutable_keys_entity import DictImmutableKeysEntity
|
||||
from .dict_immutable_keys_entity import (
|
||||
DictImmutableKeysEntity,
|
||||
RootsDictEntity
|
||||
)
|
||||
from .dict_mutable_keys_entity import DictMutableKeysEntity
|
||||
from .dict_conditional import (
|
||||
DictConditionalEntity,
|
||||
|
|
@ -169,6 +172,7 @@ __all__ = (
|
|||
"ListEntity",
|
||||
|
||||
"DictImmutableKeysEntity",
|
||||
"RootsDictEntity",
|
||||
|
||||
"DictMutableKeysEntity",
|
||||
|
||||
|
|
|
|||
|
|
@ -510,7 +510,7 @@ class BaseItemEntity(BaseEntity):
|
|||
pass
|
||||
|
||||
@abstractmethod
|
||||
def _item_initalization(self):
|
||||
def _item_initialization(self):
|
||||
"""Entity specific initialization process."""
|
||||
pass
|
||||
|
||||
|
|
@ -920,7 +920,7 @@ class ItemEntity(BaseItemEntity):
|
|||
_default_label_wrap["collapsed"]
|
||||
)
|
||||
|
||||
self._item_initalization()
|
||||
self._item_initialization()
|
||||
|
||||
def save(self):
|
||||
"""Call save on root item."""
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ from .exceptions import (
|
|||
class ColorEntity(InputEntity):
|
||||
schema_types = ["color"]
|
||||
|
||||
def _item_initalization(self):
|
||||
def _item_initialization(self):
|
||||
self.valid_value_types = (list, )
|
||||
self.value_on_not_set = [0, 0, 0, 255]
|
||||
self.use_alpha = self.schema_data.get("use_alpha", True)
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ class DictConditionalEntity(ItemEntity):
|
|||
for _key, _value in new_value.items():
|
||||
self.non_gui_children[self.current_enum][_key].set(_value)
|
||||
|
||||
def _item_initalization(self):
|
||||
def _item_initialization(self):
|
||||
self._default_metadata = NOT_SET
|
||||
self._studio_override_metadata = NOT_SET
|
||||
self._project_override_metadata = NOT_SET
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ import collections
|
|||
from .lib import (
|
||||
WRAPPER_TYPES,
|
||||
OverrideState,
|
||||
NOT_SET
|
||||
NOT_SET,
|
||||
STRING_TYPE
|
||||
)
|
||||
from openpype.settings.constants import (
|
||||
METADATA_KEYS,
|
||||
|
|
@ -18,6 +19,7 @@ from . import (
|
|||
GUIEntity
|
||||
)
|
||||
from .exceptions import (
|
||||
DefaultsNotDefined,
|
||||
SchemaDuplicatedKeys,
|
||||
EntitySchemaError,
|
||||
InvalidKeySymbols
|
||||
|
|
@ -172,7 +174,7 @@ class DictImmutableKeysEntity(ItemEntity):
|
|||
for child_obj in added_children:
|
||||
self.gui_layout.append(child_obj)
|
||||
|
||||
def _item_initalization(self):
|
||||
def _item_initialization(self):
|
||||
self._default_metadata = NOT_SET
|
||||
self._studio_override_metadata = NOT_SET
|
||||
self._project_override_metadata = NOT_SET
|
||||
|
|
@ -547,3 +549,178 @@ class DictImmutableKeysEntity(ItemEntity):
|
|||
super(DictImmutableKeysEntity, self).reset_callbacks()
|
||||
for child_entity in self.children:
|
||||
child_entity.reset_callbacks()
|
||||
|
||||
|
||||
class RootsDictEntity(DictImmutableKeysEntity):
|
||||
"""Entity that adds ability to fill value for roots of current project.
|
||||
|
||||
Value schema is defined by `object_type`.
|
||||
|
||||
It is not possible to change override state (Studio values will always
|
||||
contain studio overrides and same for project). That is because roots can
|
||||
be totally different for each project.
|
||||
"""
|
||||
_origin_schema_data = None
|
||||
schema_types = ["dict-roots"]
|
||||
|
||||
def _item_initialization(self):
|
||||
origin_schema_data = self.schema_data
|
||||
|
||||
self.separate_items = origin_schema_data.get("separate_items", True)
|
||||
object_type = origin_schema_data.get("object_type")
|
||||
if isinstance(object_type, STRING_TYPE):
|
||||
object_type = {"type": object_type}
|
||||
self.object_type = object_type
|
||||
|
||||
if not self.is_group:
|
||||
self.is_group = True
|
||||
|
||||
schema_data = copy.deepcopy(self.schema_data)
|
||||
schema_data["children"] = []
|
||||
|
||||
self.schema_data = schema_data
|
||||
self._origin_schema_data = origin_schema_data
|
||||
|
||||
self._default_value = NOT_SET
|
||||
self._studio_value = NOT_SET
|
||||
self._project_value = NOT_SET
|
||||
|
||||
super(RootsDictEntity, self)._item_initialization()
|
||||
|
||||
def schema_validations(self):
|
||||
if self.object_type is None:
|
||||
reason = (
|
||||
"Missing children definitions for root values"
|
||||
" ('object_type' not filled)."
|
||||
)
|
||||
raise EntitySchemaError(self, reason)
|
||||
|
||||
if not isinstance(self.object_type, dict):
|
||||
reason = (
|
||||
"Children definitions for root values must be dictionary"
|
||||
" ('object_type' is \"{}\")."
|
||||
).format(str(type(self.object_type)))
|
||||
raise EntitySchemaError(self, reason)
|
||||
|
||||
super(RootsDictEntity, self).schema_validations()
|
||||
|
||||
def set_override_state(self, state, ignore_missing_defaults):
|
||||
self.children = []
|
||||
self.non_gui_children = {}
|
||||
self.gui_layout = []
|
||||
|
||||
roots_entity = self.get_entity_from_path(
|
||||
"project_anatomy/roots"
|
||||
)
|
||||
children = []
|
||||
first = True
|
||||
for key in roots_entity.keys():
|
||||
if first:
|
||||
first = False
|
||||
elif self.separate_items:
|
||||
children.append({"type": "separator"})
|
||||
child = copy.deepcopy(self.object_type)
|
||||
child["key"] = key
|
||||
child["label"] = key
|
||||
children.append(child)
|
||||
|
||||
schema_data = copy.deepcopy(self.schema_data)
|
||||
schema_data["children"] = children
|
||||
|
||||
self._add_children(schema_data)
|
||||
|
||||
self._set_children_values(state)
|
||||
|
||||
super(RootsDictEntity, self).set_override_state(
|
||||
state, True
|
||||
)
|
||||
|
||||
if state == OverrideState.STUDIO:
|
||||
self.add_to_studio_default()
|
||||
|
||||
elif state == OverrideState.PROJECT:
|
||||
self.add_to_project_override()
|
||||
|
||||
def on_child_change(self, child_obj):
|
||||
if self._override_state is OverrideState.STUDIO:
|
||||
if not child_obj.has_studio_override:
|
||||
self.add_to_studio_default()
|
||||
|
||||
elif self._override_state is OverrideState.PROJECT:
|
||||
if not child_obj.has_project_override:
|
||||
self.add_to_project_override()
|
||||
|
||||
return super(RootsDictEntity, self).on_child_change(child_obj)
|
||||
|
||||
def _set_children_values(self, state):
|
||||
if state >= OverrideState.DEFAULTS:
|
||||
default_value = self._default_value
|
||||
if default_value is NOT_SET:
|
||||
if state > OverrideState.DEFAULTS:
|
||||
raise DefaultsNotDefined(self)
|
||||
else:
|
||||
default_value = {}
|
||||
|
||||
for key, child_obj in self.non_gui_children.items():
|
||||
child_value = default_value.get(key, NOT_SET)
|
||||
child_obj.update_default_value(child_value)
|
||||
|
||||
if state >= OverrideState.STUDIO:
|
||||
value = self._studio_value
|
||||
if value is NOT_SET:
|
||||
value = {}
|
||||
|
||||
for key, child_obj in self.non_gui_children.items():
|
||||
child_value = value.get(key, NOT_SET)
|
||||
child_obj.update_studio_value(child_value)
|
||||
|
||||
if state >= OverrideState.PROJECT:
|
||||
value = self._project_value
|
||||
if value is NOT_SET:
|
||||
value = {}
|
||||
|
||||
for key, child_obj in self.non_gui_children.items():
|
||||
child_value = value.get(key, NOT_SET)
|
||||
child_obj.update_project_value(child_value)
|
||||
|
||||
def _update_current_metadata(self):
|
||||
"""Override this method as this entity should not have metadata."""
|
||||
self._metadata_are_modified = False
|
||||
self._current_metadata = {}
|
||||
|
||||
def update_default_value(self, value):
|
||||
"""Update default values.
|
||||
|
||||
Not an api method, should be called by parent.
|
||||
"""
|
||||
value = self._check_update_value(value, "default")
|
||||
value, _ = self._prepare_value(value)
|
||||
|
||||
self._default_value = value
|
||||
self._default_metadata = {}
|
||||
self.has_default_value = value is not NOT_SET
|
||||
|
||||
def update_studio_value(self, value):
|
||||
"""Update studio override values.
|
||||
|
||||
Not an api method, should be called by parent.
|
||||
"""
|
||||
value = self._check_update_value(value, "studio override")
|
||||
value, _ = self._prepare_value(value)
|
||||
|
||||
self._studio_value = value
|
||||
self._studio_override_metadata = {}
|
||||
self.had_studio_override = value is not NOT_SET
|
||||
|
||||
def update_project_value(self, value):
|
||||
"""Update project override values.
|
||||
|
||||
Not an api method, should be called by parent.
|
||||
"""
|
||||
|
||||
value = self._check_update_value(value, "project override")
|
||||
value, _metadata = self._prepare_value(value)
|
||||
|
||||
self._project_value = value
|
||||
self._project_override_metadata = {}
|
||||
self.had_project_override = value is not NOT_SET
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ class DictMutableKeysEntity(EndpointEntity):
|
|||
child_entity = self.children_by_key[key]
|
||||
self.set_child_label(child_entity, label)
|
||||
|
||||
def _item_initalization(self):
|
||||
def _item_initialization(self):
|
||||
self._default_metadata = {}
|
||||
self._studio_override_metadata = {}
|
||||
self._project_override_metadata = {}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from .lib import (
|
|||
|
||||
|
||||
class BaseEnumEntity(InputEntity):
|
||||
def _item_initalization(self):
|
||||
def _item_initialization(self):
|
||||
self.multiselection = True
|
||||
self.value_on_not_set = None
|
||||
self.enum_items = None
|
||||
|
|
@ -70,7 +70,7 @@ class BaseEnumEntity(InputEntity):
|
|||
class EnumEntity(BaseEnumEntity):
|
||||
schema_types = ["enum"]
|
||||
|
||||
def _item_initalization(self):
|
||||
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
|
||||
|
|
@ -157,7 +157,7 @@ class HostsEnumEntity(BaseEnumEntity):
|
|||
"standalonepublisher"
|
||||
]
|
||||
|
||||
def _item_initalization(self):
|
||||
def _item_initialization(self):
|
||||
self.multiselection = self.schema_data.get("multiselection", True)
|
||||
use_empty_value = False
|
||||
if not self.multiselection:
|
||||
|
|
@ -250,7 +250,7 @@ class HostsEnumEntity(BaseEnumEntity):
|
|||
class AppsEnumEntity(BaseEnumEntity):
|
||||
schema_types = ["apps-enum"]
|
||||
|
||||
def _item_initalization(self):
|
||||
def _item_initialization(self):
|
||||
self.multiselection = True
|
||||
self.value_on_not_set = []
|
||||
self.enum_items = []
|
||||
|
|
@ -317,7 +317,7 @@ class AppsEnumEntity(BaseEnumEntity):
|
|||
class ToolsEnumEntity(BaseEnumEntity):
|
||||
schema_types = ["tools-enum"]
|
||||
|
||||
def _item_initalization(self):
|
||||
def _item_initialization(self):
|
||||
self.multiselection = True
|
||||
self.value_on_not_set = []
|
||||
self.enum_items = []
|
||||
|
|
@ -376,7 +376,7 @@ class ToolsEnumEntity(BaseEnumEntity):
|
|||
class TaskTypeEnumEntity(BaseEnumEntity):
|
||||
schema_types = ["task-types-enum"]
|
||||
|
||||
def _item_initalization(self):
|
||||
def _item_initialization(self):
|
||||
self.multiselection = self.schema_data.get("multiselection", True)
|
||||
if self.multiselection:
|
||||
self.valid_value_types = (list, )
|
||||
|
|
@ -452,7 +452,7 @@ class TaskTypeEnumEntity(BaseEnumEntity):
|
|||
class DeadlineUrlEnumEntity(BaseEnumEntity):
|
||||
schema_types = ["deadline_url-enum"]
|
||||
|
||||
def _item_initalization(self):
|
||||
def _item_initialization(self):
|
||||
self.multiselection = self.schema_data.get("multiselection", True)
|
||||
|
||||
self.enum_items = []
|
||||
|
|
@ -503,7 +503,7 @@ class DeadlineUrlEnumEntity(BaseEnumEntity):
|
|||
class AnatomyTemplatesEnumEntity(BaseEnumEntity):
|
||||
schema_types = ["anatomy-templates-enum"]
|
||||
|
||||
def _item_initalization(self):
|
||||
def _item_initialization(self):
|
||||
self.multiselection = False
|
||||
|
||||
self.enum_items = []
|
||||
|
|
|
|||
|
|
@ -362,7 +362,7 @@ class NumberEntity(InputEntity):
|
|||
float_number_regex = re.compile(r"^\d+\.\d+$")
|
||||
int_number_regex = re.compile(r"^\d+$")
|
||||
|
||||
def _item_initalization(self):
|
||||
def _item_initialization(self):
|
||||
self.minimum = self.schema_data.get("minimum", -99999)
|
||||
self.maximum = self.schema_data.get("maximum", 99999)
|
||||
self.decimal = self.schema_data.get("decimal", 0)
|
||||
|
|
@ -420,7 +420,7 @@ class NumberEntity(InputEntity):
|
|||
class BoolEntity(InputEntity):
|
||||
schema_types = ["boolean"]
|
||||
|
||||
def _item_initalization(self):
|
||||
def _item_initialization(self):
|
||||
self.valid_value_types = (bool, )
|
||||
value_on_not_set = self.convert_to_valid_type(
|
||||
self.schema_data.get("default", True)
|
||||
|
|
@ -431,7 +431,7 @@ class BoolEntity(InputEntity):
|
|||
class TextEntity(InputEntity):
|
||||
schema_types = ["text"]
|
||||
|
||||
def _item_initalization(self):
|
||||
def _item_initialization(self):
|
||||
self.valid_value_types = (STRING_TYPE, )
|
||||
self.value_on_not_set = ""
|
||||
|
||||
|
|
@ -449,7 +449,7 @@ class TextEntity(InputEntity):
|
|||
class PathInput(InputEntity):
|
||||
schema_types = ["path-input"]
|
||||
|
||||
def _item_initalization(self):
|
||||
def _item_initialization(self):
|
||||
self.valid_value_types = (STRING_TYPE, )
|
||||
self.value_on_not_set = ""
|
||||
|
||||
|
|
@ -460,7 +460,7 @@ class PathInput(InputEntity):
|
|||
class RawJsonEntity(InputEntity):
|
||||
schema_types = ["raw-json"]
|
||||
|
||||
def _item_initalization(self):
|
||||
def _item_initialization(self):
|
||||
# Schema must define if valid value is dict or list
|
||||
store_as_string = self.schema_data.get("store_as_string", False)
|
||||
is_list = self.schema_data.get("is_list", False)
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ class PathEntity(ItemEntity):
|
|||
raise AttributeError(self.attribute_error_msg.format("items"))
|
||||
return self.child_obj.items()
|
||||
|
||||
def _item_initalization(self):
|
||||
def _item_initialization(self):
|
||||
if self.group_item is None and not self.is_group:
|
||||
self.is_group = True
|
||||
|
||||
|
|
@ -216,7 +216,7 @@ class ListStrictEntity(ItemEntity):
|
|||
return self.children[idx]
|
||||
return default
|
||||
|
||||
def _item_initalization(self):
|
||||
def _item_initialization(self):
|
||||
self.valid_value_types = (list, )
|
||||
self.require_key = True
|
||||
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ class ListEntity(EndpointEntity):
|
|||
return list(value)
|
||||
return NOT_SET
|
||||
|
||||
def _item_initalization(self):
|
||||
def _item_initialization(self):
|
||||
self.valid_value_types = (list, )
|
||||
self.children = []
|
||||
self.value_on_not_set = []
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ class RootEntity(BaseItemEntity):
|
|||
super(RootEntity, self).__init__(schema_data)
|
||||
self._require_restart_callbacks = []
|
||||
self._item_ids_require_restart = set()
|
||||
self._item_initalization()
|
||||
self._item_initialization()
|
||||
if reset:
|
||||
self.reset()
|
||||
|
||||
|
|
@ -176,7 +176,7 @@ class RootEntity(BaseItemEntity):
|
|||
for child_obj in added_children:
|
||||
self.gui_layout.append(child_obj)
|
||||
|
||||
def _item_initalization(self):
|
||||
def _item_initialization(self):
|
||||
# Store `self` to `root_item` for children entities
|
||||
self.root_item = self
|
||||
|
||||
|
|
|
|||
|
|
@ -208,6 +208,25 @@
|
|||
}
|
||||
```
|
||||
|
||||
## dict-roots
|
||||
- entity can be used only in Project settings
|
||||
- keys of dictionary are based on current project roots
|
||||
- they are not updated "live" it is required to save root changes and then
|
||||
modify values on this entity
|
||||
# TODO do live updates
|
||||
```
|
||||
{
|
||||
"type": "dict-roots",
|
||||
"key": "roots",
|
||||
"label": "Roots",
|
||||
"object_type": {
|
||||
"type": "path",
|
||||
"multiplatform": true,
|
||||
"multipath": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## dict-conditional
|
||||
- is similar to `dict` but has always available one enum entity
|
||||
- the enum entity has single selection and it's value define other children entities
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue