diff --git a/src/humanize/number.py b/src/humanize/number.py index 52a5356a..964b5b99 100644 --- a/src/humanize/number.py +++ b/src/humanize/number.py @@ -169,10 +169,14 @@ def intcomma(value: NumberOrString, ndigits: int | None = None) -> str: Args: value (int, float, str): Integer or float to convert. - ndigits (int, None): Digits of precision for rounding after the decimal point. + ndigits (int, None): Non-negative digits of precision for rounding after the + decimal point. Returns: str: String containing commas every three digits. + + Raises: + ValueError: If a negative precision is used to format a number. """ import math @@ -195,6 +199,9 @@ def intcomma(value: NumberOrString, ndigits: int | None = None) -> str: return str(value) if ndigits is not None: + if ndigits < 0: + msg = "ndigits must be non-negative" + raise ValueError(msg) result = f"{value:,.{ndigits}f}" else: result = f"{value:,}" diff --git a/tests/test_number.py b/tests/test_number.py index 5fb12fa6..3f71d759 100644 --- a/tests/test_number.py +++ b/tests/test_number.py @@ -83,6 +83,13 @@ def test_intcomma( assert humanize.intcomma(*test_args) == expected +@pytest.mark.parametrize("value", [12345, 12345.111, "12345.111"]) +@pytest.mark.parametrize("ndigits", [-1, -10]) +def test_intcomma_negative_ndigits(value: float | str, ndigits: int) -> None: + with pytest.raises(ValueError, match="^ndigits must be non-negative$"): + humanize.intcomma(value, ndigits=ndigits) + + @pytest.mark.parametrize("sign", [1, -1]) def test_intcomma_large_integer(sign: int) -> None: value = sign * (10**400 + 123)