diff --git a/src/ifcopenshell-python/ifcopenshell/util/doc.py b/src/ifcopenshell-python/ifcopenshell/util/doc.py index dda112ae5d..664d9561cc 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/doc.py +++ b/src/ifcopenshell-python/ifcopenshell/util/doc.py @@ -160,20 +160,30 @@ def get_type_doc(version, ifc_type): return db["types"].get(ifc_type) +# TODO: there are still some discrepancies between this method +# and the specs website because of the asymmetry +# More: https://github.com/buildingSMART/IFC4.3.x-development/issues/582 def get_inverse_attributes(el): inverse_attrs = [] for a in el.all_inverse_attributes(): attribute_type = a.attribute_reference().type_of_attribute() - if isinstance(attribute_type, ifcopenshell.ifcopenshell_wrapper.aggregation_type): + # unpacking aggregation types + while isinstance(attribute_type, ifcopenshell.ifcopenshell_wrapper.aggregation_type): attribute_type = attribute_type.type_of_element() attribute_type = attribute_type.declared_type() - if not isinstance(attribute_type, ifcopenshell.ifcopenshell_wrapper.entity): - attr_types = [t.name() for t in attribute_type.select_list()] - else: - attr_types = [attribute_type.name()] + # recursively looking for entities inside the selections + types_to_process = [attribute_type] + entity_attr_types = [] + while types_to_process: + for attr_type in types_to_process.copy(): + if isinstance(attr_type, ifcopenshell.ifcopenshell_wrapper.select_type): + types_to_process.extend([t for t in attr_type.select_list()]) + else: + entity_attr_types.append(attr_type.name()) + types_to_process.remove(attr_type) - if el.name() in attr_types: + if el.name() in entity_attr_types: inverse_attrs.append(a) return inverse_attrs