Skip to content
This repository was archived by the owner on Nov 24, 2024. It is now read-only.

Commit 76e6c63

Browse files
committed
ifc2x3 tests - prevent using removed user/application
When some test was creating an element and then removing it, it would also remove user and application as they wasn't used anywhere else. `ifcopenshell.util.element.remove_deep2(file, history)` we use in every api for element deletion can possibly remove user and application which can be unsafe if `get_user` is returning some specific entity that then will become invalid. Also fixed tests breaking due ifcownerhistory and user/application appearing in ifc2x3.
1 parent 3320acc commit 76e6c63

2 files changed

Lines changed: 64 additions & 49 deletions

File tree

src/ifcopenshell-python/test/api/root/test_remove_product.py

Lines changed: 51 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ def test_removing_all_representations_of_an_element(self):
7777
ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcProject")
7878
ifcopenshell.api.run("unit.assign_unit", self.file)
7979
context = ifcopenshell.api.run("context.add_context", self.file, context_type="Model")
80+
total_entities = len(list(self.file))
8081
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
8182
element.Representation = self.file.createIfcProductDefinitionShape(
8283
Representations=[
@@ -85,9 +86,8 @@ def test_removing_all_representations_of_an_element(self):
8586
)
8687
]
8788
)
88-
total_entities = len(list(self.file))
8989
ifcopenshell.api.run("root.remove_product", self.file, product=element)
90-
assert len(list(self.file)) == total_entities - 4
90+
assert len(list(self.file)) == total_entities
9191
assert len(self.file.by_type("IfcProductDefinitionShape")) == 0
9292
assert len(self.file.by_type("IfcShapeRepresentation")) == 0
9393
assert len(self.file.by_type("IfcExtrudedAreaSolid")) == 0
@@ -97,16 +97,24 @@ def test_unassigning_but_not_removing_mapped_representations_of_an_element(self)
9797
ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcProject")
9898
ifcopenshell.api.run("unit.assign_unit", self.file)
9999
context = ifcopenshell.api.run("context.add_context", self.file, context_type="Model")
100-
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
101100
element_type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType")
102-
ifcopenshell.api.run("type.assign_type", self.file, related_objects=[element], relating_type=element_type)
103101
rep_map = self.file.createIfcRepresentationMap(
104102
MappingOrigin=self.file.createIfcAxis2Placement3D(),
105103
MappedRepresentation=self.file.createIfcShapeRepresentation(
106104
ContextOfItems=context, Items=[self.file.createIfcExtrudedAreaSolid()]
107105
),
108106
)
109107
element_type.RepresentationMaps = [rep_map]
108+
total_entities = len(list(self.file))
109+
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
110+
# should_map_representations=False to create mapping manually
111+
ifcopenshell.api.run(
112+
"type.assign_type",
113+
self.file,
114+
related_objects=[element],
115+
relating_type=element_type,
116+
should_map_representations=False,
117+
)
110118
element.Representation = self.file.createIfcProductDefinitionShape(
111119
Representations=[
112120
self.file.createIfcShapeRepresentation(
@@ -120,10 +128,9 @@ def test_unassigning_but_not_removing_mapped_representations_of_an_element(self)
120128
)
121129
]
122130
)
123-
total_entities = len(list(self.file))
124131
assert len(self.file.by_type("IfcShapeRepresentation")) == 2
125132
ifcopenshell.api.run("root.remove_product", self.file, product=element)
126-
assert len(list(self.file)) == total_entities - 6
133+
assert len(list(self.file)) == total_entities
127134
assert len(self.file.by_type("IfcProductDefinitionShape")) == 0
128135
assert len(self.file.by_type("IfcShapeRepresentation")) == 1
129136
assert len(self.file.by_type("IfcMappedItem")) == 0
@@ -139,9 +146,8 @@ def test_removing_all_openings_of_an_element(self):
139146
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
140147
opening = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcOpeningElement")
141148
ifcopenshell.api.run("void.add_opening", self.file, opening=opening, element=element)
142-
total_entities = len(list(self.file))
143149
ifcopenshell.api.run("root.remove_product", self.file, product=element)
144-
assert len(list(self.file)) == total_entities - 3
150+
assert len(list(self.file)) == 0
145151
assert len(self.file.by_type("IfcWall")) == 0
146152
assert len(self.file.by_type("IfcOpeningElement")) == 0
147153
assert len(self.file.by_type("IfcRelVoidsElement")) == 0
@@ -158,151 +164,153 @@ def test_removing_axes_of_a_grid(self):
158164

159165
def test_removing_all_void_relationships_of_an_opening(self):
160166
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
167+
total_entities = len(list(self.file))
161168
opening = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcOpeningElement")
162169
ifcopenshell.api.run("void.add_opening", self.file, opening=opening, element=element)
163-
total_entities = len(list(self.file))
164170
ifcopenshell.api.run("root.remove_product", self.file, product=opening)
165-
assert len(list(self.file)) == total_entities - 2
171+
assert len(list(self.file)) == total_entities
166172
assert len(self.file.by_type("IfcOpeningElement")) == 0
167173
assert len(self.file.by_type("IfcRelVoidsElement")) == 0
168174

169175
def test_removing_all_fill_relationships_of_a_filling(self):
170176
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
171177
opening = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcOpeningElement")
172178
filling = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcDoor")
179+
total_entities = len(list(self.file))
173180
ifcopenshell.api.run("void.add_opening", self.file, opening=opening, element=element)
174181
ifcopenshell.api.run("void.add_filling", self.file, opening=opening, element=filling)
175-
total_entities = len(list(self.file))
176182
ifcopenshell.api.run("root.remove_product", self.file, product=filling)
177-
assert len(list(self.file)) == total_entities - 2
183+
assert len(list(self.file)) == total_entities
178184
assert len(self.file.by_type("IfcDoor")) == 0
179185
assert len(self.file.by_type("IfcRelFillsElement")) == 0
180186

181187
def test_removing_all_distribution_ports(self):
182-
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcChiller")
183-
port = ifcopenshell.api.run("system.add_port", self.file, element=element)
184188
total_entities = len(list(self.file))
189+
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcFlowSegment")
190+
port = ifcopenshell.api.run("system.add_port", self.file, element=element)
185191
ifcopenshell.api.run("root.remove_product", self.file, product=element)
186-
assert len(list(self.file)) == total_entities - 3
187-
assert len(self.file.by_type("IfcChiller")) == 0
192+
assert len(list(self.file)) == total_entities
193+
assert len(self.file.by_type("IfcFlowSegment")) == 0
188194
assert len(self.file.by_type("IfcRelNests")) == 0
189195
assert len(self.file.by_type("IfcDistributionPort")) == 0
190196

191197
def test_removing_all_nesting_relationships_of_a_whole(self):
192-
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
193198
subelement = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBeam")
194-
ifcopenshell.api.run("nest.assign_object", self.file, related_objects=[subelement], relating_object=element)
195199
total_entities = len(list(self.file))
200+
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
201+
ifcopenshell.api.run("nest.assign_object", self.file, related_objects=[subelement], relating_object=element)
196202
ifcopenshell.api.run("root.remove_product", self.file, product=element)
197-
assert len(list(self.file)) == total_entities - 2
203+
assert len(list(self.file)) == total_entities
198204
assert len(self.file.by_type("IfcRelNests")) == 0
199205
assert len(self.file.by_type("IfcWall")) == 0
200206
assert len(self.file.by_type("IfcBeam")) == 1
201207

202208
def test_removing_all_nesting_relationships_of_a_part(self):
203209
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
210+
total_entities = len(list(self.file))
204211
subelement = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBeam")
205212
ifcopenshell.api.run("nest.assign_object", self.file, related_objects=[subelement], relating_object=element)
206-
total_entities = len(list(self.file))
207213
ifcopenshell.api.run("root.remove_product", self.file, product=subelement)
208-
assert len(list(self.file)) == total_entities - 2
214+
assert len(list(self.file)) == total_entities
209215
assert len(self.file.by_type("IfcRelNests")) == 0
210216
assert len(self.file.by_type("IfcWall")) == 1
211217
assert len(self.file.by_type("IfcBeam")) == 0
212218

213219
def test_removing_all_aggregate_relationships_of_a_whole(self):
214-
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcElementAssembly")
215220
subelement = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBeam")
216-
ifcopenshell.api.run("aggregate.assign_object", self.file, products=[subelement], relating_object=element)
217221
total_entities = len(list(self.file))
222+
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcElementAssembly")
223+
ifcopenshell.api.run("aggregate.assign_object", self.file, products=[subelement], relating_object=element)
218224
ifcopenshell.api.run("root.remove_product", self.file, product=element)
219-
assert len(list(self.file)) == total_entities - 2
225+
assert len(list(self.file)) == total_entities
220226
assert len(self.file.by_type("IfcRelAggregates")) == 0
221227
assert len(self.file.by_type("IfcElementAssembly")) == 0
222228
assert len(self.file.by_type("IfcBeam")) == 1
223229

224230
def test_removing_all_aggregate_relationships_of_a_part(self):
225231
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcElementAssembly")
232+
total_entities = len(list(self.file))
226233
subelement = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBeam")
227234
ifcopenshell.api.run("aggregate.assign_object", self.file, products=[subelement], relating_object=element)
228-
total_entities = len(list(self.file))
229235
ifcopenshell.api.run("root.remove_product", self.file, product=subelement)
230-
assert len(list(self.file)) == total_entities - 2
236+
assert len(list(self.file)) == total_entities
231237
assert len(self.file.by_type("IfcRelAggregates")) == 0
232238
assert len(self.file.by_type("IfcElementAssembly")) == 1
233239
assert len(self.file.by_type("IfcBeam")) == 0
234240

235241
def test_removing_all_containment_relationships_of_a_container(self):
236242
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcSpace")
243+
total_entities = len(list(self.file))
237244
subelement = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
238245
ifcopenshell.api.run("spatial.assign_container", self.file, products=[subelement], relating_structure=element)
239-
total_entities = len(list(self.file))
240246
ifcopenshell.api.run("root.remove_product", self.file, product=element)
241-
assert len(list(self.file)) == total_entities - 2
247+
assert len(list(self.file)) == total_entities
242248
assert len(self.file.by_type("IfcRelContainedInSpatialStructure")) == 0
243249
assert len(self.file.by_type("IfcSpace")) == 0
244250
assert len(self.file.by_type("IfcWall")) == 1
245251

246252
def test_removing_all_containment_relationships_of_an_element(self):
247253
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcSpace")
254+
total_entities = len(list(self.file))
248255
subelement = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
249256
ifcopenshell.api.run("spatial.assign_container", self.file, products=[subelement], relating_structure=element)
250-
total_entities = len(list(self.file))
251257
ifcopenshell.api.run("root.remove_product", self.file, product=subelement)
252-
assert len(list(self.file)) == total_entities - 2
258+
assert len(list(self.file)) == total_entities
253259
assert len(self.file.by_type("IfcRelContainedInSpatialStructure")) == 0
254260
assert len(self.file.by_type("IfcSpace")) == 1
255261
assert len(self.file.by_type("IfcWall")) == 0
256262

257263
def test_removing_path_connection_relationships_of_an_element(self):
258-
element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBeam")
259264
element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcColumn")
260-
ifcopenshell.api.run("geometry.connect_path", self.file, relating_element=element1, related_element=element2)
261265
total_entities = len(list(self.file))
266+
element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcBeam")
267+
ifcopenshell.api.run("geometry.connect_path", self.file, relating_element=element1, related_element=element2)
262268
ifcopenshell.api.run("root.remove_product", self.file, product=element1)
263-
assert len(list(self.file)) == total_entities - 2
269+
assert len(list(self.file)) == total_entities
264270
assert len(self.file.by_type("IfcRelConnectsPathElements")) == 0
265271
assert len(self.file.by_type("IfcColumn")) == 1
266272
assert len(self.file.by_type("IfcBeam")) == 0
267273

268274
def test_removing_connection_relationships_of_an_element(self):
269-
element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
270275
element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcSlab")
276+
total_entities = len(list(self.file))
277+
element1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
271278
ifcopenshell.api.run(
272279
"geometry.connect_element",
273280
self.file,
274281
related_element=element1,
275282
relating_element=element2,
276283
)
277-
total_entities = len(list(self.file))
278284
ifcopenshell.api.run("root.remove_product", self.file, product=element1)
279-
assert len(list(self.file)) == total_entities - 2
285+
assert len(list(self.file)) == total_entities
280286
assert len(self.file.by_type("IfcRelConnectsElements")) == 0
281287
assert len(self.file.by_type("IfcSlab")) == 1
282288
assert len(self.file.by_type("IfcWall")) == 0
283289

284290
def test_removing_connection_relationships_of_an_element_with_additional_realizing_element(self):
285-
wall = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
286291
slab1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcSlab")
287292
slab2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcSlab")
293+
total_entities = len(list(self.file))
294+
wall = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
288295
self.file.createIfcRelConnectsWithRealizingElements(
289296
ifcopenshell.guid.new(),
290297
OwnerHistory=ifcopenshell.api.run("owner.create_owner_history", self.file),
291298
RelatingElement=wall,
292299
RelatedElement=slab1,
293300
RealizingElements=(wall, slab1, slab2),
294301
)
295-
total_entities = len(list(self.file))
296302
ifcopenshell.api.run("root.remove_product", self.file, product=wall)
297-
assert len(list(self.file)) == total_entities - 2
303+
assert len(list(self.file)) == total_entities
298304
assert len(self.file.by_type("IfcRelConnectsElements")) == 0
299305
assert len(self.file.by_type("IfcSlab")) == 2
300306
assert len(self.file.by_type("IfcWall")) == 0
301307

302308
def test_removing_connection_relationships_of_an_element_element_is_realizing_element(self):
303309
wall = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
304310
slab1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcSlab")
311+
total_entities = len(list(self.file))
305312
slab2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcSlab")
313+
slab2_entities = len(list(self.file)) - total_entities
306314
self.file.createIfcRelConnectsWithRealizingElements(
307315
ifcopenshell.guid.new(),
308316
OwnerHistory=ifcopenshell.api.run("owner.create_owner_history", self.file),
@@ -312,14 +320,15 @@ def test_removing_connection_relationships_of_an_element_element_is_realizing_el
312320
)
313321
total_entities = len(list(self.file))
314322
ifcopenshell.api.run("root.remove_product", self.file, product=slab2)
315-
assert len(list(self.file)) == total_entities - 1
323+
assert len(list(self.file)) == (total_entities - slab2_entities)
316324
assert len(self.file.by_type("IfcRelConnectsElements")) == 1
317325
assert len(self.file.by_type("IfcSlab")) == 1
318326
assert len(self.file.by_type("IfcWall")) == 1
319327

320328
def test_removing_connection_relationships_of_an_element_element_is_only_realizing_element(self):
321329
wall = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
322330
slab1 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcSlab")
331+
total_entities = len(list(self.file))
323332
slab2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcSlab")
324333
self.file.createIfcRelConnectsWithRealizingElements(
325334
ifcopenshell.guid.new(),
@@ -328,9 +337,8 @@ def test_removing_connection_relationships_of_an_element_element_is_only_realizi
328337
RelatedElement=slab1,
329338
RealizingElements=(slab2,),
330339
)
331-
total_entities = len(list(self.file))
332340
ifcopenshell.api.run("root.remove_product", self.file, product=slab2)
333-
assert len(list(self.file)) == total_entities - 2
341+
assert len(list(self.file)) == total_entities
334342
assert len(self.file.by_type("IfcRelConnectsElements")) == 0
335343
assert len(self.file.by_type("IfcSlab")) == 1
336344
assert len(self.file.by_type("IfcWall")) == 1
@@ -395,9 +403,7 @@ def test_removing_all_type_relationships_of_an_element_type(self):
395403

396404
def test_removing_all_space_boundaries_of_an_element(self):
397405
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
398-
boundary = self.file.createIfcRelSpaceBoundary(
399-
GlobalId=ifcopenshell.guid.new(), RelatedBuildingElement=element
400-
)
406+
boundary = self.file.createIfcRelSpaceBoundary(GlobalId=ifcopenshell.guid.new(), RelatedBuildingElement=element)
401407
ifcopenshell.api.run("root.remove_product", self.file, product=element)
402408
assert not self.file.by_type("IfcRelSpaceBoundary")
403409

src/ifcopenshell-python/test/bootstrap.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import ifcopenshell
2121
import ifcopenshell.api
2222
import ifcopenshell.api.owner.settings
23-
import functools
2423

2524

2625
class IFC4X3:
@@ -48,13 +47,23 @@ class IFC2X3:
4847
def setup(self):
4948
self.file: ifcopenshell.file = ifcopenshell.api.run("project.create_file", version="IFC2X3")
5049

51-
@functools.cache
52-
def get_user(ifc: ifcopenshell.file):
50+
def get_user(ifc: ifcopenshell.file) -> ifcopenshell.entity_instance:
51+
user = next(iter(ifc.by_type("IfcPersonAndOrganization")), None)
52+
if user:
53+
return user
5354
person = ifc.create_entity("IfcPerson")
5455
organization = ifc.create_entity("IfcOrganization")
5556
return ifc.create_entity("IfcPersonAndOrganization", ThePerson=person, TheOrganization=organization)
5657

5758
ifcopenshell.api.owner.settings.get_user = get_user
58-
ifcopenshell.api.owner.settings.get_application = functools.cache(lambda ifc: ifc.createIfcApplication())
59+
60+
def get_application(ifc: ifcopenshell.file) -> ifcopenshell.entity_instance:
61+
application = next(iter(ifc.by_type("IfcApplication")), None)
62+
if application:
63+
return application
64+
return ifc.create_entity("IfcApplication")
65+
66+
ifcopenshell.api.owner.settings.get_application = get_application
67+
5968
ifcopenshell.api.pre_listeners = {}
6069
ifcopenshell.api.post_listeners = {}

0 commit comments

Comments
 (0)