From efb89acfa3a4c75e3feebaab85ac5b0d3814de22 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Tue, 22 Mar 2022 10:40:05 +1100 Subject: [PATCH] You can now use a "not" operator when selecting elements --- .../ifcopenshell/util/selector.py | 17 +++++++++++------ .../test/util/test_selector.py | 17 +++++++++++++++++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/ifcopenshell-python/ifcopenshell/util/selector.py b/src/ifcopenshell-python/ifcopenshell/util/selector.py index f69356a750..cb524270f3 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/selector.py +++ b/src/ifcopenshell-python/ifcopenshell/util/selector.py @@ -45,7 +45,8 @@ class Selector: boundedby: "@@" and: "&" or: "|" - comparison: contains | morethanequalto | lessthanequalto | equal | morethan | lessthan + not: "!" + comparison: (not)* (contains | morethanequalto | lessthanequalto | equal | morethan | lessthan) contains: "*=" morethanequalto: ">=" lessthanequalto: "<=" @@ -170,6 +171,8 @@ class Selector: comparison = value = None if len(filter_rule.children) > 1: comparison = filter_rule.children[1].children[0].data + if comparison == "not": + comparison += filter_rule.children[1].children[1].data token_type = filter_rule.children[2].children[0].type if token_type == "ESCAPED_STRING": value = str(filter_rule.children[2].children[0][1:-1]) @@ -228,18 +231,20 @@ class Selector: @classmethod def filter_element(cls, element, element_value, comparison, value): - if comparison == "equal": + if comparison.startswith("not"): + return not cls.filter_element(element, element_value, comparison[3:], value) + elif comparison == "equal": return element_value == value elif comparison == "contains": return value in str(element_value) elif comparison == "morethan": - return element_value > float(value) + return element_value > value elif comparison == "lessthan": - return element_value < float(value) + return element_value < value elif comparison == "morethanequalto": - return element_value >= float(value) + return element_value >= value elif comparison == "lessthanequalto": - return element_value <= float(value) + return element_value <= value return False @classmethod diff --git a/src/ifcopenshell-python/test/util/test_selector.py b/src/ifcopenshell-python/test/util/test_selector.py index 54a678349b..8f655a686f 100644 --- a/src/ifcopenshell-python/test/util/test_selector.py +++ b/src/ifcopenshell-python/test/util/test_selector.py @@ -73,3 +73,20 @@ class TestSelector(test.bootstrap.IFC4): assert subject.Selector.parse(self.file, '.IfcElement[Foo_Bar.Foo=NULL]') == [] ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Foo": None}) assert subject.Selector.parse(self.file, '.IfcElement[Foo_Bar.Foo=NULL]') == [element] + + def test_comparing_by_not_equal(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + element.Name = "Foobar" + assert subject.Selector.parse(self.file, '.IfcElement[Name!="Foobaz"]') == [element] + assert subject.Selector.parse(self.file, '.IfcElement[Name!="Foobar"]') == [] + + def test_comparing_by_ranges(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="Foo_Bar") + ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Foo": 4.2}) + assert subject.Selector.parse(self.file, '.IfcElement[Foo_Bar.Foo>2]') == [element] + assert subject.Selector.parse(self.file, '.IfcElement[Foo_Bar.Foo>20]') == [] + assert subject.Selector.parse(self.file, '.IfcElement[Foo_Bar.Foo<2]') == [] + assert subject.Selector.parse(self.file, '.IfcElement[Foo_Bar.Foo<20]') == [element] + assert subject.Selector.parse(self.file, '.IfcElement[Foo_Bar.Foo>=4.2]') == [element] + assert subject.Selector.parse(self.file, '.IfcElement[Foo_Bar.Foo<=4.2]') == [element]