mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-19 22:50:21 +00:00
Selector: negate list comparisons as an aggregate #8129
compare() recursed into list values passing the negated comparison through, so != meant "at least one item differs" and both = and != matched the same elements on any multi-valued property (e.g. an enumerated property with two values selected). Strip the negation for the per-item comparison and negate the aggregate instead, so != means "no item equals" and stays the complement of =. The same applies to !*=. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
committed by
Dion Moult
parent
382f5e0c21
commit
209c44db83
@@ -1242,7 +1242,13 @@ class FacetTransformer(lark.Transformer):
|
|||||||
|
|
||||||
def compare(self, element_value, comparison, value) -> bool:
|
def compare(self, element_value, comparison, value) -> bool:
|
||||||
if isinstance(element_value, (list, tuple)):
|
if isinstance(element_value, (list, tuple)):
|
||||||
return any(self.compare(ev, comparison, value) for ev in element_value)
|
# Match if any item does, negating the aggregate rather than each
|
||||||
|
# item, so that e.g. != means "no item equals" and stays the
|
||||||
|
# complement of = (#8129).
|
||||||
|
result = any(self.compare(ev, comparison.lstrip("!"), value) for ev in element_value)
|
||||||
|
if comparison.startswith("!"):
|
||||||
|
return not result
|
||||||
|
return result
|
||||||
elif isinstance(value, str):
|
elif isinstance(value, str):
|
||||||
try:
|
try:
|
||||||
if isinstance(element_value, int):
|
if isinstance(element_value, int):
|
||||||
|
|||||||
@@ -279,6 +279,12 @@ class TestFilterElements(test.bootstrap.IFC4):
|
|||||||
pset = ifcopenshell.api.pset.add_pset(self.file, product=element, name="Pset_WallCommon")
|
pset = ifcopenshell.api.pset.add_pset(self.file, product=element, name="Pset_WallCommon")
|
||||||
ifcopenshell.api.pset.edit_pset(self.file, pset=pset, properties={"Status": ["New"]})
|
ifcopenshell.api.pset.edit_pset(self.file, pset=pset, properties={"Status": ["New"]})
|
||||||
assert subject.filter_elements(self.file, "IfcWall, Pset_WallCommon.Status=New") == {element}
|
assert subject.filter_elements(self.file, "IfcWall, Pset_WallCommon.Status=New") == {element}
|
||||||
|
# On multi-valued properties, != means "no value equals" and stays the
|
||||||
|
# complement of = (#8129).
|
||||||
|
ifcopenshell.api.pset.edit_pset(self.file, pset=pset, properties={"Status": ["New", "Demolish"]})
|
||||||
|
assert subject.filter_elements(self.file, "IfcWall, Pset_WallCommon.Status=New") == {element}
|
||||||
|
assert subject.filter_elements(self.file, "IfcWall, Pset_WallCommon.Status!=New") == {element2}
|
||||||
|
assert subject.filter_elements(self.file, "IfcWall, Pset_WallCommon.Status!=Temporary") == {element, element2}
|
||||||
|
|
||||||
def test_selecting_by_property_with_comparisons(self):
|
def test_selecting_by_property_with_comparisons(self):
|
||||||
element = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWall")
|
element = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWall")
|
||||||
|
|||||||
Reference in New Issue
Block a user