Skip to content

Fix ordinal() suffix for negative integers - #411

Closed
zixuniaowu wants to merge 1 commit into
python-humanize:mainfrom
zixuniaowu:fix/negative-ordinal-suffix
Closed

zixuniaowu wants to merge 1 commit into
python-humanize:mainfrom
zixuniaowu:fix/negative-ordinal-suffix

Conversation

@zixuniaowu

Copy link
Copy Markdown

Problem

humanize.ordinal() returns the wrong suffix for every negative integer:

>>> ordinal(-1)
'-1th'   # should be '-1st'
>>> ordinal(-2)
'-2th'   # should be '-2nd'
>>> ordinal(-21)
'-21th'  # should be '-21st'

The docstring documents "Works for any integer", and negative inputs are clearly within the promised domain (invalid types fall back to str(value)), so the behavior contradicts the contract.

Root cause

The suffix digit is computed from value % 100 / value % 10. Python's % maps negative operands to non-negative residues (-1 % 10 == 9), so all negative numbers land in the "th" digit bucket. The -11/-12/-13/-111/-112/-113 inputs are "accidentally correct" and mask the defect.

Fix

Normalize the magnitude before computing the digit; the sign is still applied by the outer f-string:

magnitude = abs(value)
digit = 0 if magnitude % 100 in (11, 12, 13) else magnitude % 10

Also adds two doctest examples plus 12 parametrized negative-integer tests (covering the five genuinely wrong values -1/-2/-3/-21/-101 and the "accidentally correct" families that previously hid the bug).

Verification

  • Pristine base (392aef7) with only the new tests: 5 failed, 25 passed — proves the defect exists upstream, not introduced by this change
  • After the fix: 756 passed, 112 skipped (full suite), pytest --doctest-modules src/humanize/number.py: 8 passed (Python 3.12)

Base for this branch: 392aef7 (current main at time of branching, 2026-09-16).

ordinal(-1) returned '-1th' instead of '-1st' (and similarly for -2,
-3, -21, -101, ...): the suffix digit was computed from value % 100 /
value % 10, and Python's modulo maps negative operands to negative-free
results (-1 % 10 == 9), so every negative number got 'th'.

Compute the suffix from the absolute magnitude instead. Adds negative
parametrized cases and doctest examples.
@hugovk

hugovk commented Sep 23, 2026

Copy link
Copy Markdown
Member

Duplicate of #405 and #321 and lots more.

Check for duplicates next time.

@hugovk hugovk closed this Sep 23, 2026
@zixuniaowu

This comment was marked as low quality.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants