From 55fd5d2b3f5c88ecf70e09b288ae794bf3e45d43 Mon Sep 17 00:00:00 2001 From: Claude Paroz Date: Tue, 19 Dec 2023 22:57:12 +0100 Subject: [PATCH] Fixes #572 - Allow appending rows after a dynamic column was inserted --- src/tablib/core.py | 9 ++++++++- tests/test_tablib.py | 6 ++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/tablib/core.py b/src/tablib/core.py index a7ebff2b..9010c0ad 100644 --- a/src/tablib/core.py +++ b/src/tablib/core.py @@ -155,6 +155,9 @@ def __init__(self, *args, **kwargs): # (column, callback) tuples self._formatters = [] + # {col_index: col_func} + self._dyn_columns = {} + self.headers = kwargs.get('headers') self.title = kwargs.get('title') @@ -238,7 +241,7 @@ def _set_in_format(self, fmt_key, in_stream, **kwargs): def _validate(self, row=None, col=None, safety=False): """Assures size of every row in dataset is of proper proportions.""" if row: - is_valid = (len(row) == self.width) if self.width else True + is_valid = (len(row) == (self.width - len(self._dyn_columns))) if self.width else True elif col: if len(col) < 1: is_valid = True @@ -449,6 +452,9 @@ def insert(self, index, row, tags=()): """ self._validate(row) + for pos, func in self._dyn_columns.items(): + row = list(row) + row.insert(pos, func(row)) self._data.insert(index, Row(row, tags=tags)) def rpush(self, row, tags=()): @@ -547,6 +553,7 @@ def insert_col(self, index, col=None, header=None): # Callable Columns... if hasattr(col, '__call__'): + self._dyn_columns[self.width] = col col = list(map(col, self._data)) col = self._clean_col(col) diff --git a/tests/test_tablib.py b/tests/test_tablib.py index 6c61c204..7d33f11d 100755 --- a/tests/test_tablib.py +++ b/tests/test_tablib.py @@ -186,6 +186,12 @@ def new_col(x): return x[0] self.founders.append_col(new_col, header='first_again') + # A new row can still be appended, and the dynamic column value generated. + self.founders.append(('Some', 'One', 71)) + self.assertEqual( + self.founders['first_again'], + ['John', 'George', 'Thomas', 'Some'] + ) def test_header_slicing(self): """Verify slicing by headers."""