I don't really understand this, but I get a crash. Example code:
import ifcopenshell
f = ifcopenshell.file()
c = f.createIfcGeometricRepresentationContext()
print("1", c.HasSubContexts)
sc = f.create_entity("IfcGeometricRepresentationSubContext", **{"ParentContext": c})
print("2", c.HasSubContexts)
sc2 = f.create_entity("IfcGeometricRepresentationSubContext", **{"ParentContext": c})
print("3", c.HasSubContexts) # If I comment this line out, no segfault
f.remove(sc)
f.remove(sc2)
print("4", c.HasSubContexts)
This results in:
1 ()
2 (#2=IfcGeometricRepresentationSubContext($,$,*,*,*,*,#1,$,$,$),)
3 (#2=IfcGeometricRepresentationSubContext($,$,*,*,*,*,#1,$,$,$), #3=IfcGeometricRepresentationSubContext($,$,*,*,*,*,#1,$,$,$))
[1] 4518 segmentation fault python test.py
If I comment out print("3", c.HasSubContexts), no segfault occurs:
1 ()
2 (#2=IfcGeometricRepresentationSubContext($,$,*,*,*,*,#1,$,$,$),)
4 ()
I can reproduce it but no idea neither.
Yes, I guess removal with inverse attributes is still buggy as the index is not properly updated. I'll look into it. As a work-around you can rewrite it using forward attributes:
[sc for sc in f.by_type("IfcGeometricRepresentationSubContext") if sc.ParentContext is c]
Cheers :) I've indeed used forward attributes as a workaround with a note pointing to this bug: https://github.com/IfcOpenShell/IfcOpenShell/blob/v0.6.0/src/ifcblenderexport/blenderbim/bim/module/context/data.py#L16
I think this is the exact same bug, but thought I'd check:
f = ifcopenshell.open("/home/dion/Downloads/JudgesReception.ifc")
e = f.by_id(653)
print(len(e.HasOpenings)) # 2
f.remove(e.HasOpenings[0])
print(e.HasOpenings) # Segfault
In this case, is there any workaround? If I simply loop through all the IfcRelVoidsElements and never access any inverse relations I can derive the same relationships, but that sounds incredibly inefficient... though it does work I guess...
One more issue which really tripped me up and I spent a long time hunting down...
In this scenario, none of my code directly access any inverse attributes. opening is an arbitrary IfcOpeningElement, and rel is the IfcRelVoidsElement that references opening. However, I believe the geometry iterator internally accesses the inverse attributes... so if I then try to run the remove function, I get a segfault.
I've also tested with DISABLE_OPENING_SUBTRACTIONS set to True which doesn't seem to make an impact.
Because my code relies on the iterator, I can't see any workaround in this scenario (unless the workaround is to modify how the iterator works... but in that case maybe a better solution is to fix the fundamental problem)?
Edit: I can delete the opening first, and then delete the rel to avoid the segfault. I think I may be getting the hang of these workarounds... :) Phew! At least it isn't a showstopper!
import ifcopenshell
import ifcopenshell.geom
f = ifcopenshell.open("/home/dion/Downloads/JudgesReception.ifc")
opening = f.by_id(70332)
rel = f.by_id(70335)
iterator = ifcopenshell.geom.iterator(ifcopenshell.geom.settings(), f)
iterator.initialize()
while True:
iterator.get()
if not iterator.next():
break
f.remove(rel)
f.remove(opening) # Segfault, due to iterator
Just commenting to link this to #1222 - since the purpose of #1222 is to edit the file in memory, but this creates lots of complications for removing elements.
Sorry for yet another bump on this bug. I don't get this one at all, since I don't understand why the ContainedInStructure has any relationship to the IfcRelFillsElement:
import ifcopenshell
f = ifcopenshell.open("/home/dion/Downloads/JudgesReception.ifc")
opening = f.by_id(70332)
rel_fill = opening.HasFillings[0]
filling = rel_fill.RelatedBuildingElement
print(filling.ContainedInStructure) # If this line is removed, no segfault
f.remove(rel_fill)
print(filling.ContainedInStructure) # Segfault
This appears to be an artefact from #482. Thanks for the detailed report. I don't have this Judges file so I didn't test all of your snippets but I tested two which were fixed by the commit. These seem like good candidates to make it into a unit test.....
Edit:
as manipulating data and inspecting inverses are usually not done simultaneously
Haha famous last words from my comments on #482
Thanks so much! I'll wait for the bot build and let you know how it goes... however I did attach the JudgesReception file!
Yeah thanks I checked also the last snippet from yesterday appeared fine, build started.
@aothms awesome it works! I'll continue testing to see if I come across any other scenarios where something funky happens!
Thanks so much again for such a quick fix!