diff --git a/tabulate/__init__.py b/tabulate/__init__.py index 8f21abe7..e557ca3e 100644 --- a/tabulate/__init__.py +++ b/tabulate/__init__.py @@ -1253,20 +1253,10 @@ def _column_type(strings, has_invisible=True, numparse=True): def _format(val, valtype, floatfmt, intfmt, missingval="", has_invisible=True): - """Format a value according to its type. + """Format a value according to the type of the column.""" - Unicode is supported: - - >>> hrow = ['\u0431\u0443\u043a\u0432\u0430', '\u0446\u0438\u0444\u0440\u0430'] ; \ - tbl = [['\u0430\u0437', 2], ['\u0431\u0443\u043a\u0438', 4]] ; \ - good_result = '\\u0431\\u0443\\u043a\\u0432\\u0430 \\u0446\\u0438\\u0444\\u0440\\u0430\\n------- -------\\n\\u0430\\u0437 2\\n\\u0431\\u0443\\u043a\\u0438 4' ; \ - tabulate(tbl, headers=hrow) == good_result - True - - """ # noqa if val is None: return missingval - if valtype is str: return f"{val}" elif valtype is int: @@ -1287,16 +1277,28 @@ def _format(val, valtype, floatfmt, intfmt, missingval="", has_invisible=True): return str(val, "ascii") except (TypeError, UnicodeDecodeError): return str(val) + + # the rest is for bool and number values in bool and number column types + is_ansi_colored = has_invisible and isinstance(val, (str, bytes)) + # strip color if needed, reapply before return + if is_ansi_colored: + colored_val = val + val = raw_val = _strip_ansi(val) + if _isbool(val): + # val should be a boolean literal to convert into a number if needed + val = val in (True, "True") + if valtype is int: + # do not convert strings and bools into integers if there is no special formatting + if intfmt: + val = int(val) + val = format(val, intfmt) elif valtype is float: - is_a_colored_number = has_invisible and isinstance(val, (str, bytes)) - if is_a_colored_number: - raw_val = _strip_ansi(val) - formatted_val = format(float(raw_val), floatfmt) - return val.replace(raw_val, formatted_val) - else: - return format(float(val), floatfmt) + val = format(float(val), floatfmt) else: - return f"{val}" + val = f"{val}" + if is_ansi_colored: + val = colored_val.replace(raw_val, val) + return val def _align_header( diff --git a/test/test_input.py b/test/test_input.py index 721d03a1..78da63b7 100644 --- a/test/test_input.py +++ b/test/test_input.py @@ -50,6 +50,27 @@ def test_iterable_of_iterables_firstrow(): assert_equal(expected, result) +def test_mixed_bools(): + "Input: a list of lists with mixed number and bool values." + ll = [ + ["1.1", "1000", "1000"], + [True, True, True], + ["False", "False", "False"], + ] + # notice INCONSISTENCY in boolean representation + expected = "\n".join( + [ + "--- ----- -----", + "1.1 1000 1,000", + "1.0 True 1", + "0.0 False 0", + "--- ----- -----", + ] + ) + result = tabulate(ll, floatfmt=".1f", intfmt=("", "", ",")) + assert_equal(expected, result) + + def test_list_of_lists(): "Input: a list of lists with headers." ll = [["a", "one", 1], ["b", "two", None]]