From 8c7e9d5d992745b34a4bc2ed962a315e5c230fc8 Mon Sep 17 00:00:00 2001 From: Petru Conduraru Date: Tue, 21 Jul 2026 09:45:46 +0300 Subject: [PATCH] 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. --- .../api/attribute/edit_attributes.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/ifcopenshell-python/ifcopenshell/api/attribute/edit_attributes.py b/src/ifcopenshell-python/ifcopenshell/api/attribute/edit_attributes.py index 1f46e70921..8752c94e9a 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/attribute/edit_attributes.py +++ b/src/ifcopenshell-python/ifcopenshell/api/attribute/edit_attributes.py @@ -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