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 = [