cron-descriptor
A Python library that converts cron expressions into plain-English, localized descriptions.
Repository Health
Technical Analysis
cron-descriptor parses standard cron expressions and turns them into human-readable sentences, so a schedule like */10 * * * * becomes “Every 10 minutes” instead of a string only a scheduler can love. It supports 5-, 6-, and 7-field expressions (with optional seconds and year fields), all the special characters cron authors rely on (* / , - ? L W #), and configurable output casing (Sentence, Title, Lower).
The library is a Python port of the well-known .NET cron-expression-descriptor project, and it carries that project’s most distinctive feature forward: built-in localization for roughly 31 languages via gettext .mo catalogs, so the same expression can be described in English, German, Japanese, or Russian without any extra work from the caller. It’s a small, dependency-light utility aimed at admin dashboards, cron-job management tools, and any UI that needs to explain a schedule to a non-technical user.
What You Get
get_description()helper - a one-line function that takes a cron string and returns its English (or locale-specific) description.ExpressionDescriptorclass - full control over casing type, verbosity, day-of-week indexing, 12/24-hour format, and locale via anOptionsobject or keyword arguments.- 5/6/7-field expression support - handles standard 5-field cron as well as extended forms with seconds and/or a year field.
- ~31 bundled locales - human-readable output in English, German, French, Spanish, Japanese, Chinese (Simplified & Traditional), Russian, Hebrew, Arabic-adjacent locales, and more, via gettext
.mofiles. - Typed exception hierarchy -
FormatError,MissingFieldError, andWrongArgumentErrorgive callers specific, catchable failure modes instead of bare exceptions. - CLI entry point (
__main__.py) - the package can be invoked directly to describe an expression from the command line.
Common Use Cases
- Cron-job management UIs - showing a plain-English summary of a schedule next to the raw cron string so non-technical users understand when a job runs.
- Admin dashboards for schedulers - explaining Celery beat, Airflow, or Kubernetes CronJob schedules to operators without requiring them to read cron syntax.
- Configuration validation tooling - using the bundled
ExpressionValidatorto catch malformed cron expressions before they’re saved. - Localized SaaS products - generating schedule descriptions in the end user’s own language via the built-in locale catalogs, rather than hand-rolling translations.
Under The Hood
Architecture
cron-descriptor is a small layered pipeline rather than a framework: ExpressionDescriptor (cron_descriptor/ExpressionDescriptor.py) is the public entry point, which on construction hands the raw expression string to ExpressionParser (ExpressionParser.py) to split it into positional parts (seconds, minute, hour, day-of-month, month, day-of-week, and optional year), validated along the way via ExpressionValidator.py. get_description() then walks those parsed parts and assembles per-field sentence fragments through StringBuilder, translating each fragment through a GetText wrapper around Python’s gettext module, which loads a locale-specific .mo catalog from cron_descriptor/locale/. Configuration (casing, verbosity, locale, 12/24-hour format) flows through a single Options dataclass-like object passed at construction or supplied as keyword arguments, which are validated with hasattr/setattr against Options and rejected via WrongArgumentError if unknown. There’s no dependency-injection container or plugin system; the four collaborators (ExpressionParser, ExpressionValidator, GetText, StringBuilder) are plain constructor-injected objects. Because ExpressionDescriptor’s field-description methods index into _expression_parts by position, changing ExpressionParser’s output ordering would be the one change most likely to break every downstream description method at once.
Tech Stack
Pure Python (99% of the codebase per GitHub’s language breakdown), targeting Python 3.9 through 3.14 with from __future__ import annotations used throughout for forward-referencing type hints. The only runtime dependency is typing_extensions (for Unpack/TypedDict kwargs typing on older Python versions); dev/test dependencies are ruff, mypy (run in strict mode per pyproject.toml), polib, and pytest. Packaging uses a standard pyproject.toml with setuptools as the build backend, dynamic versioning sourced from cron_descriptor.__version__, and .mo locale files included as package data. Translation source files are .po/.mo pairs managed with GNU Gettext tooling (xgettext, msgfmt), with Poedit recommended for contributors adding new languages.
Code Quality
The project has a real, matrix-tested CI pipeline (.github/workflows/python-test.yml) running on Python 3.9–3.14 (including prereleases) via a code-check.sh script that chains ruff, mypy --strict, and pytest. The tests/ directory has nine focused test modules (test_api.py, test_casing.py, test_exceptions.py, test_formats.py — 392 lines of expression/description fixtures, test_import.py, test_locale.py, test_validator.py, test_verbosity.py), indicating deliberate coverage of casing behavior, exception paths, locale loading, and format edge cases rather than a token smoke test. pyproject.toml enables ruff’s full ALL rule set (with a short, justified ignore list) and mypy strict mode across both cron_descriptor and tests, and a pre-commit hook (code-check.sh symlinked into .git/hooks/pre-commit) is offered to contributors. Exceptions are typed and explicit (FormatError, MissingFieldError, WrongArgumentError) rather than generic.
What Makes It Unique The standout technical choice is the breadth of first-class localization: rather than hard-coding English sentence templates, every field description is routed through gettext, and the project ships and maintains translation catalogs for roughly 31 languages contributed by a large community of translators — a level of i18n investment that’s unusual for a narrowly-scoped utility library. Combined with strict typing (mypy strict, full ruff rule set) and support for the less-common 6- and 7-field cron variants (seconds and year), it reads as a mature, well-governed port of the original .NET project rather than a quick script.
Used by 4 apps in this directory
Apache Airflow
Data Engineering
Define, schedule, and monitor complex data workflows as Python code — with a powerful UI, 80+ provider integrations, and battle-tested scalability across thousands of production deployments.
Cronboard
Developer Tools · Devops
A keyboard-driven terminal dashboard for managing cron jobs on local machines and remote servers via SSH.
Khoj
AI Assistants · Knowledge Management · Productivity
A self-hostable AI second brain that chats with your documents, searches the web, builds custom agents, and runs entirely on your own LLM.
SWIRL
Search · Databases · Data Engineering
Federated AI search and RAG across 100+ enterprise sources—no data extraction, no vector database required.