diff --git a/src/ifcopenshell-python/ifcopenshell/geom/main.py b/src/ifcopenshell-python/ifcopenshell/geom/main.py index 08ce72fae7..f1ef0d2a74 100644 --- a/src/ifcopenshell-python/ifcopenshell/geom/main.py +++ b/src/ifcopenshell-python/ifcopenshell/geom/main.py @@ -505,8 +505,8 @@ def create_shape( """ Returns a geometric interpretation of the IFC entity instance - Note that in Python, you must store a reference to the element returned by this function to prevent garbage - collection when you access its children. See #1124. + The returned element's ``geometry`` keeps a reference to its owning element, so accessing children + (e.g. ``create_shape(...).geometry.verts``) no longer requires holding onto the element. See #1124. :raises RuntimeError: If failed to process shape. You can turn detailed logging to get more details. diff --git a/src/ifcwrap/IfcGeomWrapper.i b/src/ifcwrap/IfcGeomWrapper.i index 0ffec8477f..8c619fb91e 100644 --- a/src/ifcwrap/IfcGeomWrapper.i +++ b/src/ifcwrap/IfcGeomWrapper.i @@ -888,14 +888,24 @@ struct ShapeRTTI : public boost::static_visitor %extend IfcGeom::TriangulationElement { %pythoncode %{ # Hide the getters with read-only property implementations - geometry = property(geometry) + # Keep the owning element alive while its geometry is referenced (#1124). + def _geometry_with_backref(self, _f=geometry): + result = _f(self) + result._parent = self + return result + geometry = property(_geometry_with_backref) %} }; %extend IfcGeom::SerializedElement { %pythoncode %{ # Hide the getters with read-only property implementations - geometry = property(geometry) + # Keep the owning element alive while its geometry is referenced (#1124). + def _geometry_with_backref(self, _f=geometry): + result = _f(self) + result._parent = self + return result + geometry = property(_geometry_with_backref) %} }; @@ -920,10 +930,15 @@ struct ShapeRTTI : public boost::static_visitor %pythoncode %{ # Hide the getters with read-only property implementations - geometry = property(geometry) + # Keep the owning element alive while its geometry is referenced (#1124). + def _geometry_with_backref(self, _f=geometry): + result = _f(self) + result._parent = self + return result + geometry = property(_geometry_with_backref) volume = property(calc_volume_) surface_area = property(calc_surface_area_) - %} + %} }; /*