inflection review
inflection 0.5.1 ports the naming rules from Rails into a compact Python module. It converts identifiers among CamelCase, snake_case, dashed, title, parameter, and human-label forms, then handles common English singulars and plurals with ordered regex tables plus irregular and uncountable lists. This is convention code, not a language parser. Version 0.5.1 reorganized the distribution so the included `py.typed` marker is discovered by mypy. Our Python 3.12 check found no dependencies and a 0.05-second import.
inflection 0.5.1 installed as 1 MB with no dependencies and imported in 0.05 seconds in our sandbox. Use it for tested Rails-compatible identifiers; avoid it for open-ended English words or international slug generation.
We installed it
| Install | ✓ · 0.2s | 1 package on disk · 1 MB |
| Import | ✓ | import inflection in 0.05s · pure Python · py.typed · requires Python >=3.5 |
| Known vulns | 0 | (pip-audit) |
Answers from our run
Does inflection install cleanly?
Yes. In a fresh container with an empty cache, pip install inflection finished in 0.2s, leaving 1 package and 1 MB on disk. pip-audit reported no known vulnerabilities.
What does inflection need to run?
Python >=3.5, and nothing compiled: it is pure Python. In our run import inflection succeeded in 0.05s, and the package ships py.typed for type checkers.
inflection or inflect: which should you use?
inflect: Use it for a deeper English vocabulary, number words, articles, and more irregular nouns. inflection 0.5.1 installed as 1 MB with no dependencies and imported in 0.05 seconds in our sandbox.
When should you not use inflection?
The job is English morphology rather than application naming. Its Rails tables omit foot, tooth, goose, and criterion, while cow becomes kine.
Use it if
- Python models must reproduce Rails table or resource names without maintaining another inflection table.
- A generator needs dependency-free conversions among class names, underscored identifiers, dashed names, and labels.
- The relevant nouns come from a controlled domain list and every output can be pinned in tests.
- A typed pure-Python helper must continue running on interpreters as old as Python 3.5.
- The job is English morphology rather than application naming. Its Rails tables omit `foot`, `tooth`, `goose`, and `criterion`, while `cow` becomes `kine`.
- Slugs contain Cyrillic, CJK, or other non-Latin scripts. `transliterate()` discards characters that cannot survive ASCII encoding.
- You need reversible case conversion. Acronyms lose their original form, and the plural and singular rule lists are not mathematical inverses.
- Plugins must register rules through a supported isolated API. The available route mutates `PLURALS`, `SINGULARS`, or `UNCOUNTABLES` process-wide.
- Fresh releases are required. PyPI has stayed on 0.5.1 since August 2020 and GitHub's latest push is from August 2023.
- The application only changes one known identifier shape. A small local function may be easier to audit than another dormant dependency.
Setup reality
We installed inflection 0.5.1 without a cache on Python 3.12 in 0.2 seconds. Exactly 1 package and 1 MB remained, with 0 direct dependencies and 0 known pip-audit vulnerabilities. It is pure Python, MIT-licensed, and declares Python >=3.5. The package includes py.typed; import inflection completed in 0.05 seconds.
There is no service, credential, native compiler, or config file. The real setup is a fixture table of your names and expected results. tableize() first underscores and then pluralizes, so an odd noun rule can become a permanent database name. Guard empty input before camelize(value, False) because that branch reads character zero and raises IndexError for ''.
Plural and singular patterns are mutable module-level lists evaluated in order. A custom regex belongs ahead of broader built-ins, but inserting it changes behavior for every importer in that interpreter. For a few domain terms, keep an application dictionary beside the naming tests. That avoids a library silently changing another package's table calculation.
transliterate() uses NFKD normalization followed by ASCII encoding with errors ignored. Accents on many Latin letters survive as plain characters; scripts without ASCII decompositions may vanish. parameterize() inherits that loss and can return an empty slug. Use a cross-script transliterator for public names, and always reject an empty generated identifier. There is no cache beyond those shared rule tables.
Patterns
Translate between identifier conventions convert-case
import inflection
inflection.underscore('HTTPResponse') # 'http_response'
inflection.camelize('device_type') # 'DeviceType'
inflection.camelize('device_type', False) # 'deviceType'
inflection.dasherize('device_type') # 'device-type'`underscore()` discards acronym boundaries, so a later camel conversion cannot reconstruct the original `HTTPResponse` spelling.
Handle an empty lower-camel input guard-empty-camelize
import inflection
def lower_camel(value: str) -> str:
if value == '':
return value
return inflection.camelize(value, False)Version 0.5.1 indexes character zero in lower-camel mode; passing an empty string raises `IndexError`.
Walk nested payload keys explicitly map-json-keys
import inflection
def camel_keys(value):
if isinstance(value, dict):
return {inflection.camelize(k, False): camel_keys(v) for k, v in value.items()}
if isinstance(value, list):
return [camel_keys(v) for v in value]
return valueinflection only accepts one string. If this recursion is the whole feature, pyhumps already covers dictionaries and lists.
Derive a Rails-compatible table name derive-table-name
import inflection
class RawScaledScorer:
pass
table = inflection.tableize(RawScaledScorer.__name__)
assert table == 'raw_scaled_scorers'`tableize()` composes case conversion with pluralization. Assert the final database identifier before generating a migration.
Run known nouns through the Rails tables pluralize-noun
import inflection
inflection.pluralize('analysis') # 'analyses'
inflection.pluralize('child') # 'children'
inflection.pluralize('sheep') # 'sheep'
inflection.singularize('indices') # 'index'These examples are present in the rule vocabulary. Add fixtures for every domain noun instead of extrapolating to arbitrary English.
Prefer a local irregular-word map override-irregulars
import inflection
PLURALS = {
'foot': 'feet',
'goose': 'geese',
'criterion': 'criteria',
}
def plural(word: str) -> str:
return PLURALS.get(word.lower(), inflection.pluralize(word))An application dictionary is isolated and reviewable; changing inflection's globals affects every package in the interpreter.
Patch the global regex order when unavoidable register-global-rule
import inflection
inflection.PLURALS.insert(0, (r'(?i)(f)oot$', r'\1eet'))
inflection.SINGULARS.insert(0, (r'(?i)(f)eet$', r'\1oot'))Earlier regexes win. This mutates undocumented shared lists, so insert before broad rules and confine the change to application startup.
Generate a label from an internal field humanize-field
import inflection
inflection.humanize('employee_salary') # 'Employee salary'
inflection.humanize('author_id') # 'Author'
inflection.titleize('order_status') # 'Order Status'`humanize()` strips a terminal `_id`. Use an explicit label when those characters are meaningful rather than a database suffix.
Parameterize text that already transliterates safely make-url-slug
import inflection
inflection.parameterize('Donald E. Knuth') # 'donald-e-knuth'
inflection.parameterize('Hello, World!', '_') # 'hello_world'Non-Latin input may collapse to an empty result during ASCII conversion. Reject empty output before using it as a URL key.
Reduce compatible Latin characters to ASCII transliterate-latin
import inflection
plain = inflection.transliterate('cafe')
slug = inflection.parameterize(plain)Characters without an ASCII decomposition are discarded. Use Unidecode or another transliterator for readable cross-script approximations.
Append an English ordinal suffix format-ordinal
import inflection
inflection.ordinal(22) # 'nd'
inflection.ordinalize(22) # '22nd'
inflection.ordinalize(-3) # '-3rd'`ordinal()` returns the suffix alone; `ordinalize()` includes the number. Version 0.5.1 has no locale parameter.
Pin model-to-table names before migration test-schema-words
import pytest
import inflection
@pytest.mark.parametrize(('model', 'table'), [
('Person', 'people'),
('Category', 'categories'),
('Analysis', 'analyses'),
])
def test_table_name(model, table):
assert inflection.tableize(model) == tableA fixture exposes a domain noun that Rails rules mishandle before its result is stored as a schema identifier.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| inflect | PyPI | Use it for a deeper English vocabulary, number words, articles, and more irregular nouns. |
| pyhumps | PyPI | Use it when case changes must walk nested lists and dictionaries automatically. |
| python-slugify | PyPI | Use it for public slugs that need Unicode choices, replacements, length controls, and stop words. |
| Unidecode | PyPI | Use it when non-Latin scripts should become approximate readable ASCII rather than disappear. |
More utils guides
lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

