mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-06 07:51:47 +00:00
Resolve nested complex quantity paths in the selector (#2041)
get_element_value could not reach the members of an IfcPhysicalComplexQuantity (or IfcComplexProperty) by their natural path. util.element expands a complex quantity into a dict whose nested members live under a "properties" sub-dict, but the selector's dict navigation only looked at the top level, so "Qto_Custom.Layer1.Width" returned None and IfcCsv exported nothing for it. Only the internal "Qto_Custom.Layer1.properties.Width" path worked. When a key is not a direct member of the value dict, descend into its "properties" sub-dict so nested quantities/properties resolve with the natural "Set.Complex.Nested" path. Direct keys still take priority, so the explicit ".properties." path stays backward compatible and the regex branch is untouched. Verified: Qto_Custom.Layer1.Width -> 0.1 and Layer1.Height -> 2.5 (were None), the sibling simple NetArea still resolves, the legacy .properties. path still works, and IfcCsv now exports the nested value. test_selector.py: 38 passed (adds test_selecting_a_nested_complex_quantity). Generated with the assistance of an AI coding tool. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
committed by
Massimo Fabbro
parent
d63a99b70c
commit
21122c0d28
@@ -540,8 +540,15 @@ def _get_element_value(element: ifcopenshell.entity_instance, keys: list[str]) -
|
|||||||
value = results or None
|
value = results or None
|
||||||
if value and len(value) == 1:
|
if value and len(value) == 1:
|
||||||
value = value[0]
|
value = value[0]
|
||||||
|
elif key in value:
|
||||||
|
value = value[key]
|
||||||
else:
|
else:
|
||||||
value = value.get(key, None)
|
# A nested complex quantity/property (IfcPhysicalComplexQuantity /
|
||||||
|
# IfcComplexProperty) is represented as a dict whose nested members
|
||||||
|
# live under a "properties" sub-dict. Descend into it so that nested
|
||||||
|
# values are reachable with the natural "Qto.Complex.Nested" path.
|
||||||
|
subprops = value.get("properties")
|
||||||
|
value = subprops.get(key, None) if isinstance(subprops, dict) else None
|
||||||
elif isinstance(value, (list, tuple, set)): # If we use regex
|
elif isinstance(value, (list, tuple, set)): # If we use regex
|
||||||
if isinstance(key, str) and key.isnumeric():
|
if isinstance(key, str) and key.isnumeric():
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -195,6 +195,37 @@ class TestGetElementValue(test.bootstrap.IFC4):
|
|||||||
assert subject.get_element_value(element, "/Pset_.*Common/.Status") == ["New"]
|
assert subject.get_element_value(element, "/Pset_.*Common/.Status") == ["New"]
|
||||||
assert subject.get_element_value(element, "/Pset_.*Common/.Status.0") == "New"
|
assert subject.get_element_value(element, "/Pset_.*Common/.Status.0") == "New"
|
||||||
|
|
||||||
|
def test_selecting_a_nested_complex_quantity(self):
|
||||||
|
element = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWall")
|
||||||
|
complex_quantity = self.file.create_entity(
|
||||||
|
"IfcPhysicalComplexQuantity",
|
||||||
|
Name="Layer1",
|
||||||
|
Discrimination="layer",
|
||||||
|
HasQuantities=[
|
||||||
|
self.file.create_entity("IfcQuantityLength", Name="Width", LengthValue=0.1),
|
||||||
|
self.file.create_entity("IfcQuantityLength", Name="Height", LengthValue=2.5),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
quantity = self.file.create_entity(
|
||||||
|
"IfcElementQuantity",
|
||||||
|
GlobalId=ifcopenshell.guid.new(),
|
||||||
|
Name="Qto_Custom",
|
||||||
|
Quantities=[complex_quantity, self.file.create_entity("IfcQuantityArea", Name="NetArea", AreaValue=5.0)],
|
||||||
|
)
|
||||||
|
self.file.create_entity(
|
||||||
|
"IfcRelDefinesByProperties",
|
||||||
|
GlobalId=ifcopenshell.guid.new(),
|
||||||
|
RelatedObjects=[element],
|
||||||
|
RelatingPropertyDefinition=quantity,
|
||||||
|
)
|
||||||
|
# A simple quantity in the same set still resolves normally.
|
||||||
|
assert subject.get_element_value(element, "Qto_Custom.NetArea") == 5.0
|
||||||
|
# Nested quantities of a complex quantity are reachable with the natural path.
|
||||||
|
assert subject.get_element_value(element, "Qto_Custom.Layer1.Width") == 0.1
|
||||||
|
assert subject.get_element_value(element, "Qto_Custom.Layer1.Height") == 2.5
|
||||||
|
# The explicit "properties" path is preserved for backwards compatibility.
|
||||||
|
assert subject.get_element_value(element, "Qto_Custom.Layer1.properties.Width") == 0.1
|
||||||
|
|
||||||
|
|
||||||
class TestFilterElements(test.bootstrap.IFC4):
|
class TestFilterElements(test.bootstrap.IFC4):
|
||||||
def test_selecting_by_globalid(self):
|
def test_selecting_by_globalid(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user