diff --git a/src/humanize/time.py b/src/humanize/time.py index 4a07d52..18a58d5 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 7699770..1d757ba 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",