inflect plurals, ordinals, a/an articles and number-to-words for UI strings: working versions (tested 2026-10-16)
Build count-aware English labels with inflect: singular for one, irregular plurals, 11/12/13-safe ordinals, sound-based articles and spelled-out numbers.
passed6 passed · 0 failed2026-10-16 21:56 UTC- Status
- passed
- Last passed
- 2026-10-16 21:56 UTC
- Tests
- 6 / 6
- Language
- Python
- Runtime
- Python 3.13.16
pinned versions2
inflect@7.5.0pytest@9.1.1
run it
uv venv -q .venv && uv pip install -q --python .venv/bin/python -r requirements.txt .venv/bin/python -m pytest -q
test environment
Python 3.13.16 linux 6.17.0-1022-azure x64 runner: github-actions 38972656245
The code
Exactly the files that passed. Your agent can pull them with get_recipe("inflect-plural-ordinal") (install), or see them on GitHub.
requirements.txt
inflect==7.5.0 pytest==9.1.1
ui.py
import inflect
p = inflect.engine()
def count_label(noun, count):
# plural_noun returns the singular for count == 1, plural otherwise (0 included)
return f"{count} {p.plural_noun(noun, count)}"
def ordinal(n):
return p.ordinal(n)
def ordinal_words(n):
# inflect 7.x number_to_words has no to="ordinal"; wrap the ordinal form instead
return p.number_to_words(p.ordinal(n))
def with_article(noun):
# a/an is chosen from the leading sound, not the leading letter
return p.a(noun)
def spell_number(n, andword="and"):
return p.number_to_words(n, andword=andword)
tests/test_ui.py
from ui import count_label, ordinal, ordinal_words, spell_number, with_article
def test_count_label_keeps_singular_for_one():
assert count_label("item", 1) == "1 item"
assert count_label("item", 2) == "2 items"
assert count_label("item", 0) == "0 items"
assert count_label("sheep", 3) == "3 sheep"
def test_irregular_plurals():
assert count_label("child", 2) == "2 children"
assert count_label("person", 2) == "2 people"
assert count_label("box", 2) == "2 boxes"
def test_ordinal_teens_do_not_take_st():
assert ordinal(1) == "1st"
assert ordinal(2) == "2nd"
assert ordinal(3) == "3rd"
assert ordinal(11) == "11th"
assert ordinal(12) == "12th"
assert ordinal(13) == "13th"
assert ordinal(112) == "112th"
def test_ordinal_words_wrap_the_ordinal_form():
assert ordinal_words(1) == "first"
assert ordinal_words(21) == "twenty-first"
assert ordinal_words(8) == "eighth"
def test_article_follows_sound_not_spelling():
assert with_article("banana") == "a banana"
assert with_article("hour") == "an hour"
assert with_article("unicorn") == "a unicorn"
assert with_article("MBA") == "an MBA"
def test_spell_number_andword_control():
assert spell_number(1234) == "one thousand, two hundred and thirty-four"
assert spell_number(123, andword="") == "one hundred twenty-three"
assert spell_number(0) == "zero"
assert spell_number(3.5) == "three point five"
pytest.ini
[pytest] pythonpath = .
Connect to ProvenPin
Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.
terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp
~/.cursor/mcp.json
{ "mcpServers": { "provenpin": { "url": "https://mcp.provenpin.com/mcp" } } }.vscode/mcp.json
{ "servers": { "provenpin": { "type": "http", "url": "https://mcp.provenpin.com/mcp" } } }~/.codeium/windsurf/mcp_config.json
{ "mcpServers": { "provenpin": { "serverUrl": "https://mcp.provenpin.com/mcp" } } }MCP settings
{ "mcpServers": { "provenpin": { "type": "streamableHttp", "url": "https://mcp.provenpin.com/mcp" } } }Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.