reorganized entities to easier read the code

This commit is contained in:
iLLiCiTiT 2021-02-04 18:03:59 +01:00
parent 60f9faea86
commit 74618406b8
5 changed files with 696 additions and 642 deletions

View file

@ -7,19 +7,20 @@ from . import (
)
from .lib import NOT_SET
from .base_entity import (
SystemRootEntity,
BaseEntity,
SystemRootEntity
)
from .item_entities import (
ItemEntity,
GUIEntity,
DictImmutableKeysEntity,
DictMutableKeysEntity,
ListEntity,
PathEntity,
ListStrictEntity
)
from .input_entities import (
InputEntity,
NumberEntity,
BoolEntity,
EnumEntity,
@ -28,6 +29,8 @@ from .input_entities import (
RawJsonEntity
)
from .list_entity import ListEntity
from .dict_immutable_keys_entity import DictImmutableKeysEntity
__all__ = (
"constants",
@ -38,19 +41,24 @@ __all__ = (
"NOT_SET",
"BaseEntity",
"SystemRootEntity",
"ItemEntity",
"GUIEntity",
"DictImmutableKeysEntity",
"DictMutableKeysEntity",
"ListEntity",
"PathEntity",
"ListStrictEntity",
"InputEntity",
"NumberEntity",
"BoolEntity",
"EnumEntity",
"TextEntity",
"PathInput",
"RawJsonEntity"
"RawJsonEntity",
"ListEntity",
"DictImmutableKeysEntity"
)

View file

@ -454,38 +454,35 @@ class RootEntity(BaseEntity):
def create_schema_object(self, schema_data, *args, **kwargs):
if self._loaded_types is None:
from . import item_entities
from . import input_entities
from pype.settings import entities
sources = [item_entities, input_entities]
known_abstract_classes = (
BaseEntity,
item_entities.ItemEntity,
input_entities.InputEntity
entities.ItemEntity,
entities.InputEntity
)
self._loaded_types = {}
self._gui_types = []
for source in sources:
for attr in dir(source):
item = getattr(source, attr)
if not inspect.isclass(item):
for attr in dir(entities):
item = getattr(entities, attr)
if not inspect.isclass(item):
continue
if not issubclass(item, BaseEntity):
continue
if inspect.isabstract(item):
if item in known_abstract_classes:
continue
item()
if not issubclass(item, BaseEntity):
continue
for schema_type in item.schema_types:
self._loaded_types[schema_type] = item
if inspect.isabstract(item):
if item in known_abstract_classes:
continue
item()
for schema_type in item.schema_types:
self._loaded_types[schema_type] = item
gui_type = getattr(item, "gui_type", False)
if gui_type:
self._gui_types.append(item)
gui_type = getattr(item, "gui_type", False)
if gui_type:
self._gui_types.append(item)
klass = self._loaded_types.get(schema_data["type"])
if not klass:

View file

@ -0,0 +1,396 @@
import copy
from .lib import NOT_SET
from .constants import (
OverrideState,
WRAPPER_TYPES,
METADATA_KEYS,
M_OVERRIDEN_KEY
)
from . import (
BaseEntity,
ItemEntity,
BoolEntity,
GUIEntity
)
class DictImmutableKeysEntity(ItemEntity):
schema_types = ["dict"]
def __getitem__(self, key):
return self.non_gui_children[key]
def __setitem__(self, key, value):
child_obj = self.non_gui_children[key]
child_obj.set_value(value)
def __iter__(self):
for key in self.keys():
yield key
def get(self, key, default=None):
return self.non_gui_children.get(key, default)
def keys(self):
return self.non_gui_children.keys()
def values(self):
return self.non_gui_children.values()
def items(self):
return self.non_gui_children.items()
def on_value_change(self):
raise NotImplementedError(
"{} - on_value_change".format(self.__class__.__name__)
)
def schema_validations(self):
if self.checkbox_key:
checkbox_child = self.non_gui_children.get(self.checkbox_key)
if not checkbox_child:
raise ValueError(
"{}: Checkbox children \"{}\" was not found.".format(
self.path, self.checkbox_key
)
)
if not isinstance(checkbox_child, BoolEntity):
raise TypeError((
"{}: Checkbox children \"{}\" is not `boolean` type."
).format(self.path, self.checkbox_key))
super(DictImmutableKeysEntity, self).schema_validations()
for child_obj in self.children:
child_obj.schema_validations()
def on_change(self):
self.update_current_metadata()
for callback in self.on_change_callbacks:
callback()
self.parent.on_child_change(self)
def on_child_change(self, _child_obj):
self.on_change()
def _add_children(self, schema_data, first=True):
added_children = []
for children_schema in schema_data["children"]:
if children_schema["type"] in WRAPPER_TYPES:
_children_schema = copy.deepcopy(children_schema)
wrapper_children = self._add_children(
children_schema
)
_children_schema["children"] = wrapper_children
added_children.append(_children_schema)
continue
child_obj = self.create_schema_object(children_schema, self)
self.children.append(child_obj)
added_children.append(child_obj)
if isinstance(child_obj, GUIEntity):
continue
if child_obj.key in self.non_gui_children:
raise KeyError("Duplicated key \"{}\"".format(child_obj.key))
self.non_gui_children[child_obj.key] = child_obj
if not first:
return added_children
for child_obj in added_children:
if isinstance(child_obj, BaseEntity):
continue
self.gui_wrappers.append(child_obj)
def item_initalization(self):
self.default_metadata = NOT_SET
self.studio_override_metadata = NOT_SET
self.project_override_metadata = NOT_SET
# `current_metadata` are still when schema is loaded
# - only metadata stored with dict item are gorup overrides in
# M_OVERRIDEN_KEY
self.current_metadata = {}
self.metadata_are_modified = False
# Children are stored by key as keys are immutable and are defined by
# schema
self.valid_value_types = (dict, )
self.children = []
self.non_gui_children = {}
self.gui_wrappers = []
self._add_children(self.schema_data)
if self.is_dynamic_item:
self.require_key = False
# GUI attributes
self.checkbox_key = self.schema_data.get("checkbox_key")
self.highlight_content = self.schema_data.get(
"highlight_content", False
)
self.show_borders = self.schema_data.get("show_borders", True)
self.collapsible = self.schema_data.get("collapsable", True)
self.collapsed = self.schema_data.get("collapsed", True)
# Not yet implemented
self.use_label_wrap = self.schema_data.get("use_label_wrap") or True
def get_child_path(self, child_obj):
result_key = None
for key, _child_obj in self.non_gui_children.items():
if _child_obj is child_obj:
result_key = key
break
if result_key is None:
raise ValueError("Didn't found child {}".format(child_obj))
return "/".join([self.path, result_key])
def set_value(self, value):
for _key, _value in value.items():
self.non_gui_children[_key].set_value(_value)
def update_current_metadata(self):
# Define if current metadata are
metadata = NOT_SET
if self.override_state is OverrideState.PROJECT:
# metadata are NOT_SET if project overrides do not override this
# item
metadata = self.project_override_metadata
if self.override_state is OverrideState.STUDIO or metadata is NOT_SET:
metadata = self.studio_override_metadata
current_metadata = {}
for key, child_obj in self.non_gui_children.items():
if not child_obj.is_group:
continue
if (
self.override_state is OverrideState.STUDIO
and not child_obj.has_studio_override
):
continue
if (
self.override_state is OverrideState.PROJECT
and not child_obj.has_project_override
):
continue
if M_OVERRIDEN_KEY not in current_metadata:
current_metadata[M_OVERRIDEN_KEY] = []
current_metadata[M_OVERRIDEN_KEY].append(key)
if metadata is NOT_SET and not current_metadata:
self.metadata_are_modified = False
else:
self.metadata_are_modified = current_metadata != metadata
self.current_metadata = current_metadata
def set_override_state(self, state):
# Change has/had override states
self.override_state = state
if state is OverrideState.NOT_DEFINED:
pass
elif state is OverrideState.DEFAULTS:
self.has_default_value = self.default_value is not NOT_SET
elif state is OverrideState.STUDIO:
if self.studio_override_metadata is NOT_SET:
self.had_studio_override = False
self._has_studio_override = self.had_studio_override
elif state is OverrideState.PROJECT:
if self.project_override_metadata is NOT_SET:
self.had_project_override = False
self._has_project_override = self.had_project_override
for child_obj in self.non_gui_children.values():
child_obj.set_override_state(state)
self.update_current_metadata()
@property
def value(self):
output = {}
for key, child_obj in self.non_gui_children.items():
output[key] = child_obj.value
return output
@property
def has_unsaved_changes(self):
if self.metadata_are_modified:
return True
if (
self.override_state is OverrideState.PROJECT
and self._has_project_override != self.had_project_override
):
return True
elif (
self.override_state is OverrideState.STUDIO
and self._has_studio_override != self.had_studio_override
):
return True
return self.child_is_modified
@property
def child_is_modified(self):
for child_obj in self.non_gui_children.values():
if child_obj.has_unsaved_changes:
return True
return False
@property
def child_has_studio_override(self):
if self.override_state >= OverrideState.STUDIO:
for child_obj in self.non_gui_children.values():
if child_obj.child_has_studio_override:
return True
return False
@property
def child_has_project_override(self):
if self.override_state >= OverrideState.PROJECT:
for child_obj in self.non_gui_children.values():
if child_obj.child_has_studio_override:
return True
return False
def settings_value(self):
if self.override_state is OverrideState.NOT_DEFINED:
return NOT_SET
if self.is_group:
if self.override_state is OverrideState.STUDIO:
if not self._has_studio_override:
return NOT_SET
elif self.override_state is OverrideState.PROJECT:
if not self._has_project_override:
return NOT_SET
output = {}
for key, child_obj in self.non_gui_children.items():
value = child_obj.settings_value()
if value is not NOT_SET:
output[key] = value
if self.override_state is OverrideState.DEFAULTS:
return output
if not output:
return NOT_SET
output.update(self.current_metadata)
return output
def _prepare_value(self, value):
if value is NOT_SET:
return NOT_SET, NOT_SET
metadata = {}
for key in METADATA_KEYS:
if key in value:
metadata[key] = value.pop(key)
return value, metadata
def update_default_value(self, value):
self.has_default_value = value is not NOT_SET
# TODO add value validation
value, metadata = self._prepare_value(value)
self.default_metadata = metadata
if value is NOT_SET:
for child_obj in self.non_gui_children.values():
child_obj.update_default_value(value)
return
for _key, _value in value.items():
child_obj = self.non_gui_children.get(_key)
if child_obj:
child_obj.update_default_value(_value)
else:
# TODO store that has unsaved changes if is group item or
# is inside group item
self.log.warning(
"Unknown key in default values \"{}\"".format(_key)
)
def update_studio_values(self, value):
value, metadata = self._prepare_value(value)
self.studio_override_metadata = metadata
if value is NOT_SET:
for child_obj in self.non_gui_children.values():
child_obj.update_studio_values(value)
return
for _key, _value in value.items():
child_obj = self.non_gui_children.get(_key)
if child_obj:
child_obj.update_studio_values(_value)
else:
# TODO store that has unsaved changes if is group item or
# is inside group item
self.log.warning(
"Unknown key in studio overrides \"{}\"".format(_key)
)
def update_project_values(self, value):
value, metadata = self._prepare_value(value)
self.project_override_metadata = metadata
if value is NOT_SET:
for child_obj in self.non_gui_children.values():
child_obj.update_project_values(value)
return
for _key, _value in value.items():
child_obj = self.non_gui_children.get(_key)
if child_obj:
child_obj.update_project_values(_value)
else:
# TODO store that has unsaved changes if is group item or
# is inside group item
self.log.warning(
"Unknown key in project overrides \"{}\"".format(_key)
)
def discard_changes(self):
for child_obj in self.non_gui_children.values():
child_obj.discard_changes()
def set_studio_default(self):
if self.override_state is not OverrideState.STUDIO:
return
for child_obj in self.non_gui_children.values():
child_obj.set_studio_default()
def reset_to_pype_default(self):
if self.override_state is not OverrideState.STUDIO:
return
for child_obj in self.non_gui_children.values():
child_obj.reset_to_pype_default()
def remove_overrides(self):
if self.override_state is not OverrideState.PROJECT:
return
for child_obj in self.non_gui_children.values():
child_obj.remove_overrides()
def set_as_overriden(self):
if self.override_state is not OverrideState.PROJECT:
return
for child_obj in self.non_gui_children.values():
child_obj.set_as_overriden()

View file

@ -7,9 +7,7 @@ from .lib import (
)
from .constants import (
OverrideState,
WRAPPER_TYPES,
METADATA_KEYS,
M_OVERRIDEN_KEY,
M_ENVIRONMENT_KEY,
M_DYNAMIC_KEY_LABEL
)
@ -216,388 +214,6 @@ class GUIEntity(ItemEntity):
self.require_key = False
class DictImmutableKeysEntity(ItemEntity):
schema_types = ["dict"]
def __getitem__(self, key):
return self.non_gui_children[key]
def __setitem__(self, key, value):
child_obj = self.non_gui_children[key]
child_obj.set_value(value)
def __iter__(self):
for key in self.keys():
yield key
def get(self, key, default=None):
return self.non_gui_children.get(key, default)
def keys(self):
return self.non_gui_children.keys()
def values(self):
return self.non_gui_children.values()
def items(self):
return self.non_gui_children.items()
def on_value_change(self):
raise NotImplementedError(
"{} - on_value_change".format(self.__class__.__name__)
)
def schema_validations(self):
if self.checkbox_key:
checkbox_child = self.non_gui_children.get(self.checkbox_key)
if not checkbox_child:
raise ValueError(
"{}: Checkbox children \"{}\" was not found.".format(
self.path, self.checkbox_key
)
)
from .input_entities import BoolEntity
if not isinstance(checkbox_child, BoolEntity):
raise TypeError((
"{}: Checkbox children \"{}\" is not `boolean` type."
).format(self.path, self.checkbox_key))
super(DictImmutableKeysEntity, self).schema_validations()
for child_obj in self.children:
child_obj.schema_validations()
def on_change(self):
self.update_current_metadata()
for callback in self.on_change_callbacks:
callback()
self.parent.on_child_change(self)
def on_child_change(self, _child_obj):
self.on_change()
def _add_children(self, schema_data, first=True):
added_children = []
for children_schema in schema_data["children"]:
if children_schema["type"] in WRAPPER_TYPES:
_children_schema = copy.deepcopy(children_schema)
wrapper_children = self._add_children(
children_schema
)
_children_schema["children"] = wrapper_children
added_children.append(_children_schema)
continue
child_obj = self.create_schema_object(children_schema, self)
self.children.append(child_obj)
added_children.append(child_obj)
if isinstance(child_obj, GUIEntity):
continue
if child_obj.key in self.non_gui_children:
raise KeyError("Duplicated key \"{}\"".format(child_obj.key))
self.non_gui_children[child_obj.key] = child_obj
if not first:
return added_children
for child_obj in added_children:
if isinstance(child_obj, BaseEntity):
continue
self.gui_wrappers.append(child_obj)
def item_initalization(self):
self.default_metadata = NOT_SET
self.studio_override_metadata = NOT_SET
self.project_override_metadata = NOT_SET
# `current_metadata` are still when schema is loaded
# - only metadata stored with dict item are gorup overrides in
# M_OVERRIDEN_KEY
self.current_metadata = {}
self.metadata_are_modified = False
# Children are stored by key as keys are immutable and are defined by
# schema
self.valid_value_types = (dict, )
self.children = []
self.non_gui_children = {}
self.gui_wrappers = []
self._add_children(self.schema_data)
if self.is_dynamic_item:
self.require_key = False
# GUI attributes
self.checkbox_key = self.schema_data.get("checkbox_key")
self.highlight_content = self.schema_data.get(
"highlight_content", False
)
self.show_borders = self.schema_data.get("show_borders", True)
self.collapsible = self.schema_data.get("collapsable", True)
self.collapsed = self.schema_data.get("collapsed", True)
# Not yet implemented
self.use_label_wrap = self.schema_data.get("use_label_wrap") or True
def get_child_path(self, child_obj):
result_key = None
for key, _child_obj in self.non_gui_children.items():
if _child_obj is child_obj:
result_key = key
break
if result_key is None:
raise ValueError("Didn't found child {}".format(child_obj))
return "/".join([self.path, result_key])
def set_value(self, value):
for _key, _value in value.items():
self.non_gui_children[_key].set_value(_value)
def update_current_metadata(self):
# Define if current metadata are
metadata = NOT_SET
if self.override_state is OverrideState.PROJECT:
# metadata are NOT_SET if project overrides do not override this
# item
metadata = self.project_override_metadata
if self.override_state is OverrideState.STUDIO or metadata is NOT_SET:
metadata = self.studio_override_metadata
current_metadata = {}
for key, child_obj in self.non_gui_children.items():
if not child_obj.is_group:
continue
if (
self.override_state is OverrideState.STUDIO
and not child_obj.has_studio_override
):
continue
if (
self.override_state is OverrideState.PROJECT
and not child_obj.has_project_override
):
continue
if M_OVERRIDEN_KEY not in current_metadata:
current_metadata[M_OVERRIDEN_KEY] = []
current_metadata[M_OVERRIDEN_KEY].append(key)
if metadata is NOT_SET and not current_metadata:
self.metadata_are_modified = False
else:
self.metadata_are_modified = current_metadata != metadata
self.current_metadata = current_metadata
def set_override_state(self, state):
# Change has/had override states
self.override_state = state
if state is OverrideState.NOT_DEFINED:
pass
elif state is OverrideState.DEFAULTS:
self.has_default_value = self.default_value is not NOT_SET
elif state is OverrideState.STUDIO:
if self.studio_override_metadata is NOT_SET:
self.had_studio_override = False
self._has_studio_override = self.had_studio_override
elif state is OverrideState.PROJECT:
if self.project_override_metadata is NOT_SET:
self.had_project_override = False
self._has_project_override = self.had_project_override
for child_obj in self.non_gui_children.values():
child_obj.set_override_state(state)
self.update_current_metadata()
@property
def value(self):
output = {}
for key, child_obj in self.non_gui_children.items():
output[key] = child_obj.value
return output
@property
def has_unsaved_changes(self):
if self.metadata_are_modified:
return True
if (
self.override_state is OverrideState.PROJECT
and self._has_project_override != self.had_project_override
):
return True
elif (
self.override_state is OverrideState.STUDIO
and self._has_studio_override != self.had_studio_override
):
return True
return self.child_is_modified
@property
def child_is_modified(self):
for child_obj in self.non_gui_children.values():
if child_obj.has_unsaved_changes:
return True
return False
@property
def child_has_studio_override(self):
if self.override_state >= OverrideState.STUDIO:
for child_obj in self.non_gui_children.values():
if child_obj.child_has_studio_override:
return True
return False
@property
def child_has_project_override(self):
if self.override_state >= OverrideState.PROJECT:
for child_obj in self.non_gui_children.values():
if child_obj.child_has_studio_override:
return True
return False
def settings_value(self):
if self.override_state is OverrideState.NOT_DEFINED:
return NOT_SET
if self.is_group:
if self.override_state is OverrideState.STUDIO:
if not self._has_studio_override:
return NOT_SET
elif self.override_state is OverrideState.PROJECT:
if not self._has_project_override:
return NOT_SET
output = {}
for key, child_obj in self.non_gui_children.items():
value = child_obj.settings_value()
if value is not NOT_SET:
output[key] = value
if self.override_state is OverrideState.DEFAULTS:
return output
if not output:
return NOT_SET
output.update(self.current_metadata)
return output
def _prepare_value(self, value):
if value is NOT_SET:
return NOT_SET, NOT_SET
metadata = {}
for key in METADATA_KEYS:
if key in value:
metadata[key] = value.pop(key)
return value, metadata
def update_default_value(self, value):
self.has_default_value = value is not NOT_SET
# TODO add value validation
value, metadata = self._prepare_value(value)
self.default_metadata = metadata
if value is NOT_SET:
for child_obj in self.non_gui_children.values():
child_obj.update_default_value(value)
return
for _key, _value in value.items():
child_obj = self.non_gui_children.get(_key)
if child_obj:
child_obj.update_default_value(_value)
else:
# TODO store that has unsaved changes if is group item or
# is inside group item
self.log.warning(
"Unknown key in default values \"{}\"".format(_key)
)
def update_studio_values(self, value):
value, metadata = self._prepare_value(value)
self.studio_override_metadata = metadata
if value is NOT_SET:
for child_obj in self.non_gui_children.values():
child_obj.update_studio_values(value)
return
for _key, _value in value.items():
child_obj = self.non_gui_children.get(_key)
if child_obj:
child_obj.update_studio_values(_value)
else:
# TODO store that has unsaved changes if is group item or
# is inside group item
self.log.warning(
"Unknown key in studio overrides \"{}\"".format(_key)
)
def update_project_values(self, value):
value, metadata = self._prepare_value(value)
self.project_override_metadata = metadata
if value is NOT_SET:
for child_obj in self.non_gui_children.values():
child_obj.update_project_values(value)
return
for _key, _value in value.items():
child_obj = self.non_gui_children.get(_key)
if child_obj:
child_obj.update_project_values(_value)
else:
# TODO store that has unsaved changes if is group item or
# is inside group item
self.log.warning(
"Unknown key in project overrides \"{}\"".format(_key)
)
def discard_changes(self):
for child_obj in self.non_gui_children.values():
child_obj.discard_changes()
def set_studio_default(self):
if self.override_state is not OverrideState.STUDIO:
return
for child_obj in self.non_gui_children.values():
child_obj.set_studio_default()
def reset_to_pype_default(self):
if self.override_state is not OverrideState.STUDIO:
return
for child_obj in self.non_gui_children.values():
child_obj.reset_to_pype_default()
def remove_overrides(self):
if self.override_state is not OverrideState.PROJECT:
return
for child_obj in self.non_gui_children.values():
child_obj.remove_overrides()
def set_as_overriden(self):
if self.override_state is not OverrideState.PROJECT:
return
for child_obj in self.non_gui_children.values():
child_obj.set_as_overriden()
class DictMutableKeysEntity(ItemEntity):
schema_types = ["dict-modifiable"]
_miss_arg = object()
@ -900,9 +516,6 @@ class DictMutableKeysEntity(ItemEntity):
pass
return False
def discard_changes(self):
pass
def settings_value(self):
if self.override_state is OverrideState.NOT_DEFINED:
return NOT_SET
@ -920,6 +533,9 @@ class DictMutableKeysEntity(ItemEntity):
output.update(copy.deepcopy(self.current_metadata))
return output
def discard_changes(self):
pass
def remove_overrides(self):
pass
@ -957,233 +573,6 @@ class DictMutableKeysEntity(ItemEntity):
self.project_override_metadata = metadata
class ListEntity(ItemEntity):
schema_types = ["list"]
def __iter__(self):
for item in self.children:
yield item
def append(self, item):
child_obj = self.add_new_item()
child_obj.set_value(item)
self.on_change()
def extend(self, items):
for item in items:
self.append(item)
def clear(self):
self.children.clear()
self.on_change()
def pop(self, idx):
self.children.pop(idx)
self.on_change()
def remove(self, item):
for idx, child_obj in enumerate(self.children):
if child_obj.value == item:
self.pop(idx)
return
raise ValueError("ListEntity.remove(x): x not in ListEntity")
def insert(self, idx, item):
child_obj = self.add_new_item(idx)
child_obj.set_value(item)
self.on_change()
def add_new_item(self, idx=None):
child_obj = self.create_schema_object(self.item_schema, self, True)
child_obj.set_override_state(self.override_state)
if idx is None:
self.children.append(child_obj)
else:
self.children.insert(idx, child_obj)
return child_obj
def item_initalization(self):
self.valid_value_types = (list, )
self.children = []
item_schema = self.schema_data["object_type"]
if not isinstance(item_schema, dict):
item_schema = {"type": item_schema}
self.item_schema = item_schema
if not self.group_item:
self.is_group = True
# GUI attributes
self.use_label_wrap = self.schema_data.get("use_label_wrap") or False
# Used only if `use_label_wrap` is set to True
self.collapsible = self.schema_data.get("collapsible") or True
self.collapsed = self.schema_data.get("collapsed") or False
def schema_validations(self):
super(ListEntity, self).schema_validations()
if self.is_dynamic_item and self.use_label_wrap:
raise ValueError(
"`ListWidget` can't have set `use_label_wrap` to True and"
" be used as widget at the same time."
)
if self.use_label_wrap and not self.label:
raise ValueError(
"`ListWidget` can't have set `use_label_wrap` to True and"
" not have set \"label\" key at the same time."
)
for child_obj in self.children:
child_obj.schema_validations()
def get_child_path(self, child_obj):
result_idx = None
for idx, _child_obj in enumerate(self.children):
if _child_obj is child_obj:
result_idx = idx
break
if result_idx is None:
raise ValueError("Didn't found child {}".format(child_obj))
return "/".join([self.path, str(result_idx)])
def set_value(self, value):
pass
def on_change(self):
pass
def on_child_change(self, child_obj):
print("{} - on_child_change".format(self.__class__.__name__))
def on_value_change(self):
raise NotImplementedError(self.__class__.__name__)
def set_override_state(self, state):
self.override_state = state
if (
not self.has_default_value
and state in (OverrideState.STUDIO, OverrideState.PROJECT)
):
raise DefaultsNotDefined(self)
self._set_value()
def _set_value(self, value=NOT_SET):
while self.children:
self.children.pop(0)
if self.override_state is OverrideState.NOT_DEFINED:
return
if value is NOT_SET:
if self.override_state is OverrideState.PROJECT:
if self.had_project_override:
value = self.project_override_value
elif self.had_studio_override:
value = self.studio_override_value
else:
value = self.default_value
elif self.override_state is OverrideState.STUDIO:
if self.had_studio_override:
value = self.studio_override_value
else:
value = self.default_value
elif self.override_state is OverrideState.DEFAULTS:
value = self.default_value
if value is NOT_SET:
value = self.value_on_not_set
for item in value:
child_obj = self.create_schema_object(self.item_schema, self, True)
self.children.append(child_obj)
child_obj.update_default_value(item)
if self.override_state is OverrideState.STUDIO:
if self.had_studio_override:
child_obj.update_studio_values(item)
elif self.override_state is OverrideState.PROJECT:
if self.had_project_override:
child_obj.update_project_values(item)
for child_obj in self.children:
child_obj.set_override_state(self.override_state)
@property
def value(self):
output = []
for child_obj in self.children:
output.append(child_obj.value)
return output
@property
def child_has_studio_override(self):
pass
@property
def has_unsaved_changes(self):
pass
@property
def child_is_modified(self):
pass
@property
def child_has_project_override(self):
if self.override_state is OverrideState.PROJECT:
# TODO implement
pass
return False
def discard_changes(self):
pass
def settings_value(self):
if self.override_state is OverrideState.NOT_DEFINED:
return NOT_SET
if self.is_group:
if self.override_state is OverrideState.STUDIO:
if not self._has_studio_override:
return NOT_SET
elif self.override_state is OverrideState.PROJECT:
if not self._has_project_override:
return NOT_SET
output = []
for child_obj in self.children:
output.append(child_obj.settings_value())
return output
def remove_overrides(self):
pass
def reset_to_pype_default(self):
pass
def set_as_overriden(self):
pass
def set_studio_default(self):
pass
def update_default_value(self, value):
self.has_default_value = value is not NOT_SET
self.default_value = value
def update_studio_values(self, value):
self.studio_override_value = value
def update_project_values(self, value):
self.project_override_value = value
class PathEntity(ItemEntity):
schema_types = ["path-widget"]
platforms = ("windows", "darwin", "linux")

View file

@ -0,0 +1,264 @@
from .item_entities import ItemEntity
from .constants import OverrideState
from .lib import (
NOT_SET,
DefaultsNotDefined
)
class ListEntity(ItemEntity):
schema_types = ["list"]
def __iter__(self):
for item in self.children:
yield item
def append(self, item):
child_obj = self.add_new_item()
child_obj.set_value(item)
self.on_change()
def extend(self, items):
for item in items:
self.append(item)
def clear(self):
self.children.clear()
self.on_change()
def pop(self, idx):
item = self.children.pop(idx)
self.on_change()
return item
def remove(self, item):
for idx, child_obj in enumerate(self.children):
if child_obj.value == item:
self.pop(idx)
return
raise ValueError("ListEntity.remove(x): x not in ListEntity")
def insert(self, idx, item):
child_obj = self.add_new_item(idx)
child_obj.set_value(item)
self.on_change()
def add_new_item(self, idx=None):
child_obj = self.create_schema_object(self.item_schema, self, True)
child_obj.set_override_state(self.override_state)
if idx is None:
self.children.append(child_obj)
else:
self.children.insert(idx, child_obj)
return child_obj
def item_initalization(self):
self.valid_value_types = (list, )
self.children = []
item_schema = self.schema_data["object_type"]
if not isinstance(item_schema, dict):
item_schema = {"type": item_schema}
self.item_schema = item_schema
if not self.group_item:
self.is_group = True
# GUI attributes
self.use_label_wrap = self.schema_data.get("use_label_wrap") or False
# Used only if `use_label_wrap` is set to True
self.collapsible = self.schema_data.get("collapsible") or True
self.collapsed = self.schema_data.get("collapsed") or False
def schema_validations(self):
super(ListEntity, self).schema_validations()
if self.is_dynamic_item and self.use_label_wrap:
raise ValueError(
"`ListWidget` can't have set `use_label_wrap` to True and"
" be used as widget at the same time."
)
if self.use_label_wrap and not self.label:
raise ValueError(
"`ListWidget` can't have set `use_label_wrap` to True and"
" not have set \"label\" key at the same time."
)
for child_obj in self.children:
child_obj.schema_validations()
def get_child_path(self, child_obj):
result_idx = None
for idx, _child_obj in enumerate(self.children):
if _child_obj is child_obj:
result_idx = idx
break
if result_idx is None:
raise ValueError("Didn't found child {}".format(child_obj))
return "/".join([self.path, str(result_idx)])
def set_value(self, value):
pass
def on_change(self):
value_is_modified = None
if self.override_state is OverrideState.PROJECT:
# Only value change
if (
self._has_project_override
and self.project_override_value is not NOT_SET
):
value_is_modified = (
self._current_value != self.project_override_value
)
if (
self.override_state is OverrideState.STUDIO
or value_is_modified is None
):
if (
self._has_studio_override
and self.studio_override_value is not NOT_SET
):
value_is_modified = (
self._current_value != self.studio_override_value
)
if value_is_modified is None:
value_is_modified = self._current_value != self.default_value
self.value_is_modified = value_is_modified
for callback in self.on_change_callbacks:
callback()
self.parent.on_child_change(self)
def on_child_change(self, child_obj):
print("{} - on_child_change".format(self.__class__.__name__))
def on_value_change(self):
raise NotImplementedError(self.__class__.__name__)
def set_override_state(self, state):
self.override_state = state
if (
not self.has_default_value
and state in (OverrideState.STUDIO, OverrideState.PROJECT)
):
raise DefaultsNotDefined(self)
self._set_value()
def _set_value(self, value=NOT_SET):
while self.children:
self.children.pop(0)
if self.override_state is OverrideState.NOT_DEFINED:
return
if value is NOT_SET:
if self.override_state is OverrideState.PROJECT:
if self.had_project_override:
value = self.project_override_value
elif self.had_studio_override:
value = self.studio_override_value
else:
value = self.default_value
elif self.override_state is OverrideState.STUDIO:
if self.had_studio_override:
value = self.studio_override_value
else:
value = self.default_value
elif self.override_state is OverrideState.DEFAULTS:
value = self.default_value
if value is NOT_SET:
value = self.value_on_not_set
for item in value:
child_obj = self.create_schema_object(self.item_schema, self, True)
self.children.append(child_obj)
child_obj.update_default_value(item)
if self.override_state is OverrideState.STUDIO:
if self.had_studio_override:
child_obj.update_studio_values(item)
elif self.override_state is OverrideState.PROJECT:
if self.had_project_override:
child_obj.update_project_values(item)
for child_obj in self.children:
child_obj.set_override_state(self.override_state)
@property
def value(self):
output = []
for child_obj in self.children:
output.append(child_obj.value)
return output
@property
def child_has_studio_override(self):
pass
@property
def has_unsaved_changes(self):
pass
@property
def child_is_modified(self):
pass
@property
def child_has_project_override(self):
if self.override_state is OverrideState.PROJECT:
# TODO implement
pass
return False
def discard_changes(self):
pass
def settings_value(self):
if self.override_state is OverrideState.NOT_DEFINED:
return NOT_SET
if self.is_group:
if self.override_state is OverrideState.STUDIO:
if not self._has_studio_override:
return NOT_SET
elif self.override_state is OverrideState.PROJECT:
if not self._has_project_override:
return NOT_SET
output = []
for child_obj in self.children:
output.append(child_obj.settings_value())
return output
def remove_overrides(self):
pass
def reset_to_pype_default(self):
pass
def set_as_overriden(self):
pass
def set_studio_default(self):
pass
def update_default_value(self, value):
self.has_default_value = value is not NOT_SET
self.default_value = value
def update_studio_values(self, value):
self.studio_override_value = value
def update_project_values(self, value):
self.project_override_value = value