feat(blenvy): significant breaking changes in the way components are handled
* to fix issues with hash collisions because of incomplete & incorect "component paths" (ie the different nesting levels of the structs within components) * removed short name nested component path passing * changed the way the composite paths are created & the hash is generated * a lot of other related changes * also changed the registry's default path, to use the blenvy level assets path
This commit is contained in:
parent
c282dab585
commit
e86920168a
|
@ -97,6 +97,8 @@ Components:
|
|||
- [x] add warning about hash colision (not much we can/ could do if it is the case ?)
|
||||
- [ ] double check weird collisions AND/OR reuse existing if applicable
|
||||
|
||||
- [x] annoying default path for registry, should be relative to the assets path
|
||||
|
||||
|
||||
General things to solve:
|
||||
- [x] save settings
|
||||
|
|
|
@ -7,7 +7,7 @@ from . import process_enum
|
|||
from . import process_list
|
||||
from . import process_map
|
||||
|
||||
def process_component(registry, definition, update, extras=None, nesting = [], nesting_long_names = []):
|
||||
def process_component(registry, definition, update, extras=None, nesting_long_names = []):
|
||||
long_name = definition['long_name']
|
||||
short_name = definition["short_name"]
|
||||
type_info = definition["typeInfo"] if "typeInfo" in definition else None
|
||||
|
@ -30,28 +30,32 @@ def process_component(registry, definition, update, extras=None, nesting = [], n
|
|||
with_list = False
|
||||
with_map = False
|
||||
|
||||
padding = " " * (len(nesting_long_names) + 1)
|
||||
#print(f"{padding}process component", long_name, "nesting_long_names",nesting_long_names, "foo", has_properties, has_prefixItems, is_enum, is_list, is_map)
|
||||
|
||||
if has_properties:
|
||||
__annotations__ = __annotations__ | process_structs.process_structs(registry, definition, properties, update, nesting, nesting_long_names)
|
||||
__annotations__ = __annotations__ | process_structs.process_structs(registry, definition, properties, update, nesting_long_names)
|
||||
with_properties = True
|
||||
tupple_or_struct = "struct"
|
||||
|
||||
if has_prefixItems:
|
||||
__annotations__ = __annotations__ | process_tupples.process_tupples(registry, definition, prefixItems, update, nesting, nesting_long_names)
|
||||
__annotations__ = __annotations__ | process_tupples.process_tupples(registry, definition, prefixItems, update, nesting_long_names)
|
||||
with_items = True
|
||||
tupple_or_struct = "tupple"
|
||||
|
||||
if is_enum:
|
||||
__annotations__ = __annotations__ | process_enum.process_enum(registry, definition, update, nesting, nesting_long_names)
|
||||
__annotations__ = __annotations__ | process_enum.process_enum(registry, definition, update, nesting_long_names)
|
||||
with_enum = True
|
||||
|
||||
if is_list:
|
||||
__annotations__ = __annotations__ | process_list.process_list(registry, definition, update, nesting, nesting_long_names)
|
||||
__annotations__ = __annotations__ | process_list.process_list(registry, definition, update, nesting_long_names)
|
||||
with_list= True
|
||||
|
||||
if is_map:
|
||||
__annotations__ = __annotations__ | process_map.process_map(registry, definition, update, nesting, nesting_long_names)
|
||||
__annotations__ = __annotations__ | process_map.process_map(registry, definition, update, nesting_long_names)
|
||||
with_map = True
|
||||
|
||||
# print("AFTER PROCESS", nesting_long_names, long_name)
|
||||
|
||||
field_names = []
|
||||
for a in __annotations__:
|
||||
|
@ -61,7 +65,10 @@ def process_component(registry, definition, update, extras=None, nesting = [], n
|
|||
extras = extras if extras is not None else {
|
||||
"long_name": long_name
|
||||
}
|
||||
|
||||
nesting_long_names = nesting_long_names + [long_name]
|
||||
root_component = nesting_long_names[0] if len(nesting_long_names) > 0 else long_name
|
||||
|
||||
# print("")
|
||||
property_group_params = {
|
||||
**extras,
|
||||
|
@ -78,7 +85,7 @@ def process_component(registry, definition, update, extras=None, nesting = [], n
|
|||
-BasicTest => the registration & update callback of this one overwrites the first "basicTest"
|
||||
have not found a cleaner workaround so far
|
||||
"""
|
||||
property_group_name = registry.generate_propGroup_name(nesting, long_name)
|
||||
property_group_name = registry.generate_propGroup_name(nesting_long_names)
|
||||
(property_group_pointer, property_group_class) = property_group_from_infos(property_group_name, property_group_params)
|
||||
# add our component propertyGroup to the registry
|
||||
registry.register_component_propertyGroup(property_group_name, property_group_pointer)
|
||||
|
|
|
@ -1,21 +1,19 @@
|
|||
from bpy.props import (StringProperty)
|
||||
from . import process_component
|
||||
|
||||
def process_enum(registry, definition, update, nesting, nesting_long_names):
|
||||
def process_enum(registry, definition, update, nesting_long_names):
|
||||
blender_property_mapping = registry.blender_property_mapping
|
||||
short_name = definition["short_name"]
|
||||
long_name = definition["long_name"]
|
||||
|
||||
type_def = definition["type"] if "type" in definition else None
|
||||
variants = definition["oneOf"]
|
||||
|
||||
nesting = nesting + [short_name]
|
||||
nesting_long_names = nesting_long_names = [long_name]
|
||||
nesting_long_names = nesting_long_names + [long_name]
|
||||
|
||||
__annotations__ = {}
|
||||
original_type_name = "enum"
|
||||
|
||||
# print("processing enum", short_name, long_name, definition)
|
||||
#print("processing enum", long_name)#, definition)
|
||||
|
||||
if type_def == "object":
|
||||
labels = []
|
||||
|
@ -28,12 +26,12 @@ def process_enum(registry, definition, update, nesting, nesting_long_names):
|
|||
if "prefixItems" in variant:
|
||||
#print("tupple variant in enum", variant)
|
||||
registry.add_custom_type(variant_name, variant)
|
||||
(sub_component_group, _) = process_component.process_component(registry, variant, update, {"nested": True}, nesting, nesting_long_names)
|
||||
(sub_component_group, _) = process_component.process_component(registry, variant, update, {"nested": True}, nesting_long_names=nesting_long_names)
|
||||
additional_annotations[variant_prefixed_name] = sub_component_group
|
||||
elif "properties" in variant:
|
||||
#print("struct variant in enum", variant)
|
||||
registry.add_custom_type(variant_name, variant)
|
||||
(sub_component_group, _) = process_component.process_component(registry, variant, update, {"nested": True}, nesting, nesting_long_names)
|
||||
(sub_component_group, _) = process_component.process_component(registry, variant, update, {"nested": True}, nesting_long_names=nesting_long_names)
|
||||
additional_annotations[variant_prefixed_name] = sub_component_group
|
||||
else: # for the cases where it's neither a tupple nor a structs: FIXME: not 100% sure of this
|
||||
#print("other variant in enum")
|
||||
|
|
|
@ -2,15 +2,13 @@ from bpy.props import (StringProperty, IntProperty, CollectionProperty)
|
|||
from .utils import generate_wrapper_propertyGroup
|
||||
from . import process_component
|
||||
|
||||
def process_list(registry, definition, update, nesting=[], nesting_long_names=[]):
|
||||
def process_list(registry, definition, update, nesting_long_names=[]):
|
||||
value_types_defaults = registry.value_types_defaults
|
||||
type_infos = registry.type_infos
|
||||
|
||||
short_name = definition["short_name"]
|
||||
long_name = definition["long_name"]
|
||||
ref_name = definition["items"]["type"]["$ref"].replace("#/$defs/", "")
|
||||
|
||||
nesting = nesting+[short_name]
|
||||
nesting_long_names = nesting_long_names + [long_name]
|
||||
|
||||
item_definition = type_infos[ref_name]
|
||||
|
@ -20,9 +18,9 @@ def process_list(registry, definition, update, nesting=[], nesting_long_names=[]
|
|||
property_group_class = None
|
||||
#if the content of the list is a unit type, we need to generate a fake wrapper, otherwise we cannot use layout.prop(group, "propertyName") as there is no propertyName !
|
||||
if is_item_value_type:
|
||||
property_group_class = generate_wrapper_propertyGroup(long_name, item_long_name, definition["items"]["type"]["$ref"], registry, update)
|
||||
property_group_class = generate_wrapper_propertyGroup(long_name, item_long_name, definition["items"]["type"]["$ref"], registry, update, nesting_long_names=nesting_long_names)
|
||||
else:
|
||||
(_, list_content_group_class) = process_component.process_component(registry, item_definition, update, {"nested": True, "long_name": item_long_name}, nesting)
|
||||
(_, list_content_group_class) = process_component.process_component(registry, item_definition, update, {"nested": True, "long_name": item_long_name}, nesting_long_names=nesting_long_names)
|
||||
property_group_class = list_content_group_class
|
||||
|
||||
item_collection = CollectionProperty(type=property_group_class)
|
||||
|
|
|
@ -2,14 +2,12 @@ from bpy.props import (StringProperty, IntProperty, CollectionProperty, PointerP
|
|||
from .utils import generate_wrapper_propertyGroup
|
||||
from . import process_component
|
||||
|
||||
def process_map(registry, definition, update, nesting=[], nesting_long_names=[]):
|
||||
def process_map(registry, definition, update, nesting_long_names=[]):
|
||||
value_types_defaults = registry.value_types_defaults
|
||||
type_infos = registry.type_infos
|
||||
|
||||
short_name = definition["short_name"]
|
||||
long_name = definition["long_name"]
|
||||
|
||||
nesting = nesting + [short_name]
|
||||
nesting_long_names = nesting_long_names + [long_name]
|
||||
|
||||
value_ref_name = definition["valueType"]["type"]["$ref"].replace("#/$defs/", "")
|
||||
|
@ -26,9 +24,9 @@ def process_map(registry, definition, update, nesting=[], nesting_long_names=[])
|
|||
|
||||
#if the content of the list is a unit type, we need to generate a fake wrapper, otherwise we cannot use layout.prop(group, "propertyName") as there is no propertyName !
|
||||
if is_key_value_type:
|
||||
keys_property_group_class = generate_wrapper_propertyGroup(f"{long_name}_keys", original_long_name, definition_link, registry, update)
|
||||
keys_property_group_class = generate_wrapper_propertyGroup(f"{long_name}_keys", original_long_name, definition_link, registry, update, nesting_long_names=nesting_long_names)
|
||||
else:
|
||||
(_, list_content_group_class) = process_component.process_component(registry, key_definition, update, {"nested": True, "long_name": original_long_name}, nesting, nesting_long_names)
|
||||
(_, list_content_group_class) = process_component.process_component(registry, key_definition, update, {"nested": True, "long_name": original_long_name}, nesting_long_names=nesting_long_names)
|
||||
keys_property_group_class = list_content_group_class
|
||||
|
||||
keys_collection = CollectionProperty(type=keys_property_group_class)
|
||||
|
@ -45,9 +43,9 @@ def process_map(registry, definition, update, nesting=[], nesting_long_names=[])
|
|||
|
||||
#if the content of the list is a unit type, we need to generate a fake wrapper, otherwise we cannot use layout.prop(group, "propertyName") as there is no propertyName !
|
||||
if is_value_value_type:
|
||||
values_property_group_class = generate_wrapper_propertyGroup(f"{long_name}_values", original_long_name, definition_link, registry, update)
|
||||
values_property_group_class = generate_wrapper_propertyGroup(f"{long_name}_values", original_long_name, definition_link, registry, update, nesting_long_names)
|
||||
else:
|
||||
(_, list_content_group_class) = process_component.process_component(registry, value_definition, update, {"nested": True, "long_name": original_long_name}, nesting, nesting_long_names)
|
||||
(_, list_content_group_class) = process_component.process_component(registry, value_definition, update, {"nested": True, "long_name": original_long_name}, nesting_long_names)
|
||||
values_property_group_class = list_content_group_class
|
||||
|
||||
values_collection = CollectionProperty(type=values_property_group_class)
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
from bpy.props import (StringProperty)
|
||||
from . import process_component
|
||||
|
||||
def process_structs(registry, definition, properties, update, nesting, nesting_long_names):
|
||||
def process_structs(registry, definition, properties, update, nesting_long_names):
|
||||
value_types_defaults = registry.value_types_defaults
|
||||
blender_property_mapping = registry.blender_property_mapping
|
||||
type_infos = registry.type_infos
|
||||
long_name = definition["long_name"]
|
||||
short_name = definition["short_name"]
|
||||
|
||||
__annotations__ = {}
|
||||
default_values = {}
|
||||
nesting = nesting + [short_name]
|
||||
nesting_long_names = nesting_long_names + [long_name]
|
||||
|
||||
for property_name in properties.keys():
|
||||
|
@ -35,7 +33,7 @@ def process_structs(registry, definition, properties, update, nesting, nesting_l
|
|||
__annotations__[property_name] = blender_property
|
||||
else:
|
||||
original_long_name = original["long_name"]
|
||||
(sub_component_group, _) = process_component.process_component(registry, original, update, {"nested": True, "long_name": original_long_name}, nesting, nesting_long_names)
|
||||
(sub_component_group, _) = process_component.process_component(registry, original, update, {"nested": True, "long_name": original_long_name}, nesting_long_names)
|
||||
__annotations__[property_name] = sub_component_group
|
||||
# if there are sub fields, add an attribute "sub_fields" possibly a pointer property ? or add a standard field to the type , that is stored under "attributes" and not __annotations (better)
|
||||
else:
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
from bpy.props import (StringProperty)
|
||||
from . import process_component
|
||||
|
||||
def process_tupples(registry, definition, prefixItems, update, nesting=[], nesting_long_names=[]):
|
||||
def process_tupples(registry, definition, prefixItems, update, nesting_long_names=[]):
|
||||
value_types_defaults = registry.value_types_defaults
|
||||
blender_property_mapping = registry.blender_property_mapping
|
||||
type_infos = registry.type_infos
|
||||
long_name = definition["long_name"]
|
||||
short_name = definition["short_name"]
|
||||
|
||||
nesting = nesting + [short_name]
|
||||
nesting_long_names = nesting_long_names + [long_name]
|
||||
__annotations__ = {}
|
||||
|
||||
|
@ -41,7 +39,7 @@ def process_tupples(registry, definition, prefixItems, update, nesting=[], nesti
|
|||
__annotations__[property_name] = blender_property
|
||||
else:
|
||||
original_long_name = original["long_name"]
|
||||
(sub_component_group, _) = process_component.process_component(registry, original, update, {"nested": True, "long_name": original_long_name}, nesting)
|
||||
(sub_component_group, _) = process_component.process_component(registry, original, update, {"nested": True, "long_name": original_long_name}, nesting_long_names=nesting_long_names)
|
||||
__annotations__[property_name] = sub_component_group
|
||||
else:
|
||||
# component not found in type_infos, generating placeholder
|
||||
|
|
|
@ -37,9 +37,9 @@ def generate_propertyGroups_for_components():
|
|||
for component_name in type_infos:
|
||||
definition = type_infos[component_name]
|
||||
is_component = definition['isComponent'] if "isComponent" in definition else False
|
||||
root_property_name = component_name if is_component else None
|
||||
#print("root property", root_property_name)
|
||||
process_component(registry, definition, update_calback_helper(definition, update_component, root_property_name), None, [])
|
||||
root_property_name = component_name# if is_component else None
|
||||
print("root property", component_name,f"({is_component})")
|
||||
process_component(registry, definition, update_calback_helper(definition, update_component, root_property_name), extras=None, nesting_long_names=[])
|
||||
|
||||
# if we had to add any wrapper types on the fly, process them now
|
||||
registry.process_custom_types()
|
|
@ -8,12 +8,16 @@ from bpy_types import PropertyGroup
|
|||
|
||||
# this helper creates a "fake"/wrapper property group that is NOT a real type in the registry
|
||||
# usefull for things like value types in list items etc
|
||||
def generate_wrapper_propertyGroup(wrapped_type_long_name_name, item_long_name, definition_link, registry, update):
|
||||
def generate_wrapper_propertyGroup(wrapped_type_long_name, item_long_name, definition_link, registry, update, nesting_long_names=[]):
|
||||
value_types_defaults = registry.value_types_defaults
|
||||
blender_property_mapping = registry.blender_property_mapping
|
||||
is_item_value_type = item_long_name in value_types_defaults
|
||||
|
||||
wrapper_name = "wrapper_" + wrapped_type_long_name_name
|
||||
|
||||
wrapper_name = "wrapper_" + wrapped_type_long_name
|
||||
|
||||
#nesting = nesting + [short_name]
|
||||
nesting_long_names = nesting_long_names + [wrapper_name]
|
||||
|
||||
wrapper_definition = {
|
||||
"isComponent": False,
|
||||
|
@ -33,7 +37,7 @@ def generate_wrapper_propertyGroup(wrapped_type_long_name_name, item_long_name,
|
|||
}
|
||||
|
||||
# we generate a very small 'hash' for the component name
|
||||
property_group_name = registry.generate_propGroup_name(nesting=[], longName=wrapper_name)
|
||||
property_group_name = registry.generate_propGroup_name(nesting=nesting_long_names)
|
||||
registry.add_custom_type(wrapper_name, wrapper_definition)
|
||||
|
||||
|
||||
|
|
|
@ -217,25 +217,27 @@ class ComponentsRegistry(PropertyGroup):
|
|||
|
||||
long_names_to_propgroup_names = {}
|
||||
|
||||
# generate propGroup name from nesting level & longName: each longName + nesting is unique
|
||||
def generate_propGroup_name(self, nesting, longName):
|
||||
# generate propGroup name from nesting level: each longName + nesting is unique
|
||||
def generate_propGroup_name(self, nesting):
|
||||
#print("gen propGroup name for", shortName, nesting)
|
||||
key = str(nesting) + longName if len(nesting) > 0 else longName
|
||||
key = str(nesting)
|
||||
|
||||
propGroupHash = tiger_hash(key)
|
||||
propGroupName = propGroupHash + "_ui"
|
||||
|
||||
# check for collision
|
||||
#print("--computing hash for", nesting, longName)
|
||||
padding = " " * (len(nesting) + 1)
|
||||
|
||||
print(f"{padding}--computing hash for", nesting)
|
||||
if propGroupName in self.long_names_to_propgroup_names.values():
|
||||
print(" WARNING !! you have a collision between the hash of multiple component names: collision for", nesting, longName)
|
||||
print(" WARNING !! you have a collision between the hash of multiple component names: collision for", nesting)
|
||||
|
||||
self.long_names_to_propgroup_names[key] = propGroupName
|
||||
|
||||
return propGroupName
|
||||
|
||||
def get_propertyGroupName_from_longName(self, longName):
|
||||
return self.long_names_to_propgroup_names.get(longName, None)
|
||||
return self.long_names_to_propgroup_names.get(str([longName]), None)
|
||||
|
||||
|
||||
###########
|
||||
|
|
|
@ -62,15 +62,15 @@ class ComponentsSettings(PropertyGroup):
|
|||
|
||||
schema_path: StringProperty(
|
||||
name="schema path",
|
||||
description="path to the registry schema file",
|
||||
description="path to the registry schema file (relative to the assets path)",
|
||||
default="registry.json",
|
||||
update=save_settings
|
||||
)# type: ignore
|
||||
|
||||
schema_path_full: StringProperty(
|
||||
name="schema full path",
|
||||
description="path to the registry schema file",
|
||||
get=lambda self: os.path.abspath(os.path.join(os.path.dirname(bpy.data.filepath), self.schema_path))
|
||||
description="full path to the registry schema file",
|
||||
get=lambda self: os.path.abspath(os.path.join(bpy.context.window_manager.blenvy.assets_path_full, self.schema_path))
|
||||
) # type: ignore
|
||||
|
||||
watcher_enabled: BoolProperty(name="Watcher_enabled", default=True, update=toggle_watcher)# type: ignore
|
||||
|
|
Loading…
Reference in New Issue