From 6fba6ef46499bf0c31ff15fbb2e613bb194a6b6a Mon Sep 17 00:00:00 2001 From: Vincent Gao Date: Sun, 14 Jun 2026 23:34:33 +0200 Subject: [PATCH] Fix crash when wrapping a pandas NA scalar (#429) In _wrap_text_to_colwidths the empty-string check compared each cell directly to "". For a pandas NA scalar, cell == "" returns a non-bool NA whose truthiness then raises "boolean value of NA is ambiguous" inside the surrounding or, so tabulate crashed whenever maxcolwidths was set and any cell was pd.NA. Guard the comparison with isinstance(cell, str) so only real strings are tested for emptiness; the NA then flows through the normal _type path and renders as , matching how plain tabulate (without maxcolwidths) already displays it. --- tabulate/__init__.py | 6 +++++- test/test_textwrapper.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/tabulate/__init__.py b/tabulate/__init__.py index 12a2950..b306341 100644 --- a/tabulate/__init__.py +++ b/tabulate/__init__.py @@ -1651,7 +1651,11 @@ def _wrap_text_to_colwidths( if cell is None else ( str(cell) - if cell == "" or _isnumber(cell) + # Guard the empty-string check with isinstance: comparing + # a non-string scalar such as pandas' ``pd.NA`` to "" can + # return a non-bool whose truthiness then raises (e.g. + # "boolean value of NA is ambiguous") inside the ``or``. + if (isinstance(cell, str) and cell == "") or _isnumber(cell) else str(_type(cell, numparse)(cell)) ) ) diff --git a/test/test_textwrapper.py b/test/test_textwrapper.py index e6bab0f..bb0f270 100644 --- a/test/test_textwrapper.py +++ b/test/test_textwrapper.py @@ -302,6 +302,36 @@ def test_wrap_none_value_with_missingval(): assert_equal(expected, result) +def test_wrap_pandas_na_value(): + """TextWrapper: a pandas NA scalar must wrap without crashing (issue #429). + + ``pd.NA == ""`` returns a non-bool ``NA`` whose truthiness raises + "boolean value of NA is ambiguous"; wrapping must guard against that. + """ + try: + import pandas as pd + except ImportError: + skip("test_wrap_pandas_na_value is skipped") + + data = [["First Entry", pd.NA], ["Second Entry", pd.NA]] + headers = ["Title", "Value"] + result = tabulate(data, headers=headers, tablefmt="grid", maxcolwidths=[7, 5]) + + expected = [ + "+---------+---------+", + "| Title | Value |", + "+=========+=========+", + "| First | |", + "| Entry | |", + "+---------+---------+", + "| Second | |", + "| Entry | |", + "+---------+---------+", + ] + expected = "\n".join(expected) + assert_equal(expected, result) + + def test_wrap_optional_bool_strs(): """TextWrapper: Show that str bools and None can be wrapped without crashing""" data = [