From 60b4f6191c87611c371a68d5a20aa4d0431cb47b Mon Sep 17 00:00:00 2001 From: Stephen Boddy Date: Sat, 11 Jul 2026 15:07:06 +0100 Subject: [PATCH] Allow process/resource type assignment via Type-suffix convention The class-pairing validation added in 10ee5aef4f rejects any type assignment whose class isn't in the buildingSMART implementer agreement map. That map only covers physical product occurrence/type pairs (IfcWallType -> IfcWall, etc); IfcTypeProcess and IfcTypeResource subtypes such as IfcTaskType, IfcProcedureType and the resource types have no entry, so previously-valid assignments like IfcTaskType -> IfcTask were rejected with "allowed occurrence classes: ". These classes still follow the schema's universal Type-suffix naming convention, so derive the pairing the same way the existing ApplicableOccurrence fallback does: strip "Type" from the relating type's class name and accept it only if the schema actually declares that entity. This can only add pairings implied by the type's own class name, so it cannot loosen the existing rejection of genuine mismatches (e.g. IfcWallType -> IfcWindow). Generated with the assistance of an AI coding tool. (cherry picked from commit d188e3beaf2f79a3ca82afc3a1d43524e53abd3b) --- .../ifcopenshell/api/type/assign_type.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/ifcopenshell-python/ifcopenshell/api/type/assign_type.py b/src/ifcopenshell-python/ifcopenshell/api/type/assign_type.py index 3087811234..54723c754e 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/type/assign_type.py +++ b/src/ifcopenshell-python/ifcopenshell/api/type/assign_type.py @@ -196,13 +196,25 @@ class Usecase: allowed_occurrences = set( ifcopenshell.util.type.get_applicable_entities(relating_type.is_a(), schema=self.file.schema) ) + schema = ifcopenshell.schema_by_name(self.file.schema) + # The implementer agreement map has no entry for the abstract # IfcTypeProduct, which Bonsai uses for annotation types. The schema # itself defines IfcTypeProduct.ApplicableOccurrence for exactly this # purpose, so honor it when the leading class token is a valid entity. if applicable_occurrence := getattr(relating_type, "ApplicableOccurrence", None): occurrence_class = applicable_occurrence.split("/", 1)[0] - schema = ifcopenshell.schema_by_name(self.file.schema) + try: + schema.declaration_by_name(occurrence_class) + allowed_occurrences.add(occurrence_class) + except RuntimeError: + pass + # The map only covers physical product occurrence/type pairs (e.g. + # IfcWallType -> IfcWall). Process and resource types (IfcTaskType, + # IfcCrewResourceType, ...) aren't in it, but the schema's universal + # Type-suffix naming convention gives the same pairing directly. + if (type_class := relating_type.is_a()).endswith("Type"): + occurrence_class = type_class[: -len("Type")] try: schema.declaration_by_name(occurrence_class) allowed_occurrences.add(occurrence_class)