From 95c447063e88c4bebada3f530b44714bb5f9f121 Mon Sep 17 00:00:00 2001 From: eeshsaxena Date: Sat, 4 Jul 2026 14:53:41 +0530 Subject: [PATCH] Return non-finite floats unchanged from naturaldelta naturaldelta() documents that a value which cannot be converted to a number is returned unchanged. float("nan") was handled because int(nan) raises ValueError, but float("inf")/float("-inf") raised an uncaught OverflowError from int(value), which the except clause omitted. Catch OverflowError alongside ValueError/TypeError around the int() guard so infinity is returned unchanged, symmetric with nan. The catch is scoped to the int() conversion only, so a finite value too large for datetime.timedelta still raises OverflowError from timedelta(), as documented. Fixes #333 --- src/humanize/time.py | 13 +++++++++---- tests/test_time.py | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/humanize/time.py b/src/humanize/time.py index 4a07d528..18a58d55 100644 --- a/src/humanize/time.py +++ b/src/humanize/time.py @@ -148,11 +148,16 @@ def naturaldelta( delta = value else: try: - int(value) # Explicitly don't support string such as "NaN" or "inf" - value = float(value) - delta = dt.timedelta(seconds=value) - except (ValueError, TypeError): + # Explicitly don't support non-finite or non-numeric values such as + # "NaN"/"inf": int() raises ValueError for NaN and OverflowError for + # infinity, and TypeError for unsupported types. + int(value) + except (ValueError, TypeError, OverflowError): return str(value) + value = float(value) + # A finite value that is too large for timedelta still raises + # OverflowError here, as documented. + delta = dt.timedelta(seconds=value) use_months = months diff --git a/tests/test_time.py b/tests/test_time.py index 76997704..1d757ba9 100644 --- a/tests/test_time.py +++ b/tests/test_time.py @@ -138,6 +138,27 @@ def test_naturaldelta(test_input: float | dt.timedelta, expected: str) -> None: assert humanize.naturaldelta(-test_input) == expected +@pytest.mark.parametrize( + "test_input, expected", + [ + (float("nan"), "nan"), + (float("inf"), "inf"), + (float("-inf"), "-inf"), + ], +) +def test_naturaldelta_nonfinite(test_input: float, expected: str) -> None: + # Non-finite floats are returned unchanged, per the docstring. `nan` raises + # ValueError from int() while `inf` raises OverflowError; both are caught. + assert humanize.naturaldelta(test_input) == expected + + +def test_naturaldelta_overflow() -> None: + # A finite value too large to convert to a timedelta still raises, as + # documented, and is not swallowed by the non-finite guard. + with pytest.raises(OverflowError): + humanize.naturaldelta(1e40) + + @freeze_time(FROZEN_DATE) @pytest.mark.parametrize( "test_input, expected",