mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 17:58:20 +00:00
Prioritize existing data types for templates props for safety
Noticed working on #5596 and #5708 a few issue when pset template is changing the prop types. E.g. prop had string data type and now template suggests that it should be a float. Previously, it might error trying to cast a string to a float. Now it will show a float until user will set it to null, then next time it will be loaded from the template data type. Another example - prop was a string and now it's a boolean. Previously, it would be cast to boolean implicitly. E.g. "test" -> bool("test") -> True. And if user wouldn't be paying attention then enabling pset editing and saving it would make them lose "test" value. Now - https://imgchest.com/p/na7ke99wb78 Before - https://imgchest.com/p/5xy23rr3z4l
This commit is contained in:
@@ -252,19 +252,38 @@ class Pset(bonsai.core.tool.Pset):
|
|||||||
props: bpy.types.PropertyGroup,
|
props: bpy.types.PropertyGroup,
|
||||||
) -> None:
|
) -> None:
|
||||||
if pset:
|
if pset:
|
||||||
data = ifcopenshell.util.element.get_property_definition(pset)
|
data = ifcopenshell.util.element.get_property_definition(pset, verbose=True)
|
||||||
del data["id"]
|
del data["id"]
|
||||||
else:
|
else:
|
||||||
data = {}
|
data = {}
|
||||||
|
simplified_data = {prop_name: prop_data["value"] for prop_name, prop_data in data.items()}
|
||||||
|
|
||||||
|
# For every prop we first ensure that existing prop value type matches the template value type
|
||||||
|
# to prevent data loss and error casting data.
|
||||||
|
# Property will be added later by import_pset_from_existing.
|
||||||
for prop_template in sorted(pset_template.HasPropertyTemplates, key=lambda p: p.Name):
|
for prop_template in sorted(pset_template.HasPropertyTemplates, key=lambda p: p.Name):
|
||||||
if not prop_template.is_a("IfcSimplePropertyTemplate"):
|
if not prop_template.is_a("IfcSimplePropertyTemplate"):
|
||||||
continue # Other types not yet supported
|
continue # Other types not yet supported
|
||||||
|
prop_data = data.get(prop_template.Name)
|
||||||
if prop_template.TemplateType == "P_SINGLEVALUE":
|
if prop_template.TemplateType == "P_SINGLEVALUE":
|
||||||
cls.import_single_value_from_template(pset_template, prop_template, data, props)
|
if prop_data:
|
||||||
|
if prop_data["class"] != "IfcPropertySingleValue":
|
||||||
|
continue
|
||||||
|
template_data_type = cls.get_prop_template_primitive_type(prop_template)
|
||||||
|
existing_data_type = prop_data.get("value_type", None)
|
||||||
|
if existing_data_type and template_data_type != existing_data_type:
|
||||||
|
continue
|
||||||
|
continue
|
||||||
|
cls.import_single_value_from_template(pset_template, prop_template, simplified_data, props)
|
||||||
|
|
||||||
elif prop_template.TemplateType.startswith("Q_"):
|
elif prop_template.TemplateType.startswith("Q_"):
|
||||||
cls.import_single_value_from_template(pset_template, prop_template, data, props)
|
cls.import_single_value_from_template(pset_template, prop_template, simplified_data, props)
|
||||||
|
|
||||||
elif prop_template.TemplateType == "P_ENUMERATEDVALUE":
|
elif prop_template.TemplateType == "P_ENUMERATEDVALUE":
|
||||||
cls.import_enumerated_value_from_template(prop_template, data, props)
|
if prop_data and prop_data["class"] != "IfcPropertyEnumeratedValue":
|
||||||
|
continue
|
||||||
|
cls.import_enumerated_value_from_template(prop_template, simplified_data, props)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# NOTE: currently unsupported types:
|
# NOTE: currently unsupported types:
|
||||||
# - P_BOUNDEDVALUE
|
# - P_BOUNDEDVALUE
|
||||||
|
|||||||
@@ -411,14 +411,14 @@ class Usecase:
|
|||||||
raise TypeError(f"'{self.settings['pset']}' is not a valid pset")
|
raise TypeError(f"'{self.settings['pset']}' is not a valid pset")
|
||||||
|
|
||||||
def get_primary_measure_type(self, name, old_value=None, new_value=None):
|
def get_primary_measure_type(self, name, old_value=None, new_value=None):
|
||||||
|
if old_value:
|
||||||
|
return old_value.is_a()
|
||||||
if self.pset_template:
|
if self.pset_template:
|
||||||
for prop_template in self.pset_template.HasPropertyTemplates:
|
for prop_template in self.pset_template.HasPropertyTemplates:
|
||||||
if prop_template.Name != name:
|
if prop_template.Name != name:
|
||||||
continue
|
continue
|
||||||
return prop_template.PrimaryMeasureType or "IfcLabel"
|
return prop_template.PrimaryMeasureType or "IfcLabel"
|
||||||
if old_value:
|
if new_value and hasattr(new_value, "is_a"):
|
||||||
return old_value.is_a()
|
|
||||||
elif new_value and hasattr(new_value, "is_a"):
|
|
||||||
return new_value.is_a()
|
return new_value.is_a()
|
||||||
elif new_value is not None:
|
elif new_value is not None:
|
||||||
if isinstance(new_value, str):
|
if isinstance(new_value, str):
|
||||||
|
|||||||
@@ -394,6 +394,7 @@ def get_properties(
|
|||||||
"id": prop.id(),
|
"id": prop.id(),
|
||||||
"class": prop.is_a(),
|
"class": prop.is_a(),
|
||||||
"value": results[prop_name],
|
"value": results[prop_name],
|
||||||
|
"value_type": v.is_a() if v else None,
|
||||||
}
|
}
|
||||||
elif ifc_class == "IfcPropertyEnumeratedValue":
|
elif ifc_class == "IfcPropertyEnumeratedValue":
|
||||||
# 2 IfcPropertyEnumeratedValue.EnumerationValues
|
# 2 IfcPropertyEnumeratedValue.EnumerationValues
|
||||||
|
|||||||
Reference in New Issue
Block a user