From 6cc366ff3408ddc71f82cefeaf06fe91492697d0 Mon Sep 17 00:00:00 2001 From: x0Lazarus <113273587+x0Lazarus@users.noreply.github.com> Date: Fri, 18 Sep 2026 07:11:05 -0700 Subject: [PATCH] Preserve large integer strings in intcomma --- src/humanize/number.py | 12 +++++++++--- tests/test_i18n.py | 7 +++++++ tests/test_number.py | 18 ++++++++++++++++-- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/humanize/number.py b/src/humanize/number.py index 52a5356a..b8d6cbe3 100644 --- a/src/humanize/number.py +++ b/src/humanize/number.py @@ -181,12 +181,18 @@ def intcomma(value: NumberOrString, ndigits: int | None = None) -> str: try: if isinstance(value, str): value = value.replace(thousands_sep, "").replace(decimal_sep, ".") - if not math.isfinite(float(value)): + if ndigits is not None and not math.isfinite(float(value)): return _format_not_finite(float(value)) - if "." in value: + try: + integer_value = int(value) + except ValueError: + if not math.isfinite(float(value)): + return _format_not_finite(float(value)) + if "." not in value: + raise value = float(value) else: - value = int(value) + value = integer_value elif not isinstance(value, int): if not math.isfinite(float(value)): return _format_not_finite(float(value)) diff --git a/tests/test_i18n.py b/tests/test_i18n.py index 20db617b..e4e4452e 100644 --- a/tests/test_i18n.py +++ b/tests/test_i18n.py @@ -104,6 +104,7 @@ def test_i18n() -> None: def test_intcomma() -> None: number = 10_000_000 + large_number = str(10**400 + 123) assert humanize.intcomma(number) == "10,000,000" @@ -115,11 +116,17 @@ def test_intcomma() -> None: assert humanize.intcomma("1234567,89") == "1.234.567,89" assert humanize.intcomma("1.234.567,89") == "1.234.567,89" assert humanize.intcomma("1.234.567,8") == "1.234.567,8" + large_expected = "10" + ".000" * 132 + ".123" + assert humanize.intcomma(large_number) == large_expected + assert humanize.intcomma(large_expected) == large_expected humanize.i18n.activate("fr_FR") assert humanize.intcomma(number) == "10 000 000" assert humanize.intcomma(1_234_567.89) == "1 234 567,89" assert humanize.intcomma("1 234 567,89") == "1 234 567,89" + large_expected = "10" + " 000" * 132 + " 123" + assert humanize.intcomma(large_number) == large_expected + assert humanize.intcomma(large_expected) == large_expected humanize.i18n.activate("pt_BR") assert humanize.intcomma(number) == "10.000.000" diff --git a/tests/test_number.py b/tests/test_number.py index 5fb12fa6..21a1d7b1 100644 --- a/tests/test_number.py +++ b/tests/test_number.py @@ -75,6 +75,14 @@ def test_ordinal(test_input: str, expected: str) -> None: ([-math.inf], "-Inf"), (["nan"], "NaN"), (["-inf"], "-Inf"), + (["inf"], "+Inf"), + (["1e400"], "+Inf"), + (["1.0e400"], "+Inf"), + (["1e3"], "1e3"), + (["1.0e3"], "1,000.0"), + (["not a number"], "not a number"), + ([str(10**400 + 123), 2], "+Inf"), + ([str(-(10**400 + 123)), 2], "-Inf"), ], ) def test_intcomma( @@ -84,10 +92,16 @@ def test_intcomma( @pytest.mark.parametrize("sign", [1, -1]) -def test_intcomma_large_integer(sign: int) -> None: +@pytest.mark.parametrize("representation", ["integer", "string", "grouped_string"]) +def test_intcomma_large_integer(sign: int, representation: str) -> None: value = sign * (10**400 + 123) expected = ("-" if sign < 0 else "") + "10" + ",000" * 132 + ",123" - assert humanize.intcomma(value) == expected + argument = ( + str(value) + if representation == "string" + else expected if representation == "grouped_string" else value + ) + assert humanize.intcomma(argument) == expected def test_intword_powers() -> None: