diff --git a/src/humanize/time.py b/src/humanize/time.py index 4a07d52..3d5ef12 100644 --- a/src/humanize/time.py +++ b/src/humanize/time.py @@ -117,9 +117,6 @@ def naturaldelta( converted to int (cannot be float due to 'inf' or 'nan'). In that case, a `value` is returned unchanged. - Raises: - OverflowError: If `value` is too large to convert to datetime.timedelta. - Examples: Compare two timestamps in a custom local timezone:: @@ -151,6 +148,13 @@ def naturaldelta( int(value) # Explicitly don't support string such as "NaN" or "inf" value = float(value) delta = dt.timedelta(seconds=value) + except OverflowError: + # int(value) raises OverflowError for non-finite floats (inf/-inf). + # Like NaN they are returned unchanged. A truly too-large *finite* + # float still raises, preserving the documented OverflowError contract. + if not math.isfinite(value): + return str(value) + raise except (ValueError, TypeError): return str(value) diff --git a/tests/test_time.py b/tests/test_time.py index 7699770..d5856ed 100644 --- a/tests/test_time.py +++ b/tests/test_time.py @@ -138,6 +138,25 @@ def test_naturaldelta(test_input: float | dt.timedelta, expected: str) -> None: assert humanize.naturaldelta(-test_input) == expected +def test_naturaldelta_non_finite_floats() -> None: + """Regression for #333: non-finite floats must not raise OverflowError. + + float("inf") and float("-inf") trigger int(value) -> OverflowError inside + timedelta(seconds=value). They should be returned as strings, like float("nan"). + A legitimately too-large *finite* float must still raise OverflowError. + """ + # Non-finite values return the string repr + assert humanize.naturaldelta(float("inf")) == "inf" + assert humanize.naturaldelta(float("-inf")) == "-inf" + # NaN already worked before; confirm it still does + assert humanize.naturaldelta(float("nan")) == "nan" + # A truly too-large finite float must still raise (documented behaviour) + import pytest + + with pytest.raises(OverflowError): + humanize.naturaldelta(1e308 * 10) + + @freeze_time(FROZEN_DATE) @pytest.mark.parametrize( "test_input, expected",