humanize

Converts numbers, dates, times, and file sizes into human-readable text for Python apps.

Library
PyPI
v4.16.0
750stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
84/100Excellent
Development Activity88
Maintenance88
Community64
Maturity56
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
87/100Excellent
Architecture80
Code Quality92
Innovation85
Learning Curve90

humanize solves a small but recurring UI problem: turning precise machine values into the approximate, human-friendly phrasing people actually read. Its modules cover natural time (naturaltime, naturaldelta, naturalday, naturaldate, precisedelta), file sizes (naturalsize), numbers (intcomma, intword, ordinal, apnumber, fractional, scientific, metric), and lists (natural_list), each exposing a small, predictable function rather than a class-based API.

Originally created by Jason Moiron in 2010 and now maintained by the python-humanize organization, the library has zero runtime dependencies, ships full type hints, and includes translations for more than three dozen locales that can be swapped at runtime with humanize.i18n.activate(). It’s a common building block behind relative timestamps, file-size displays, and readable number formatting across Python web apps and CLIs.

What You Get

  • Ready-made functions for natural time, date, file size, and number formatting
  • Localized output for 36+ languages via a lightweight gettext-based i18n layer
  • Full type hints (py.typed) in a strict-mypy-checked codebase
  • A precise timedelta formatter (precisedelta) with configurable minimum unit and suppression
  • Zero runtime dependencies beyond the Python standard library

Common Use Cases

  • Rendering ‘time ago’ timestamps in feeds, comments, or notifications
  • Displaying human-readable file sizes in upload/download UIs
  • Formatting large numbers for dashboards and reports
  • Producing locale-aware duration and count strings for internationalized apps
  • Generating ordinal labels (1st, 2nd, 3rd) for rankings or lists

Under The Hood

Architecture The library is organized as flat, self-contained modules — time.py, number.py, filesize.py, lists.py, and i18n.py — each exposing plain functions rather than classes (the one exception, Unit, is a small ordering-aware Enum in time.py). __init__.py re-exports the public API and declares __lazy_modules__ so submodules are only imported on first use, keeping import humanize cheap. time.py and number.py depend on i18n.py for gettext-backed translation, but the modules otherwise have minimal coupling, so a change to one formatter (e.g. naturalsize) has no ripple effect on the others.

Tech Stack Pure Python 3.10+ with no runtime dependencies. The build uses hatchling with hatch-vcs for git-tag-based versioning. Test/dev dependencies (declared as an optional tests extra) are pytest 9+, freezegun for deterministic time-based tests, and pytest-benchmark/pytest-codspeed for performance regression tracking. Ruff (with a wide rule set including pydocstyle, pyupgrade, and flake8-comprehensions) and strict mypy handle linting and type checking, mkdocs builds the docs site, and tox coordinates multi-version test matrices (CPython 3.10-3.15, PyPy, free-threaded builds) across GitHub Actions workflows for lint, test, docs, benchmark, and release.

Code Quality Test coverage is extensive relative to the library’s size: test_time.py alone runs 873 lines against time.py’s 702, with further dedicated suites for numbers, i18n (336 lines), file sizes, and lists. freezegun pins ‘now’ for deterministic relative-time assertions, and pytest-benchmark/codspeed guard against performance regressions. CI enforces ruff lint, strict mypy, and the full test matrix on every change, and public functions carry Google-style docstrings with runnable pycon examples.

API Design The public surface is intentionally flat and function-based: import humanize then call humanize.naturaltime(...) or humanize.naturalsize(...) directly, with no classes to instantiate and sensible defaults (naturalsize defaults to SI decimal units, precisedelta’s minimum unit defaults to seconds). Locale switching is a single explicit, reversible call (i18n.activate() / deactivate()), and lazy module loading keeps startup cost low without requiring the caller to do anything differently. Getting a first human-readable string out of the library takes one import and one function call.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search