From 9e524493aee2791a2a0db33097d364a966698bf6 Mon Sep 17 00:00:00 2001 From: deepakganesh78 Date: Sun, 2 Aug 2026 22:27:24 +0530 Subject: [PATCH] Fix dynamic column callable placeholders Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- AUTHORS | 1 + HISTORY.md | 5 +++++ src/tablib/core.py | 8 +++++++- tests/test_tablib.py | 9 ++++++--- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index cd73e6574..218b1b2f5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -10,6 +10,7 @@ Here is a list of past and present much-appreciated contributors: Bruno Soares Claude Paroz Daniel Santos + Deepak Ganesh Egor Osokin Erik Youngren Hugo van Kemenade diff --git a/HISTORY.md b/HISTORY.md index 77f3b6b34..858518e4e 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,6 +2,11 @@ ## 3.9.0 and newer +### Bugfixes + +- Resolve dynamic column callables supplied as row placeholders when appending + rows (#576). + See GitHub Releases: - https://github.com/jazzband/tablib/releases diff --git a/src/tablib/core.py b/src/tablib/core.py index b0b56fd23..6ef49b39c 100644 --- a/src/tablib/core.py +++ b/src/tablib/core.py @@ -458,10 +458,16 @@ def insert(self, index, row, tags=()): :class:`Dataset` later. """ + row = list(row) + if len(row) == self.width: + for pos, func in sorted(self._dynamic_columns.items()): + if pos < len(row) and row[pos] is func: + source_row = row[:pos] + row[pos + 1:] + row[pos] = func(source_row) + self._validate(row) if len(row) < self.width: for pos, func in self._dynamic_columns.items(): - row = list(row) row.insert(pos, func(row)) self._data.insert(index, Row(row, tags=tags)) diff --git a/tests/test_tablib.py b/tests/test_tablib.py index ca8ac05ec..1041c20ea 100755 --- a/tests/test_tablib.py +++ b/tests/test_tablib.py @@ -205,16 +205,19 @@ def initials(row): self.founders.append(('Some', 'One', 71)) # Also acceptable when all dynamic column values are provided. self.founders.append(('Other', 'Second', 84, 'Other', 'OS')) + # Callable placeholders for dynamic columns are resolved when adding rows. + self.founders.append(('Brad', 'Montgomery', 70, new_col, initials)) self.assertEqual(self.founders[3], ('Some', 'One', 71, 'Some', 'SO')) self.assertEqual(self.founders[4], ('Other', 'Second', 84, 'Other', 'OS')) + self.assertEqual(self.founders[5], ('Brad', 'Montgomery', 70, 'Brad', 'BM')) self.assertEqual( self.founders['first_again'], - ['John', 'George', 'Thomas', 'Some', 'Other'] + ['John', 'George', 'Thomas', 'Some', 'Other', 'Brad'] ) self.assertEqual( self.founders['initials'], - ['JA', 'GW', 'TJ', 'SO', 'OS'] + ['JA', 'GW', 'TJ', 'SO', 'OS', 'BM'] ) # However only partial dynamic values provided is not accepted. @@ -226,7 +229,7 @@ def initials(row): self.founders.append(('After', 'Deletion', 75)) self.assertEqual( self.founders['initials'], - ['JA', 'GW', 'TJ', 'SO', 'OS', 'AD'] + ['JA', 'GW', 'TJ', 'SO', 'OS', 'BM', 'AD'] ) def test_header_slicing(self):