From fd8d96c5355669edf0a47afce662345e4dc38657 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 14 Apr 2022 14:58:09 -0400 Subject: [PATCH 01/10] fix decimal precision issue --- tabulate.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tabulate.py b/tabulate.py index 0579fb3f..d89bdfdc 100644 --- a/tabulate.py +++ b/tabulate.py @@ -5,6 +5,7 @@ from __future__ import print_function from __future__ import unicode_literals from collections import namedtuple +from decimal import Decimal import sys import re import math @@ -996,7 +997,7 @@ def _format(val, valtype, floatfmt, missingval="", has_invisible=True): formatted_val = format(float(raw_val), floatfmt) return val.replace(raw_val, formatted_val) else: - return format(float(val), floatfmt) + return format(Decimal(val), floatfmt) else: return "{0}".format(val) From ad23d3778b13a326ed86cbe63b7e20a0a9acdcb8 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 14 Apr 2022 15:04:53 -0400 Subject: [PATCH 02/10] fix other float to Decimal --- tabulate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tabulate.py b/tabulate.py index d89bdfdc..2e77ebe9 100644 --- a/tabulate.py +++ b/tabulate.py @@ -994,7 +994,7 @@ def _format(val, valtype, floatfmt, missingval="", has_invisible=True): ) if is_a_colored_number: raw_val = _strip_invisible(val) - formatted_val = format(float(raw_val), floatfmt) + formatted_val = format(Decimal(raw_val), floatfmt) return val.replace(raw_val, formatted_val) else: return format(Decimal(val), floatfmt) From dac53ae286dd59b4f6d61e617f1e5f0c68c77c21 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 14 Apr 2022 15:59:00 -0400 Subject: [PATCH 03/10] fix float precision --- tabulate.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/tabulate.py b/tabulate.py index 2e77ebe9..9e91f246 100644 --- a/tabulate.py +++ b/tabulate.py @@ -5,7 +5,7 @@ from __future__ import print_function from __future__ import unicode_literals from collections import namedtuple -from decimal import Decimal +from decimal import Decimal, getcontext, setcontext, Context import sys import re import math @@ -993,11 +993,23 @@ def _format(val, valtype, floatfmt, missingval="", has_invisible=True): val, (_text_type, _binary_type) ) if is_a_colored_number: + print("HIIIIII", val) raw_val = _strip_invisible(val) - formatted_val = format(Decimal(raw_val), floatfmt) + formatted_val = format(Decimal(str(raw_val)), floatfmt) return val.replace(raw_val, formatted_val) else: - return format(Decimal(val), floatfmt) + context = Context(clamp=1, prec=6) + setcontext(context) + try: + if "f" in floatfmt: + if int(Decimal(val)) == Decimal(val): + val = int(Decimal(val, context=context)) + val = Decimal(str(val), context=context) + else: + val = float(val) + except (OverflowError, ValueError): + val = float(val) + return format(val, floatfmt) else: return "{0}".format(val) From 07e9ef669cfcfd927db6e048378813b625be09f0 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 14 Apr 2022 16:05:44 -0400 Subject: [PATCH 04/10] add test --- test/test_output.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/test_output.py b/test/test_output.py index eed44895..1f103f2c 100644 --- a/test/test_output.py +++ b/test/test_output.py @@ -1428,6 +1428,12 @@ def test_floatfmt_multi(): assert_equal(expected, result) +def test_floatfmt_precision(): + result = tabulate([[99999998999.999980]], floatfmt=".6f", tablefmt="plain") + expected = "99999998999.999980" + assert_equal(expected, result) + + def test_colalign_multi(): "Output: string columns with custom colalign" result = tabulate( From 810e744ba5cdd7a0479041e1fccff2d75a9703de Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 14 Apr 2022 16:06:27 -0400 Subject: [PATCH 05/10] clean up --- tabulate.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tabulate.py b/tabulate.py index 9e91f246..f5cd51f3 100644 --- a/tabulate.py +++ b/tabulate.py @@ -5,7 +5,7 @@ from __future__ import print_function from __future__ import unicode_literals from collections import namedtuple -from decimal import Decimal, getcontext, setcontext, Context +from decimal import Decimal import sys import re import math @@ -993,18 +993,15 @@ def _format(val, valtype, floatfmt, missingval="", has_invisible=True): val, (_text_type, _binary_type) ) if is_a_colored_number: - print("HIIIIII", val) raw_val = _strip_invisible(val) - formatted_val = format(Decimal(str(raw_val)), floatfmt) + formatted_val = format(float(val), floatfmt) return val.replace(raw_val, formatted_val) else: - context = Context(clamp=1, prec=6) - setcontext(context) try: if "f" in floatfmt: if int(Decimal(val)) == Decimal(val): - val = int(Decimal(val, context=context)) - val = Decimal(str(val), context=context) + val = int(Decimal(val)) + val = Decimal(str(val)) else: val = float(val) except (OverflowError, ValueError): From 9990531aa8da61781873d139528adae03bc7b270 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 14 Apr 2022 16:10:07 -0400 Subject: [PATCH 06/10] fix bug --- tabulate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tabulate.py b/tabulate.py index f5cd51f3..ad7f17e3 100644 --- a/tabulate.py +++ b/tabulate.py @@ -994,7 +994,7 @@ def _format(val, valtype, floatfmt, missingval="", has_invisible=True): ) if is_a_colored_number: raw_val = _strip_invisible(val) - formatted_val = format(float(val), floatfmt) + formatted_val = format(float(raw_val), floatfmt) return val.replace(raw_val, formatted_val) else: try: From d4f0d919d22fad8d95501d67f51b17dc6b3daec3 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 14 Apr 2022 16:17:09 -0400 Subject: [PATCH 07/10] expand test --- tabulate.py | 4 +--- test/test_output.py | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/tabulate.py b/tabulate.py index ad7f17e3..ed8adecd 100644 --- a/tabulate.py +++ b/tabulate.py @@ -998,9 +998,7 @@ def _format(val, valtype, floatfmt, missingval="", has_invisible=True): return val.replace(raw_val, formatted_val) else: try: - if "f" in floatfmt: - if int(Decimal(val)) == Decimal(val): - val = int(Decimal(val)) + if "f" in floatfmt and float('-inf') < float(val) < float('inf'): val = Decimal(str(val)) else: val = float(val) diff --git a/test/test_output.py b/test/test_output.py index 1f103f2c..1820878e 100644 --- a/test/test_output.py +++ b/test/test_output.py @@ -1429,8 +1429,8 @@ def test_floatfmt_multi(): def test_floatfmt_precision(): - result = tabulate([[99999998999.999980]], floatfmt=".6f", tablefmt="plain") - expected = "99999998999.999980" + result = tabulate([[99999998999.999980, 1234.5, 1.2345678, "inf"]], floatfmt=".6f", tablefmt="plain") + expected = "99999998999.999980 1234.500000 1.234568 inf" assert_equal(expected, result) From 0b1d392ee81389eb3c0f138b65e4457a56b9acfc Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 14 Apr 2022 17:10:17 -0400 Subject: [PATCH 08/10] fix test to get around weird precision issues in python2.7 --- test/test_output.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_output.py b/test/test_output.py index 1820878e..38f17660 100644 --- a/test/test_output.py +++ b/test/test_output.py @@ -1429,7 +1429,7 @@ def test_floatfmt_multi(): def test_floatfmt_precision(): - result = tabulate([[99999998999.999980, 1234.5, 1.2345678, "inf"]], floatfmt=".6f", tablefmt="plain") + result = tabulate([["99999998999.999980", 1234.5, 1.2345678, "inf"]], floatfmt=".6f", tablefmt="plain") expected = "99999998999.999980 1234.500000 1.234568 inf" assert_equal(expected, result) From 37724ee58fc4b287754dbe6f0fba11f03e05b4a9 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Fri, 25 Jul 2025 13:24:11 -0400 Subject: [PATCH 09/10] lint --- README.md | 12 ++++++------ test/test_output.py | 8 +++++++- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 223a85a2..5c69cd93 100644 --- a/README.md +++ b/README.md @@ -503,10 +503,10 @@ format: >>> print(tabulate(table, headers, tablefmt="asciidoc")) [cols="8<,7>",options="header"] |==== -| item | qty -| spam | 42 -| eggs | 451 -| bacon | 0 +| item | qty +| spam | 42 +| eggs | 451 +| bacon | 0 |==== ``` @@ -1065,11 +1065,11 @@ the lines being wrapped would probably be significantly longer than this. Text is preferably wrapped on whitespaces and right after the hyphens in hyphenated words. -break_long_words (default: True) If true, then words longer than width will be broken in order to ensure that no lines are longer than width. +break_long_words (default: True) If true, then words longer than width will be broken in order to ensure that no lines are longer than width. If it is false, long words will not be broken, and some lines may be longer than width. (Long words will be put on a line by themselves, in order to minimize the amount by which width is exceeded.) -break_on_hyphens (default: True) If true, wrapping will occur preferably on whitespaces and right after hyphens in compound words, as it is customary in English. +break_on_hyphens (default: True) If true, wrapping will occur preferably on whitespaces and right after hyphens in compound words, as it is customary in English. If false, only whitespaces will be considered as potentially good places for line breaks. ```pycon diff --git a/test/test_output.py b/test/test_output.py index d99037f3..e3af6abb 100644 --- a/test/test_output.py +++ b/test/test_output.py @@ -2897,7 +2897,11 @@ def test_floatfmt_multi(): def test_floatfmt_precision(): - result = tabulate([["99999998999.999980", 1234.5, 1.2345678, "inf"]], floatfmt=".6f", tablefmt="plain") + result = tabulate( + [["99999998999.999980", 1234.5, 1.2345678, "inf"]], + floatfmt=".6f", + tablefmt="plain", + ) expected = "99999998999.999980 1234.500000 1.234568 inf" assert_equal(expected, result) @@ -3326,6 +3330,7 @@ def test_preserve_whitespace(): result = tabulate(test_table, table_headers, preserve_whitespace=False) assert_equal(expected, result) + def test_break_long_words(): "Output: Default table output, with breakwords true." table_headers = ["h1", "h2", "h3"] @@ -3341,6 +3346,7 @@ def test_break_long_words(): result = tabulate(test_table, table_headers, maxcolwidths=3, break_long_words=True) assert_equal(expected, result) + def test_break_on_hyphens(): "Output: Default table output, with break on hyphens true." table_headers = ["h1", "h2", "h3"] From 94989986a31b194ff9a795d32cbcc1c0ec9e9a57 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Fri, 25 Jul 2025 13:29:13 -0400 Subject: [PATCH 10/10] respond to comments --- tabulate/__init__.py | 11 +++-------- test/test_output.py | 5 +++-- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/tabulate/__init__.py b/tabulate/__init__.py index 4fc1a4f3..69ed495b 100644 --- a/tabulate/__init__.py +++ b/tabulate/__init__.py @@ -1358,14 +1358,9 @@ def _format(val, valtype, floatfmt, intfmt, missingval="", has_invisible=True): else: if isinstance(val, str) and "," in val: val = val.replace(",", "") # handle thousands-separators - try: - if "f" in floatfmt and float("-inf") < float(val) < float("inf"): - val = Decimal(str(val)) - else: - val = float(val) - except (OverflowError, ValueError): - val = float(val) - return format(val, floatfmt) + if isinstance(val, Decimal): + return format(val, floatfmt) + return format(float(val), floatfmt) else: return f"{val}" diff --git a/test/test_output.py b/test/test_output.py index e3af6abb..4befbb98 100644 --- a/test/test_output.py +++ b/test/test_output.py @@ -1,5 +1,6 @@ """Test output of the various forms of tabular data.""" +from decimal import Decimal from pytest import mark from common import assert_equal, raises, skip, check_warnings @@ -2896,9 +2897,9 @@ def test_floatfmt_multi(): assert_equal(expected, result) -def test_floatfmt_precision(): +def test_floatfmt_decimal(): result = tabulate( - [["99999998999.999980", 1234.5, 1.2345678, "inf"]], + [[Decimal("99999998999.999980"), 1234.5, 1.2345678, "inf"]], floatfmt=".6f", tablefmt="plain", )