From be9db5e836f66416b6dc6f898f9f2677af203bc4 Mon Sep 17 00:00:00 2001 From: Andrew Graham-Yooll Date: Sat, 18 Jan 2025 15:13:05 +0800 Subject: [PATCH] Update tests and code for easier reading --- src/tablib/formats/_xlsx.py | 20 +++++++------ tests/test_tablib.py | 56 ++++++++++++++++++------------------- 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/src/tablib/formats/_xlsx.py b/src/tablib/formats/_xlsx.py index 1a496af6..96c72876 100644 --- a/src/tablib/formats/_xlsx.py +++ b/src/tablib/formats/_xlsx.py @@ -9,7 +9,6 @@ from openpyxl.styles import Alignment, Font from openpyxl.utils import get_column_letter from openpyxl.workbook import Workbook -from openpyxl.writer.excel import ExcelWriter import tablib @@ -50,6 +49,11 @@ def export_set(cls, dataset, freeze_panes=True, invalid_char_subst="-", escape=F If ``escape`` is True, formulae will have the leading '=' character removed. This is a security measure to prevent formulae from executing by default in exported XLSX files. + + If ``column_width`` is set to "adaptive", the column width will be set to the maximum + width of the content in each column. If it is set to an integer, the column width will be + set to that integer value. If it is set to None, the column width will be set as the default openpyxl.Worksheet width value. + """ wb = Workbook() ws = wb.worksheets[0] @@ -60,9 +64,6 @@ def export_set(cls, dataset, freeze_panes=True, invalid_char_subst="-", escape=F ) cls.dset_sheet(dataset, ws, freeze_panes=freeze_panes, escape=escape) - if isinstance(column_width, str) and column_width != "adaptive": - raise ValueError(f"Unsupported value `{column_width}` passed to `column_width` " - "parameter. It supports 'adaptive' or integer values") cls._adapt_column_width(ws, column_width) @@ -175,13 +176,16 @@ def dset_sheet(cls, dataset, ws, freeze_panes=True, escape=False): cell.value = cell.value.replace("=", "") @classmethod - def _adapt_column_width(cls, worksheet, - width: str | int | None) -> None: + def _adapt_column_width(cls, worksheet, width): + if isinstance(width, str) and width != "adaptive": + raise ValueError(f"Unsupported value `{width}` passed to `column_width` " + "parameter. It supports 'adaptive' or integer values") + if width is None: return column_widths = [] - if isinstance(width, str) and width == "adaptive": + if width == "adaptive": for row in worksheet.values: for i, cell in enumerate(row): cell = str(cell) @@ -189,7 +193,7 @@ def _adapt_column_width(cls, worksheet, if len(cell) > column_widths[i]: column_widths[i] = len(cell) else: - column_widths += [len(cell)] + column_widths.append(len(cell)) else: column_widths = [width] * worksheet.max_column diff --git a/tests/test_tablib.py b/tests/test_tablib.py index c9184ffa..0e5a92ef 100755 --- a/tests/test_tablib.py +++ b/tests/test_tablib.py @@ -1341,6 +1341,24 @@ def get_format_str(cell): class XLSXTests(BaseTestCase): + def _helper_export_column_width(self, column_width): + """check that column width adapts to value length""" + def _get_width(data, input_arg): + xlsx_content = data.export('xlsx', column_width=input_arg) + wb = load_workbook(filename=BytesIO(xlsx_content)) + ws = wb.active + return ws.column_dimensions['A'].width + + xls_source = Path(__file__).parent / 'files' / 'xlsx_cell_values.xlsx' + with xls_source.open('rb') as fh: + data = tablib.Dataset().load(fh) + width_before = _get_width(data, column_width) + data.append([ + 'verylongvalue-verylongvalue-verylongvalue-verylongvalue-verylongvalue-verylongvalue-verylongvalue-verylongvalue', + ]) + width_after = _get_width(data, width_before) + return width_before, width_after + def test_xlsx_format_detect(self): """Test the XLSX format detection.""" in_stream = self.founders.xlsx @@ -1484,45 +1502,27 @@ def test_xlsx_raise_ValueError_on_cell_write_during_export(self): _xlsx = data.export('xlsx') wb = load_workbook(filename=BytesIO(_xlsx)) self.assertEqual('[1]', wb.active['A1'].value) - - def _helper_export_column_width(self, input_arg): - """check that column width adapts to value length""" - def _get_width(data, input_arg): - xlsx_content = data.export('xlsx', column_width=input_arg) - wb = load_workbook(filename=BytesIO(xlsx_content)) - ws = wb.active - return ws.column_dimensions['A'].width - - xls_source = Path(__file__).parent / 'files' / 'xlsx_cell_values.xlsx' - with xls_source.open('rb') as fh: - data = tablib.Dataset().load(fh) - width_before = _get_width(data, input_arg) - data.append([ - 'verylongvalue-verylongvalue-verylongvalue-verylongvalue-verylongvalue-verylongvalue-verylongvalue-verylongvalue', - ]) - width_after = _get_width(data, width_before) - return width_before, width_after - - def test_xlsx_column_width_none(self): - """check column width with None""" - width_before, width_after = self._helper_export_column_width(None) - self.assertEqual(width_before, 13) - self.assertEqual(width_after, 13) - + def test_xlsx_column_width_adaptive(self): - """check column width with 'adaptive'""" + """ Test that column width adapts to value length""" width_before, width_after = self._helper_export_column_width("adaptive") self.assertEqual(width_before, 11) self.assertEqual(width_after, 11) def test_xlsx_column_width_integer(self): - """check column width with an integer""" + """Test that column width changes to integer length""" width_before, width_after = self._helper_export_column_width(10) self.assertEqual(width_before, 10) self.assertEqual(width_after, 10) + + def test_xlsx_column_width_none(self): + """Test that column width does not change""" + width_before, width_after = self._helper_export_column_width(None) + self.assertEqual(width_before, 13) + self.assertEqual(width_after, 13) def test_xlsx_column_width_value_error(self): - """check column width with invalid input""" + """Raise ValueError if column_width is not a valid input""" with self.assertRaises(ValueError): self._helper_export_column_width("invalid input")