mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-25 05:14:40 +01:00
Merge pull request #1815 from pypeclub/feature/template_schema_as_object_type
Settings list can use template or schema as object type
This commit is contained in:
commit
39ddf303c6
5 changed files with 230 additions and 4 deletions
|
|
@ -3,6 +3,7 @@ import re
|
|||
import json
|
||||
import copy
|
||||
import inspect
|
||||
import contextlib
|
||||
|
||||
from .exceptions import (
|
||||
SchemaTemplateMissingKeys,
|
||||
|
|
@ -111,6 +112,10 @@ class SchemasHub:
|
|||
self._loaded_templates = {}
|
||||
self._loaded_schemas = {}
|
||||
|
||||
# Store validating and validated dynamic template or schemas
|
||||
self._validating_dynamic = set()
|
||||
self._validated_dynamic = set()
|
||||
|
||||
# It doesn't make sence to reload types on each reset as they can't be
|
||||
# changed
|
||||
self._load_types()
|
||||
|
|
@ -126,6 +131,60 @@ class SchemasHub:
|
|||
def gui_types(self):
|
||||
return self._gui_types
|
||||
|
||||
def get_template_name(self, item_def, default=None):
|
||||
"""Get template name from passed item definition.
|
||||
|
||||
Args:
|
||||
item_def(dict): Definition of item with "type".
|
||||
default(object): Default return value.
|
||||
"""
|
||||
output = default
|
||||
if not item_def or not isinstance(item_def, dict):
|
||||
return output
|
||||
|
||||
item_type = item_def.get("type")
|
||||
if item_type in ("template", "schema_template"):
|
||||
output = item_def["name"]
|
||||
return output
|
||||
|
||||
def is_dynamic_template_validating(self, template_name):
|
||||
"""Is template validating using different entity.
|
||||
|
||||
Returns:
|
||||
bool: Is template validating.
|
||||
"""
|
||||
if template_name in self._validating_dynamic:
|
||||
return True
|
||||
return False
|
||||
|
||||
def is_dynamic_template_validated(self, template_name):
|
||||
"""Is template already validated.
|
||||
|
||||
Returns:
|
||||
bool: Is template validated.
|
||||
"""
|
||||
|
||||
if template_name in self._validated_dynamic:
|
||||
return True
|
||||
return False
|
||||
|
||||
@contextlib.contextmanager
|
||||
def validating_dynamic(self, template_name):
|
||||
"""Template name is validating and validated.
|
||||
|
||||
Context manager that cares about storing template name validations of
|
||||
template.
|
||||
|
||||
This is to avoid infinite loop of dynamic children validation.
|
||||
"""
|
||||
self._validating_dynamic.add(template_name)
|
||||
try:
|
||||
yield
|
||||
self._validated_dynamic.add(template_name)
|
||||
|
||||
finally:
|
||||
self._validating_dynamic.remove(template_name)
|
||||
|
||||
def get_schema(self, schema_name):
|
||||
"""Get schema definition data by it's name.
|
||||
|
||||
|
|
|
|||
|
|
@ -141,7 +141,20 @@ class ListEntity(EndpointEntity):
|
|||
item_schema = self.schema_data["object_type"]
|
||||
if not isinstance(item_schema, dict):
|
||||
item_schema = {"type": item_schema}
|
||||
self.item_schema = item_schema
|
||||
|
||||
obj_template_name = self.schema_hub.get_template_name(item_schema)
|
||||
_item_schemas = self.schema_hub.resolve_schema_data(item_schema)
|
||||
if len(_item_schemas) == 1:
|
||||
self.item_schema = _item_schemas[0]
|
||||
if self.item_schema != item_schema:
|
||||
if "label" in self.item_schema:
|
||||
self.item_schema.pop("label")
|
||||
self.item_schema["use_label_wrap"] = False
|
||||
else:
|
||||
self.item_schema = _item_schemas
|
||||
|
||||
# Store if was used template or schema
|
||||
self._obj_template_name = obj_template_name
|
||||
|
||||
if self.group_item is None:
|
||||
self.is_group = True
|
||||
|
|
@ -150,6 +163,12 @@ class ListEntity(EndpointEntity):
|
|||
self.initial_value = []
|
||||
|
||||
def schema_validations(self):
|
||||
if isinstance(self.item_schema, list):
|
||||
reason = (
|
||||
"`ListWidget` has multiple items as object type."
|
||||
)
|
||||
raise EntitySchemaError(self, reason)
|
||||
|
||||
super(ListEntity, self).schema_validations()
|
||||
|
||||
if self.is_dynamic_item and self.use_label_wrap:
|
||||
|
|
@ -167,18 +186,36 @@ class ListEntity(EndpointEntity):
|
|||
raise EntitySchemaError(self, reason)
|
||||
|
||||
# Validate object type schema
|
||||
child_validated = False
|
||||
validate_children = True
|
||||
for child_entity in self.children:
|
||||
child_entity.schema_validations()
|
||||
child_validated = True
|
||||
validate_children = False
|
||||
break
|
||||
|
||||
if not child_validated:
|
||||
if validate_children and self._obj_template_name:
|
||||
_validated = self.schema_hub.is_dynamic_template_validated(
|
||||
self._obj_template_name
|
||||
)
|
||||
_validating = self.schema_hub.is_dynamic_template_validating(
|
||||
self._obj_template_name
|
||||
)
|
||||
validate_children = not _validated and not _validating
|
||||
|
||||
if not validate_children:
|
||||
return
|
||||
|
||||
def _validate():
|
||||
idx = 0
|
||||
tmp_child = self._add_new_item(idx)
|
||||
tmp_child.schema_validations()
|
||||
self.children.pop(idx)
|
||||
|
||||
if self._obj_template_name:
|
||||
with self.schema_hub.validating_dynamic(self._obj_template_name):
|
||||
_validate()
|
||||
else:
|
||||
_validate()
|
||||
|
||||
def get_child_path(self, child_obj):
|
||||
result_idx = None
|
||||
for idx, _child_obj in enumerate(self.children):
|
||||
|
|
|
|||
|
|
@ -417,6 +417,8 @@ How output of the schema could look like on save:
|
|||
- there are 2 possible ways how to set the type:
|
||||
1.) dictionary with item modifiers (`number` input has `minimum`, `maximum` and `decimals`) in that case item type must be set as value of `"type"` (example below)
|
||||
2.) item type name as string without modifiers (e.g. `text`)
|
||||
3.) enhancement of 1.) there is also support of `template` type but be carefull about endless loop of templates
|
||||
- goal of using `template` is to easily change same item definitions in multiple lists
|
||||
|
||||
1.) with item modifiers
|
||||
```
|
||||
|
|
@ -442,6 +444,65 @@ How output of the schema could look like on save:
|
|||
}
|
||||
```
|
||||
|
||||
3.) with template definition
|
||||
```
|
||||
# Schema of list item where template is used
|
||||
{
|
||||
"type": "list",
|
||||
"key": "menu_items",
|
||||
"label": "Menu Items",
|
||||
"object_type": {
|
||||
"type": "template",
|
||||
"name": "template_object_example"
|
||||
}
|
||||
}
|
||||
|
||||
# WARNING:
|
||||
# In this example the template use itself inside which will work in `list`
|
||||
# but may cause an issue in other entity types (e.g. `dict`).
|
||||
|
||||
'template_object_example.json' :
|
||||
[
|
||||
{
|
||||
"type": "dict-conditional",
|
||||
"use_label_wrap": true,
|
||||
"collapsible": true,
|
||||
"key": "menu_items",
|
||||
"label": "Menu items",
|
||||
"enum_key": "type",
|
||||
"enum_label": "Type",
|
||||
"enum_children": [
|
||||
{
|
||||
"key": "action",
|
||||
"label": "Action",
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "key",
|
||||
"label": "Key"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "menu",
|
||||
"label": "Menu",
|
||||
"children": [
|
||||
{
|
||||
"key": "children",
|
||||
"label": "Children",
|
||||
"type": "list",
|
||||
"object_type": {
|
||||
"type": "template",
|
||||
"name": "template_object_example"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### dict-modifiable
|
||||
- one of dictionary inputs, this is only used as value input
|
||||
- items in this input can be removed and added same way as in `list` input
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
[
|
||||
{
|
||||
"type": "dict-conditional",
|
||||
"use_label_wrap": true,
|
||||
"collapsible": true,
|
||||
"key": "menu_items",
|
||||
"label": "Menu items",
|
||||
"enum_key": "type",
|
||||
"enum_label": "Type",
|
||||
"enum_children": [
|
||||
{
|
||||
"key": "action",
|
||||
"label": "Action",
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "key",
|
||||
"label": "Key"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "label",
|
||||
"label": "Label"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "command",
|
||||
"label": "Comand"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "menu",
|
||||
"label": "Menu",
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "label",
|
||||
"label": "Label"
|
||||
},
|
||||
{
|
||||
"key": "children",
|
||||
"label": "Children",
|
||||
"type": "list",
|
||||
"object_type": {
|
||||
"type": "template",
|
||||
"name": "example_infinite_hierarchy"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "separator",
|
||||
"label": "Separator"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
@ -82,6 +82,17 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"use_label_wrap": true,
|
||||
"collapsible": true,
|
||||
"key": "infinite_hierarchy",
|
||||
"label": "Infinite list template hierarchy",
|
||||
"object_type": {
|
||||
"type": "template",
|
||||
"name": "example_infinite_hierarchy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"key": "schema_template_exaples",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue