Repository: jazzband/tablib
Pull request #614 (2025-02-22 01:51:28)

Fix bug in ODS import where headers are not set on Dataset
Sheets in ODS files saved by LibreOffice can contain 'table-column' nodes before the 'table-row' nodes. Previously, all child nodes of a sheet where enumerated before iterating over them, leading to incorrect counting of skipped rows and failed identification of the headers row.

This change creates a generator that returns 'table-row' nodes only, before they are enumerated and iterated over.

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/jazzband/tablib/pull/614?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jazzband) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 93.01%. Comparing base [(`dcab406`)](https://app.codecov.io/gh/jazzband/tablib/commit/dcab406c553fc8b3c2e0aef955e9e8adea0590d8?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jazzband) to head [(`0f20450`)](https://app.codecov.io/gh/jazzband/tablib/commit/0f20450feb2bae1ce9d7c6709b1f3ba3bab8cc50?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jazzband).
> Report is 7 commits behind head on master.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master     #614      +/-   ##
==========================================
+ Coverage   92.89%   93.01%   +0.11%     
==========================================
  Files          28       28              
  Lines        3055     3105      +50     
==========================================
+ Hits         2838     2888      +50     
  Misses        217      217              
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/jazzband/tablib/pull/614?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jazzband).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jazzband).


Patch:
diff --git a/AUTHORS b/AUTHORS
index c8fc980..d6e7c3c 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -13,6 +13,7 @@ Here is a list of past and present much-appreciated contributors:
     Egor Osokin
     Erik Youngren
     Hugo van Kemenade
+    Ian Stride
     Iuri de Silvio
     Jakub Janoszek
     James Douglass
diff --git a/src/tablib/formats/_ods.py b/src/tablib/formats/_ods.py
index f30c0f2..97cef20 100644
--- a/src/tablib/formats/_ods.py
+++ b/src/tablib/formats/_ods.py
@@ -113,9 +113,9 @@ class ODSFormat:
         def is_real_cell(cell):
             return cell.hasChildNodes() or not cell.getAttribute('numbercolumnsrepeated')
 
-        for i, row in enumerate(sheet.childNodes):
-            if row.tagName != 'table:table-row':
-                continue
+        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)]


Test patch:
diff --git a/tests/test_tablib.py b/tests/test_tablib.py
index 4b0500d..7d7b304 100755
--- a/tests/test_tablib.py
+++ b/tests/test_tablib.py
@@ -1246,6 +1246,7 @@ class ODSTests(BaseTestCase):
         with ods_source.open('rb') as fh:
             dbook = tablib.Databook().load(fh, 'ods')
         self.assertEqual(len(dbook.sheets()), 2)
+        self.assertEqual(["This", "is", "a", "second", "sheet"], dbook.sheets()[1].headers)
 
     def test_ods_import_set_skip_lines(self):
         data.append(('garbage', 'line', ''))
@@ -1266,7 +1267,7 @@ class ODSTests(BaseTestCase):
         # <table:table-cell office:value-type="unknown" calcext:value-type="string">
         ods_source = Path(__file__).parent / 'files' / 'unknown_value_type.ods'
         with ods_source.open('rb') as fh:
-            dataset = tablib.Dataset().load(fh, 'ods')
+            dataset = tablib.Dataset().load(fh, 'ods', headers=False)
         self.assertEqual(dataset.pop(), ('abcd',))
 
     def test_ods_export_dates(self):