Repository: jazzband/tablib (python)

Issue:
ODS loading issue - ValueError: 'value' is not in list
When saving data containing the empty string to ODS format, the resulting ODS file is not loadable by tablib. The code below reproduces the problem.

```python
book = tablib.Databook()
book.load(
    tablib.Databook(sets=[tablib.Dataset(("",))]).export("ods"),
    format="ods",
)
```

If the empty string is replaced with `None` the problem does not occur.

Would it be possible for tablib to handle this situation in a more robust manner?

Pull request description:
Fix bug in ODS import regarding cells with empty strings
Table cells with an empty 'text:p' tag raise a ValueError because tablib attempts to read an attribute ('value') that cannot exist on 'test:p'. The solution is to try to access the attribute, but carry on if it can't be found.

Resolves #612 

Patch:
diff --git a/src/tablib/formats/_ods.py b/src/tablib/formats/_ods.py
index adab7e1..f30c0f2 100644
--- a/src/tablib/formats/_ods.py
+++ b/src/tablib/formats/_ods.py
@@ -155,7 +155,10 @@ class ODSFormat:
         if not cell.childNodes:
             value = getattr(cell, 'data', None)
             if value is None:
-                value = cell.getAttribute('value')
+                try:
+                    value = cell.getAttribute('value')
+                except ValueError:
+                    pass
             if value is None:
                 return ''
             if value_type == 'float':
@@ -165,9 +168,7 @@ class ODSFormat:
             return value  # Any other type default to 'string'
 
         for subnode in cell.childNodes:
-            value = cls.read_cell(subnode, value_type)
-            if value:
-                return value
+            return cls.read_cell(subnode, value_type)
 
     @classmethod
     def import_set(cls, dset, in_stream, headers=True, skip_lines=0):


Test patch:
diff --git a/tests/test_tablib.py b/tests/test_tablib.py
index 3211991..4b0500d 100755
--- a/tests/test_tablib.py
+++ b/tests/test_tablib.py
@@ -1182,9 +1182,18 @@ class ODSTests(BaseTestCase):
         date = dt.date(2019, 10, 4)
         date_time = dt.datetime(2019, 10, 4, 12, 30, 8)
         time = dt.time(14, 30)
-        data.append(('string', '004', 42, 21.55, Decimal('34.5'), date, time, date_time, None))
+        data.append(('string', '004', 42, 21.55, Decimal('34.5'), date, time, date_time, None, ''))
         data.headers = (
-            'string', 'start0', 'integer', 'float', 'decimal', 'date', 'time', 'date/time', 'None'
+            'string',
+            'start0',
+            'integer',
+            'float',
+            'decimal',
+            'date',
+            'time',
+            'date/time',
+            'None',
+            'empty',
         )
         _ods = data.ods
         data.ods = _ods
@@ -1197,6 +1206,7 @@ class ODSTests(BaseTestCase):
         self.assertEqual(data.dict[0]['time'], time)
         self.assertEqual(data.dict[0]['date/time'], date_time)
         self.assertEqual(data.dict[0]['None'], '')
+        self.assertEqual(data.dict[0]['empty'], '')
 
     def test_ods_export_display(self):
         """Test that exported datetime types are displayed correctly in office software"""