From 519076acef66d8153b5783ffed7c8013576e0841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Afonso=20Janu=C3=A1rio?= Date: Fri, 4 Sep 2026 20:36:53 +0100 Subject: [PATCH] Stop crashing on ANSI-colored numeric strings under maxcolwidths When maxcolwidths triggers text wrapping, each cell gets cast through _type(cell, numparse)(cell) before wrapping. _type() strips ANSI escapes internally just to classify the value, then hands back a constructor like int or float, which the caller applies to the original, still-escaped string. A colored cell like a yellow-and-black "3" reads as an int once the codes are stripped, but int() on the raw string with the escape sequences still in it just raises ValueError. Since the cell is already a string in this case, there's no need to cast it at all: the existing branch right above already skips casting for values that already look like numbers via _isnumber(), so this just extends that same short-circuit to strings carrying ANSI codes, covering both the str and bytes forms. Fixes GH-359. --- tabulate/__init__.py | 8 +++++++- test/test_regression.py | 9 +++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/tabulate/__init__.py b/tabulate/__init__.py index 12a2950..db4067a 100644 --- a/tabulate/__init__.py +++ b/tabulate/__init__.py @@ -1651,7 +1651,13 @@ def _wrap_text_to_colwidths( if cell is None else ( str(cell) - if cell == "" or _isnumber(cell) + if cell == "" + or _isnumber(cell) + or (isinstance(cell, str) and _ansi_codes.search(cell)) + or ( + isinstance(cell, bytes) + and _ansi_codes_bytes.search(cell) + ) else str(_type(cell, numparse)(cell)) ) ) diff --git a/test/test_regression.py b/test/test_regression.py index 9555676..e73c40b 100644 --- a/test/test_regression.py +++ b/test/test_regression.py @@ -531,6 +531,15 @@ def test_exception_on_empty_data_with_maxcolwidths(): assert_equal(result, "") +def test_colored_number_with_maxcolwidths(): + "Regression: ANSI-colored numeric strings crash when wrapped by maxcolwidths (github issue #359)" + colored_three = "\033[31m3\033[0m" + result = tabulate([[colored_three]], maxcolwidths=10) + assert "3" in result + assert "\033[31m" in result + assert "\033[0m" in result + + def test_numpy_int64_as_integer(): "Regression: format numpy.int64 as integer (github issue #18)" try: