From 9326b16b01cce8a6fbad68b94cede4c31c19516c Mon Sep 17 00:00:00 2001 From: Zo Bot Date: Wed, 1 Jul 2026 01:55:12 +0000 Subject: [PATCH 1/3] 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 2fb22c6..593b408 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 78639c3..204d172 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 ffdc079f0d547c0c8fd01e96747b1f99228d4082 Mon Sep 17 00:00:00 2001 From: Zo Bot Date: Thu, 2 Jul 2026 15:53:18 +0000 Subject: [PATCH 2/3] 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 4a07d52..41e5677 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 7699770..323dcac 100644 --- a/tests/test_time.py +++ b/tests/test_time.py @@ -4,6 +4,7 @@ import datetime as dt import typing +import math import pytest from freezegun import freeze_time @@ -128,6 +129,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"), ], @@ -135,7 +138,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 6eafe65d51f4768b1a426f4960913c9b79c45c5d 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 3/3] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_time.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_time.py b/tests/test_time.py index 323dcac..771e763 100644 --- a/tests/test_time.py +++ b/tests/test_time.py @@ -3,8 +3,8 @@ from __future__ import annotations import datetime as dt -import typing import math +import typing import pytest from freezegun import freeze_time