From 7baed872c6ec2076f46bb1f1b05e310502e19b39 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sat, 26 Aug 2023 18:24:48 +1000 Subject: [PATCH] Minor fixes, and IfcCSV now uses pandas to import ODS/XLSX for more robust importing. --- src/ifccsv/ifccsv.py | 38 +++---------------- .../ifcopenshell/util/selector.py | 3 +- .../test/util/test_selector.py | 22 ++++++++++- 3 files changed, 27 insertions(+), 36 deletions(-) diff --git a/src/ifccsv/ifccsv.py b/src/ifccsv/ifccsv.py index ae5c03ef47..d8e31a2183 100755 --- a/src/ifccsv/ifccsv.py +++ b/src/ifccsv/ifccsv.py @@ -91,10 +91,6 @@ class IfcCsv: for element in elements: result = [] - for index, attribute in enumerate(attributes): - if "*" in attribute: - attributes.extend(self.get_wildcard_attributes(attribute)) - del attributes[index] for attribute in attributes: value = ifcopenshell.util.selector.get_element_value(element, attribute) @@ -262,7 +258,7 @@ class IfcCsv: reverse = sort_data["order"] == "DESC" self.results = sorted(self.results, key=lambda x: natural_sort(x[i]), reverse=reverse) else: - if include_global_id and len(self.results[0]) > 1: + if include_global_id and len(list(self.results[0])) > 1: self.results = sorted(self.results, key=lambda x: x[1]) elif not include_global_id: self.results = sorted(self.results, key=lambda x: x[0]) @@ -397,36 +393,12 @@ class IfcCsv: self.process_row(ifc_file, row, headers, attributes, null, bool_true, bool_false) def import_xlsx(self, ifc_file, table, attributes, null, bool_true, bool_false): - workbook = openpyxl.load_workbook(filename=table, read_only=True) - worksheet = workbook.active # Assuming data is on the first sheet - headers = None - - for row in worksheet.iter_rows(values_only=True): - if not headers: - headers = list(row) - if not attributes: - attributes = [None] * len(headers) - elif len(attributes) == len(headers) - 1: - attributes.insert(0, "") # The GlobalId column - continue - self.process_row(ifc_file, row, headers, attributes, null, bool_true, bool_false) + df = pd.read_excel(table) + self.import_pd(ifc_file, df, attributes, null, bool_true, bool_false) def import_ods(self, ifc_file, table, attributes, null, bool_true, bool_false): - doc = load(table) - first_sheet = doc.spreadsheet.getElementsByType(Table)[0] - rows = first_sheet.getElementsByType(TableRow) - headers = None - - for row in rows: - values = [cell.getElementsByType(P)[0].childNodes[0].data for cell in row.getElementsByType(TableCell)] - if not headers: - headers = values - if not attributes: - attributes = [None] * len(headers) - elif len(attributes) == len(headers) - 1: - attributes.insert(0, "") # The GlobalId column - continue - self.process_row(ifc_file, values, headers, attributes, null, bool_true, bool_false) + df = pd.read_excel(table, engine="odf") + self.import_pd(ifc_file, df, attributes, null, bool_true, bool_false) def import_pd(self, ifc_file, df, attributes=None, null="-", bool_true="YES", bool_false="NO"): headers = df.columns.tolist() diff --git a/src/ifcopenshell-python/ifcopenshell/util/selector.py b/src/ifcopenshell-python/ifcopenshell/util/selector.py index 095a9df50e..b1bf056ff7 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/selector.py +++ b/src/ifcopenshell-python/ifcopenshell/util/selector.py @@ -808,7 +808,8 @@ class Selector: value = len(list(value)) elif isinstance(value, (list, tuple)): value = len(value) - value = 1 + else: + value = 1 elif key == "class": value = value.is_a() elif key == "id": diff --git a/src/ifcopenshell-python/test/util/test_selector.py b/src/ifcopenshell-python/test/util/test_selector.py index 650e6e2c99..a63a8fdfb2 100644 --- a/src/ifcopenshell-python/test/util/test_selector.py +++ b/src/ifcopenshell-python/test/util/test_selector.py @@ -78,7 +78,7 @@ class TestGetElementValue(test.bootstrap.IFC4): assert subject.get_element_value(element, "material.item.Name.0") == "L1" assert subject.get_element_value(element, "material.item.Name.1") == "L2" assert subject.get_element_value(element, '"material"."item"."Name"') == ["L1", "L2"] - assert subject.get_element_value(element, 'r"material"."item"."Name"') == ["L1", "L2"] + assert subject.get_element_value(element, 'material."item"."Name"') == ["L1", "L2"] # Provide shortform for convenience assert subject.get_element_value(element, "mat.i.Name") == ["L1", "L2"] @@ -86,7 +86,7 @@ class TestGetElementValue(test.bootstrap.IFC4): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") assert subject.get_element_value(element, "material.item.Name.0") is None - def test_selceting_a_list_item_that_fails_silently(self): + def test_selecting_a_list_item_that_fails_silently(self): element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") material = ifcopenshell.api.run("material.add_material", self.file, name="CON01") material2 = ifcopenshell.api.run("material.add_material", self.file, name="CON02") @@ -99,6 +99,24 @@ class TestGetElementValue(test.bootstrap.IFC4): assert subject.get_element_value(element, "material.item.Name.0") == "L1" assert subject.get_element_value(element, "material.item.Name.1") is None + def test_selecting_a_pset(self): + element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + element2 = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall") + pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="Foobar") + ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Foo": "Bar"}) + assert subject.get_element_value(element, "Foobar.Foo") == "Bar" + assert subject.get_element_value(element, "Foobar./F.*/") == "Bar" + assert subject.get_element_value(element, "/Foo.*/./F.*/") == "Bar" + ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Baz": 123}) + assert subject.get_element_value(element, "/Foo.*/./B.*/") == 123 + assert subject.get_element_value(element, "/Foo.*/./.*/") == ["Bar", 123] + ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Bay": 123.3}) + assert subject.get_element_value(element, "/Foo.*/./B.*/") == [123, 123.3] + pset = ifcopenshell.api.run("pset.add_pset", self.file, product=element, name="Pset_WallCommon") + ifcopenshell.api.run("pset.edit_pset", self.file, pset=pset, properties={"Status": ["New"]}) + assert subject.get_element_value(element, "/Pset_.*Common/.Status") == ["New"] + assert subject.get_element_value(element, "/Pset_.*Common/.Status.0") == "New" + class TestFilterElements(test.bootstrap.IFC4): def test_selecting_by_globalid(self):