Bug: Table with duplicate column names not caught
When creating a Table within a worksheet, if duplicate column names are used, Excel reports that the workbook is corrupt. This is how to reproduce:
def table_error():
wb = openpyxl.Workbook()
ws = wb.active
ws.cell(row=1, column=1, value='Duplicate')
ws.cell(row=1, column=2, value='Duplicate')
ws.cell(row=2, column=1, value='Data')
ws.cell(row=2, column=2, value='Data')
table = openpyxl.worksheet.table.Table(displayName="Table1", ref="A1:B2")
ws.add_table(table)
wb.save('table_error.xlsx')
To fix this, I added a verify function in openpyxl/worksheet/table.py in the Table class:
def verify_colunn_names_are_unique(self):
column_names = [col.name for col in self.tableColumns]
if len(column_names) != len(set(column_names)):
duplicates = list(set([name for name in column_names if column_names.count(name) > 1]))
duplicates_text = ', '.join(duplicates)
warnings.warn(f'The table "{self.name}" has duplicate columns:{duplicates_text}. Some applications may not be able to read the file.')
The text is based off the long sheet names warning.
I then called this from write_tables() in openpyxl/worksheet/_writer.py after the code that populates the column names with whatever is in the cells:
def write_tables(self):
tables = TablePartList()
for table in self.ws._tables.values():
if not table.tableColumns:
table._initialise_columns()
if table.headerRowCount:
try:
row = self.ws[table.ref][0]
for cell, col in zip(row, table.tableColumns):
if cell.data_type != "s":
warn("File may not be readable: column headings must be strings.")
col.name = str(cell.value)
except TypeError:
warn("Column headings are missing, file may not be readable")
table.verify_colunn_names_are_unique()
rel = Relationship(Type=table._rel_type, Target="")
self._rels.append(rel)
table._rel_id = rel.Id
tables.append(Related(id=rel.Id))
if tables:
self.xf.send(tables.to_tree())
Thanks for all the work!