roman
Tiny, dependency-free Python library and CLI for converting between integers and Roman numerals.
Repository Health
Technical Analysis
roman is a small, focused Python package that converts arabic integers to Roman numeral strings and back again. It ships both an importable API (toRoman/fromRoman) for use inside application code and a standalone roman command-line tool for one-off conversions in a terminal, sharing the exact same conversion logic underneath.
Originally written by Mark Pilgrim for the Dive Into Python tutorial and now maintained by the Zope Foundation, the package has no runtime dependencies, ships type hints and a py.typed marker, and enforces 100% branch test coverage — making it a reliable drop-in utility anywhere a project needs Roman numeral formatting or parsing.
What You Get
- A pure Python module with no runtime dependencies
- toRoman() and fromRoman() functions with full type hints
- A roman CLI command installed automatically via project.scripts
- A typed exception hierarchy (RomanError, OutOfRangeError, NotIntegerError, InvalidRomanNumeralError) for precise error handling
- A py.typed marker for downstream static type checking
Common Use Cases
- Formatting page numbers, chapter numbers, or outline levels as Roman numerals in generated documents
- Parsing Roman numeral input from users or legacy data files back into integers
- Converting to Roman numerals via the roman CLI for quick, ad-hoc terminal conversions
- Validating whether a string is a well-formed Roman numeral before processing it further
Under The Hood
Architecture
The entire library lives in a single module, src/roman/__init__.py: a custom exception hierarchy (RomanError and its subclasses OutOfRangeError, NotIntegerError, InvalidRomanNumeralError), a module-level romanNumeralMap tuple mapping numeral strings to integer values in descending order, the two pure conversion functions toRoman/fromRoman, and a thin argparse-based parse_args/main pair wired up as the roman console script. There is no layering or dependency injection because none is needed — both public functions iterate the same shared romanNumeralMap, so it functions as the one abstraction the whole module depends on, and the CLI is a pass-through wrapper rather than a separate concern.
Tech Stack
Pure Python 3.10+ with zero runtime dependencies, using only the standard library (argparse, re, sys). Packaged with a setuptools-based pyproject.toml (generated from the Zope Foundation’s shared zope.meta pure-python template), tested across versions with tox, and exercised in CI via GitHub Actions with Coveralls reporting. The CLI entry point is declared under project.scripts rather than a bespoke launcher.
Code Quality
A single table-driven test module (src/tests.py) built on unittest covers both conversion directions, all three custom error types, CLI argument parsing, and main() including case-insensitive reverse conversion. The project enforces 100% branch coverage via pyproject.toml’s coverage configuration, ships full type hints on its public functions, and includes a py.typed marker for downstream type checkers. A pre-commit configuration keeps style consistent across contributors.
API Design
The public surface is intentionally tiny: toRoman and fromRoman, plus a CLI that mirrors them 1:1 with a -r/--reverse flag. Usage requires no setup, configuration, or client objects — just import roman and call a function. Errors are raised as specific, catchable exception types rather than generic ValueError, and fromRoman case-normalizes input automatically. The one legacy wart is the historic camelCase naming (toRoman/fromRoman) inherited from the package’s 2001 origin, which departs from modern PEP 8 conventions but has remained stable given the package’s long-standing, low-churn API.