From 331b4c68bc0bc05c33269c90d286737a2ca437e8 Mon Sep 17 00:00:00 2001 From: Charlie Tonneslan Date: Sun, 24 May 2026 08:15:04 -0400 Subject: [PATCH] fractional: stop printing two minus signs for a negative mixed number int() truncates toward zero, so int(-1.3) is -1 and (-1.3) - (-1) is -0.3, which Fraction turns into -3/10. Both the whole-number part and the numerator end up signed and the output reads as "-1 -3/10". The minus sign already rides on the whole-number part; absorb it from the numerator so the result is the conventional "-1 3/10". Added a few negative cases to test_fractional. Signed-off-by: Charlie Tonneslan --- src/humanize/number.py | 7 ++++++- tests/test_number.py | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/humanize/number.py b/src/humanize/number.py index f4dcb05d..1cbfc2b3 100644 --- a/src/humanize/number.py +++ b/src/humanize/number.py @@ -367,7 +367,12 @@ def fractional(value: NumberOrString) -> str: if not whole_number: return f"{numerator:.0f}/{denominator:.0f}" - return f"{whole_number:.0f} {numerator:.0f}/{denominator:.0f}" + # int() truncates toward zero, so for a negative number both + # whole_number and numerator carry the minus sign, which prints as + # "-1 -3/10". The sign already rides on the whole part; absorb it + # from the fractional part so the result reads as a normal mixed + # fraction. + return f"{whole_number:.0f} {abs(numerator):.0f}/{denominator:.0f}" def scientific(value: NumberOrString, precision: int = 2) -> str: diff --git a/tests/test_number.py b/tests/test_number.py index cb74fcf0..d8f9100a 100644 --- a/tests/test_number.py +++ b/tests/test_number.py @@ -183,6 +183,9 @@ def test_apnumber(test_input: int | str, expected: str) -> None: (-math.inf, "-Inf"), ("nan", "NaN"), ("-inf", "-Inf"), + (-1.3, "-1 3/10"), + (-2.5, "-2 1/2"), + (-0.5, "-1/2"), ], ) def test_fractional(test_input: float | str, expected: str) -> None: