diff --git a/src/ifcopenshell-python/ifcopenshell/geom/main.py b/src/ifcopenshell-python/ifcopenshell/geom/main.py index 9cf79934aa..c64d262e6f 100644 --- a/src/ifcopenshell-python/ifcopenshell/geom/main.py +++ b/src/ifcopenshell-python/ifcopenshell/geom/main.py @@ -482,8 +482,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 10c9b02395..b6dffb3b6e 100644 --- a/src/ifcwrap/IfcGeomWrapper.i +++ b/src/ifcwrap/IfcGeomWrapper.i @@ -793,14 +793,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) %} }; @@ -825,10 +835,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_) - %} + %} }; /*