Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 28 additions & 6 deletions src/tablib/formats/_ods.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,22 +110,29 @@ 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 (AttributeError, TypeError, ValueError):
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
dset.headers = limit_row(row_vals)
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
Expand Down Expand Up @@ -248,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
Binary file added tests/files/columns_repeated.ods
Binary file not shown.
11 changes: 10 additions & 1 deletion tests/test_tablib.py
Original file line number Diff line number Diff line change
Expand Up @@ -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) + ('',) * 6)

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:
Expand Down
Loading