From d66ec21e8cdf4add86b84e85bb6d7f052d7fe453 Mon Sep 17 00:00:00 2001 From: Ian Stride Date: Sun, 23 Feb 2025 17:15:28 +0000 Subject: [PATCH 1/4] Support 'number-columns-repeated' attribute of ODS cells --- src/tablib/formats/_ods.py | 23 +++++++++++++++++------ tests/files/columns_repeated.ods | Bin 0 -> 11289 bytes tests/test_tablib.py | 11 ++++++++++- 3 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 tests/files/columns_repeated.ods diff --git a/src/tablib/formats/_ods.py b/src/tablib/formats/_ods.py index 97cef201..054e79ed 100644 --- a/src/tablib/formats/_ods.py +++ b/src/tablib/formats/_ods.py @@ -110,22 +110,33 @@ def import_sheet(cls, dset, sheet, headers=True, skip_lines=0): dset.title = sheet.getAttribute('name') - def is_real_cell(cell): - return cell.hasChildNodes() or not cell.getAttribute('numbercolumnsrepeated') + def repeat(cell): + try: + n = int(cell.getAttribute("numbercolumnsrepeated")) + except Exception: + n = 1 + + return [cls.read_cell(cell)] * n rows = (row for row in sheet.childNodes if row.tagName == "table:table-row") for i, row in enumerate(rows): if i < skip_lines: continue - row_vals = [cls.read_cell(cell) for cell in row.childNodes if is_real_cell(cell)] + row_vals = [c for cell in row.childNodes for c in repeat(cell)] if not row_vals: continue if i == skip_lines and headers: - dset.headers = row_vals + try: + end = row_vals.index("") + except ValueError: + end = len(row_vals) + dset.headers = row_vals[:end] else: - if i > skip_lines and len(row_vals) < dset.width: - row_vals += [''] * (dset.width - len(row_vals)) + if i > skip_lines: + if len(row_vals) < dset.width: + row_vals += [''] * (dset.width - len(row_vals)) + row_vals = row_vals[:dset.width] dset.append(row_vals) @classmethod diff --git a/tests/files/columns_repeated.ods b/tests/files/columns_repeated.ods new file mode 100644 index 0000000000000000000000000000000000000000..3829da97b0df989574909e51b7291c938aa9fb10 GIT binary patch literal 11289 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 EFK}G<`Tzg` literal 0 HcmV?d00001 diff --git a/tests/test_tablib.py b/tests/test_tablib.py index 7a89eb7b..dc46ae59 100755 --- a/tests/test_tablib.py +++ b/tests/test_tablib.py @@ -1260,7 +1260,16 @@ def test_ods_import_set_ragged(self): ods_source = Path(__file__).parent / 'files' / 'ragged.ods' with ods_source.open('rb') as fh: dataset = tablib.Dataset().load(fh, 'ods') - self.assertEqual(dataset.pop(), (1, '', True, '')) + self.assertEqual(dataset[0], (1, '', True, '')) + + def test_ods_import_columns_repeated(self): + ods = Path(__file__).parent / "files" / "columns_repeated.ods" + + with ods.open("rb") as fh: + dataset = tablib.Dataset().load(fh, "ods") + + self.assertEqual(dataset[0], ("a1", "", "", "d1")) + self.assertEqual(dataset[1], ("repeat",) * 4) def test_ods_unknown_value_type(self): # The ods file was trafficked to contain: From bff484e27dd7c56b84e16ec8d81ec7db24bb1802 Mon Sep 17 00:00:00 2001 From: Ian Stride Date: Sun, 16 Mar 2025 14:21:51 +0000 Subject: [PATCH 2/4] Catch specific errors when getting 'number-columns-repeated attribute --- src/tablib/formats/_ods.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tablib/formats/_ods.py b/src/tablib/formats/_ods.py index 054e79ed..c8120048 100644 --- a/src/tablib/formats/_ods.py +++ b/src/tablib/formats/_ods.py @@ -113,7 +113,7 @@ def import_sheet(cls, dset, sheet, headers=True, skip_lines=0): def repeat(cell): try: n = int(cell.getAttribute("numbercolumnsrepeated")) - except Exception: + except (AttributeError, TypeError, ValueError): n = 1 return [cls.read_cell(cell)] * n From 5dc164d84ca8def8c52486fc6b4d3fe33f9b6207 Mon Sep 17 00:00:00 2001 From: Ian Stride Date: Tue, 25 Mar 2025 17:51:51 +0000 Subject: [PATCH 3/4] Accept the header row as it is when reading ODS format --- src/tablib/formats/_ods.py | 6 +----- tests/test_tablib.py | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/tablib/formats/_ods.py b/src/tablib/formats/_ods.py index c8120048..4d810da1 100644 --- a/src/tablib/formats/_ods.py +++ b/src/tablib/formats/_ods.py @@ -127,11 +127,7 @@ def repeat(cell): if not row_vals: continue if i == skip_lines and headers: - try: - end = row_vals.index("") - except ValueError: - end = len(row_vals) - dset.headers = row_vals[:end] + dset.headers = row_vals else: if i > skip_lines: if len(row_vals) < dset.width: diff --git a/tests/test_tablib.py b/tests/test_tablib.py index dc46ae59..491ad231 100755 --- a/tests/test_tablib.py +++ b/tests/test_tablib.py @@ -1260,7 +1260,7 @@ def test_ods_import_set_ragged(self): ods_source = Path(__file__).parent / 'files' / 'ragged.ods' with ods_source.open('rb') as fh: dataset = tablib.Dataset().load(fh, 'ods') - self.assertEqual(dataset[0], (1, '', True, '')) + self.assertEqual(dataset[0], (1, '', True) + ('',) * 16381) def test_ods_import_columns_repeated(self): ods = Path(__file__).parent / "files" / "columns_repeated.ods" From 5d74fb4bc79fdb2c8267494231d45b041598e657 Mon Sep 17 00:00:00 2001 From: Ian Stride Date: Tue, 15 Jul 2025 17:55:29 +0100 Subject: [PATCH 4/4] Limit the number of empty header row values Default is 5. --- src/tablib/formats/_ods.py | 17 ++++++++++++++++- tests/test_tablib.py | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/tablib/formats/_ods.py b/src/tablib/formats/_ods.py index 4d810da1..f83b9e0b 100644 --- a/src/tablib/formats/_ods.py +++ b/src/tablib/formats/_ods.py @@ -127,7 +127,7 @@ def repeat(cell): if not row_vals: continue if i == skip_lines and headers: - dset.headers = row_vals + dset.headers = limit_row(row_vals) else: if i > skip_lines: if len(row_vals) < dset.width: @@ -255,3 +255,18 @@ def detect(cls, stream): return True except Exception: return False + + +def limit_row(headers, limit=5): + """Limits the number of trailing empty row values""" + limited = [] + count = 0 + + for v in headers: + limited += [v] + count = count + 1 if v == "" else 0 + + if count == limit: + break + + return limited diff --git a/tests/test_tablib.py b/tests/test_tablib.py index 491ad231..adc54ed4 100755 --- a/tests/test_tablib.py +++ b/tests/test_tablib.py @@ -1260,7 +1260,7 @@ def test_ods_import_set_ragged(self): ods_source = Path(__file__).parent / 'files' / 'ragged.ods' with ods_source.open('rb') as fh: dataset = tablib.Dataset().load(fh, 'ods') - self.assertEqual(dataset[0], (1, '', True) + ('',) * 16381) + self.assertEqual(dataset[0], (1, '', True) + ('',) * 6) def test_ods_import_columns_repeated(self): ods = Path(__file__).parent / "files" / "columns_repeated.ods"