Compare commits

...

1 Commits

Author SHA1 Message Date
Petru Conduraru 8c7e9d5d99 ifcopenshell.api.attribute: clear occurrence PredefinedType when type becomes concrete
assign_type() already clears an occurrence's PredefinedType/ObjectType
when it is assigned to a type with a concrete PredefinedType (#7006).
But if the type's own PredefinedType is edited to a concrete value
after occurrences are already assigned to it (e.g. via Bonsai's Edit
Type Attributes), edit_attributes() only kept the type's own
PredefinedType/ElementType consistent and never touched its
occurrences, leaving them with a stale explicit PredefinedType
(often NOTDEFINED, e.g. carried in from an import) alongside a
concretely typed type. This combination fails buildingSMART's OJT001
rule on export. Mirror assign_type()'s clearing so it also applies
when the type is edited, not just when it is assigned.

Generated with the assistance of an AI coding tool.
2026-07-21 09:45:46 +03:00
@@ -38,6 +38,10 @@ def edit_attributes(file: ifcopenshell.file, product: ifcopenshell.entity_instan
- PredefinedType to be "NOTDEFINED" if ElementType/ObjectType is None
- PredefinedType to be "USERDEFINED" if ElementType/ObjectType is not None
If a type's own PredefinedType becomes a concrete value, its already
typed occurrences have their PredefinedType/ObjectType cleared to forbid
double typing (see #7006).
:param product: The product you want to edit. This may be any rooted IFC
entity.
:param attributes: a dictionary of attribute names and values.
@@ -70,6 +74,19 @@ def edit_attributes(file: ifcopenshell.file, product: ifcopenshell.entity_instan
elif element_type and predefined_type != "USERDEFINED":
product.PredefinedType = "USERDEFINED"
# Remove occurrences' PredefinedType / ObjectType to forbid double typing (see #7006)
type_predefined_type = ifcopenshell.util.element.get_predefined_type(product)
if type_predefined_type not in ("NOTDEFINED", None):
if hasattr(product, "ObjectTypeOf"):
types_rel = next(iter(product.ObjectTypeOf), None)
else:
types_rel = next(iter(getattr(product, "Types", ())), None)
if types_rel:
for obj in types_rel.RelatedObjects:
obj.ObjectType = None
if hasattr(obj, "PredefinedType"):
obj.PredefinedType = None
elif (object_type := getattr_safe(product, "ObjectType")) is not ...:
relating_type = ifcopenshell.util.element.get_type(product)
# Allow for None due to https://github.com/buildingSMART/IFC4.3.x-development/issues/818