simpler way to check if enum property is valid

Well, it's simpler to use but not really simpler in implementation 😅
Thanks to @Gorgious56 for helping out
Hopefully, it's a farewell to those annoying warnings

see https://blenderartists.org/t/best-way-to-handle-dynamic-enum-items-without-pyrna-enum-to-py-current-value-matches-no-enum
This commit is contained in:
Andrej730
2024-05-22 18:44:12 +05:00
parent f2eb08a066
commit 1aaccba803
3 changed files with 35 additions and 15 deletions
@@ -121,9 +121,10 @@ class AuthoringData:
def type_thumbnail(cls): def type_thumbnail(cls):
if not cls.data["relating_type_id"]: if not cls.data["relating_type_id"]:
return 0 return 0
if not tool.Blender.enum_property_has_valid_index(cls.props, "relating_type_id", cls.data["relating_type_id"]): relating_type_id = tool.Blender.get_enum_safe(cls.props, "relating_type_id")
if relating_type_id is None:
return 0 return 0
element = tool.Ifc.get().by_id(int(cls.props.relating_type_id)) element = tool.Ifc.get().by_id(int(relating_type_id))
return cls.type_thumbnails.get(element.id(), None) or 0 return cls.type_thumbnails.get(element.id(), None) or 0
@classmethod @classmethod
@@ -251,10 +252,8 @@ class AuthoringData:
@classmethod @classmethod
def predefined_type(cls): def predefined_type(cls):
if not tool.Blender.enum_property_has_valid_index(cls.props, "relating_type_id", cls.data["relating_type_id"]): relating_type_id = tool.Blender.get_enum_safe(cls.props, "relating_type_id")
return if relating_type_id is None:
relating_type_id = cls.props.relating_type_id
if not relating_type_id:
return return
relating_type = tool.Ifc.get().by_id(int(relating_type_id)) relating_type = tool.Ifc.get().by_id(int(relating_type_id))
if not hasattr(relating_type, "PredefinedType"): if not hasattr(relating_type, "PredefinedType"):
@@ -60,7 +60,7 @@ def update_ifc_class(self, context):
bpy.ops.bim.load_type_thumbnails(ifc_class=self.ifc_class) bpy.ops.bim.load_type_thumbnails(ifc_class=self.ifc_class)
AuthoringData.data["relating_type_id"] = AuthoringData.relating_type_id() AuthoringData.data["relating_type_id"] = AuthoringData.relating_type_id()
AuthoringData.data["type_thumbnail"] = AuthoringData.type_thumbnail() AuthoringData.data["type_thumbnail"] = AuthoringData.type_thumbnail()
if not tool.Blender.enum_property_has_valid_index(self, "relating_type_id", AuthoringData.data["relating_type_id"]): if tool.Blender.get_enum_safe(self, "relating_type_id") is None:
self["relating_type_id"] = 0 self["relating_type_id"] = 0
+29 -8
View File
@@ -468,20 +468,41 @@ class Blender(blenderbim.core.tool.Blender):
active_object.select_set(True) active_object.select_set(True)
@classmethod @classmethod
def enum_property_has_valid_index(cls, props: bpy.types.PropertyGroup, prop_name: str, enum_items: tuple) -> bool: def get_enum_safe(cls, props: bpy.types.PropertyGroup, prop_name: str) -> Union[str, None]:
"""method created for readibility and to avoid console warnings like """method created for readibility and to avoid console warnings like
`pyrna_enum_to_py: current value '17' matches no enum in 'BIMModelProperties', '', 'relating_type_id'` `pyrna_enum_to_py: current value '17' matches no enum in 'BIMModelProperties', '', 'relating_type_id'`
""" """
items_amount = len(enum_items) # Yes, accessing items through annotations is a bit hacky
# but it's the only way to get the dynamic enum items
# besides providing them to get_enum_safe explicitly.
prop_keywords = props.__annotations__[prop_name].keywords
items = prop_keywords.get("items")
if items is None:
return None
if not isinstance(items, (list, tuple)):
# items are retrieved through a callback, not a static list / tuple :
items = items(props, bpy.context)
items_amount = len(items)
# If enum has no items it seems to always produce a warning. # If enum has no items it seems to always produce a warning.
# E.g. if you try to get it's value directly: `BIMModelProperties.relating_type_id`. # E.g. if you try to get it's value directly: `BIMModelProperties.relating_type_id`.
if items_amount == 0: if items_amount == 0:
return False return None
current_value_index = props.get(prop_name, None)
# assuming the default value is fine index = props.get(prop_name)
if current_value_index is None: # If value was never changed (still default), we can just retrieve it from the enum.
return True if index is None:
return current_value_index < items_amount default_value = prop_keywords.get("default")
if isinstance(default_value, int):
index = default_value
else:
# If default value is a string then it's a static enum
# and we can just return it.
return default_value
# Ensure index is valid.
if items_amount > index >= 0:
return items[index][0]
return None
@classmethod @classmethod
def append_data_block(cls, filepath: str, data_block_type: str, name: str, link=False, relative=False) -> dict: def append_data_block(cls, filepath: str, data_block_type: str, name: str, link=False, relative=False) -> dict: