From 99f7fb4b94aa1fa68b6bdbff5acb2ad75519013b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 2 Jul 2026 15:54:29 +0000 Subject: [PATCH 1/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_time.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_time.py b/tests/test_time.py index 76997704..de57d626 100644 --- a/tests/test_time.py +++ b/tests/test_time.py @@ -3,6 +3,7 @@ from __future__ import annotations import datetime as dt +import math import typing import pytest From a1ec3a743aa330c03e7c4501f29be679afad0095 Mon Sep 17 00:00:00 2001 From: Zo Bot Date: Wed, 1 Jul 2026 01:55:12 +0000 Subject: [PATCH 2/4] ordinal: use abs(value) for suffix so negative integers get the right -st, -nd, -rd, -th --- src/humanize/number.py | 3 ++- tests/test_number.py | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/humanize/number.py b/src/humanize/number.py index 2fb22c60..593b4086 100644 --- a/src/humanize/number.py +++ b/src/humanize/number.py @@ -109,7 +109,8 @@ def ordinal(value: NumberOrString, gender: str = "male") -> str: except (TypeError, ValueError): return str(value) gender = "male" if gender == "male" else "female" - digit = 0 if value % 100 in (11, 12, 13) else value % 10 + abs_value = abs(value) + digit = 0 if abs_value % 100 in (11, 12, 13) else abs_value % 10 return f"{value}{P_(f'{digit} ({gender})', _ORDINAL_SUFFIXES[digit])}" diff --git a/tests/test_number.py b/tests/test_number.py index 78639c32..204d1726 100644 --- a/tests/test_number.py +++ b/tests/test_number.py @@ -25,6 +25,16 @@ ("102", "102nd"), ("103", "103rd"), ("111", "111th"), + (-1, "-1st"), + (-2, "-2nd"), + (-3, "-3rd"), + (-4, "-4th"), + (-11, "-11th"), + (-12, "-12th"), + (-13, "-13th"), + (-21, "-21st"), + (-101, "-101st"), + (-111, "-111th"), ("something else", "something else"), (None, "None"), (math.nan, "NaN"), From db41b9fd3b062ed9c9901ce626439c6e467c13c5 Mon Sep 17 00:00:00 2001 From: Zo Bot Date: Thu, 2 Jul 2026 15:53:18 +0000 Subject: [PATCH 3/4] naturaldelta: include OverflowError in the int() guard so float('inf') returns unchanged MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The docstring says naturaldelta returns non-number input unchanged. int(float('inf')) raises OverflowError (not ValueError or TypeError), so the existing except (ValueError, TypeError) clause let it escape. The two new test cases (float('inf') and float('-inf')) fail on the pre-fix code with OverflowError and pass once OverflowError is added to the except tuple. The existing 'NaN' string case still returns "NaN" because str('NaN') is 'NaN' and float('NaN') → nan → int(nan) still raises ValueError which is still caught. --- src/humanize/time.py | 2 +- tests/test_time.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/humanize/time.py b/src/humanize/time.py index 4a07d528..41e56771 100644 --- a/src/humanize/time.py +++ b/src/humanize/time.py @@ -151,7 +151,7 @@ def naturaldelta( int(value) # Explicitly don't support string such as "NaN" or "inf" value = float(value) delta = dt.timedelta(seconds=value) - except (ValueError, TypeError): + except (ValueError, TypeError, OverflowError): return str(value) use_months = months diff --git a/tests/test_time.py b/tests/test_time.py index de57d626..c5263b38 100644 --- a/tests/test_time.py +++ b/tests/test_time.py @@ -5,6 +5,7 @@ import datetime as dt import math import typing +import math import pytest from freezegun import freeze_time @@ -129,6 +130,8 @@ def test_naturaldelta_nomonths(test_input: dt.timedelta, expected: str) -> None: (dt.timedelta(days=365), "a year"), (dt.timedelta(days=365 * 1_141), "1,141 years"), ("NaN", "NaN"), # Returns non-numbers unchanged. + (float("inf"), "inf"), + (float("-inf"), "-inf"), # largest possible timedelta (dt.timedelta(days=999_999_999), "2,739,726 years"), ], @@ -136,7 +139,8 @@ def test_naturaldelta_nomonths(test_input: dt.timedelta, expected: str) -> None: def test_naturaldelta(test_input: float | dt.timedelta, expected: str) -> None: assert humanize.naturaldelta(test_input) == expected if not isinstance(test_input, str): - assert humanize.naturaldelta(-test_input) == expected + if isinstance(test_input, dt.timedelta) or math.isfinite(test_input): + assert humanize.naturaldelta(-test_input) == expected @freeze_time(FROZEN_DATE) From 53a7c55b8c01cf080712c01fd1d06711005623f7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 7 Jul 2026 01:51:25 +0000 Subject: [PATCH 4/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_time.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_time.py b/tests/test_time.py index c5263b38..771e763e 100644 --- a/tests/test_time.py +++ b/tests/test_time.py @@ -5,7 +5,6 @@ import datetime as dt import math import typing -import math import pytest from freezegun import freeze_time