This release is a pre-release and may not be stable for production use.
Romcal
A Python library for calculating Catholic liturgical dates and generating liturgical calendars. Powered by Rust via UniFFI bindings.
For the Rust library, see romcal. For command-line usage, see the CLI documentation.
Installation
pip install romcal
Or with uv:
uv add romcal
Note: Pre-built wheels are available for Python 3.11-3.14 on Linux (x86_64, aarch64, musl), macOS (Intel, Apple Silicon), and Windows (x64, ARM64). For other platforms, Rust is required to build from source.
Quick Start
from romcal import Romcal
# Create a default instance
romcal = Romcal()
# Get a specific liturgical date
easter = romcal.get_date("easter_sunday", 2026)
print(easter) # "2026-04-05"
# Generate the liturgical calendar for year 2026
calendar = romcal.liturgical_calendar(2026)
# Access a specific date
christmas = calendar.get("2026-12-25")
if christmas:
print(christmas[0]["fullname"]) # "The Nativity of the Lord"
Configuration
Using Keyword Arguments
from romcal import CalendarContext, Romcal
# With calendar and locale
romcal1 = Romcal(calendar="france", locale="fr")
# With full configuration
romcal2 = Romcal(
calendar="france",
locale="fr",
context=CalendarContext.LITURGICAL,
epiphany_on_sunday=True,
ascension_on_sunday=True,
corpus_christi_on_sunday=True,
)
Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
calendar |
str |
"general_roman" |
Calendar ID (e.g., "france", "united_states") |
locale |
str |
"en" |
Locale code (e.g., "fr", "es") |
context |
CalendarContext |
GREGORIAN |
GREGORIAN (Jan-Dec) or LITURGICAL (Advent-Advent) |
epiphany_on_sunday |
bool |
False |
Celebrate Epiphany on Sunday (Jan 2-8) instead of Jan 6 |
ascension_on_sunday |
bool |
False |
Celebrate Ascension on Sunday instead of Thursday |
corpus_christi_on_sunday |
bool |
True |
Celebrate Corpus Christi on Sunday instead of Thursday |
easter_calculation_type |
EasterCalculationType |
GREGORIAN |
GREGORIAN or JULIAN Easter calculation |
calendar_definitions |
list |
None |
List of calendar definitions (Pydantic models or dicts) |
resources |
list |
None |
List of locale resources (Pydantic models or dicts) |
Loading Calendar Data
Without loading data, only the Proper of Time is available. To include the General Roman Calendar, particular calendars, and localized names, you can either use bundled data or load from files.
Using bundled data (recommended):
from romcal import (
Romcal,
get_bundled_calendar_definitions,
get_bundled_resources,
)
romcal = Romcal(
calendar="france",
locale="fr",
calendar_definitions=get_bundled_calendar_definitions(),
resources=get_bundled_resources(),
)
Loading from files:
import json
from pathlib import Path
from romcal import Romcal
DATA_DIR = Path("data")
def load_calendar_definitions():
"""Load all calendar definitions from the data folder."""
definitions = []
for json_file in (DATA_DIR / "definitions").rglob("*.json"):
with open(json_file) as f:
definitions.append(json.load(f))
return definitions
def load_resources():
"""Load all resources from the data folder."""
resources_dir = DATA_DIR / "resources"
resources = []
# Group files by locale
files_by_locale = {}
for json_file in resources_dir.rglob("*.json"):
locale = json_file.parent.name
files_by_locale.setdefault(locale, []).append(json_file)
# Merge files for each locale
for locale, locale_files in files_by_locale.items():
metadata = None
entities = {}
for file in locale_files:
with open(file) as f:
content = json.load(f)
if file.name == "meta.json":
metadata = content.get("metadata")
elif file.name.startswith("entities.") and "entities" in content:
entities.update(content["entities"])
resources.append({
"locale": locale,
"metadata": metadata,
"entities": entities if entities else None,
})
return resources
# Create instance with loaded data (dicts are accepted)
romcal = Romcal(
calendar="france",
locale="fr",
calendar_definitions=load_calendar_definitions(),
resources=load_resources(),
)
API
Romcal()
Creates a new Romcal instance.
from romcal import Romcal
# Default configuration
romcal1 = Romcal()
# With calendar and locale
romcal2 = Romcal(calendar="france", locale="fr")
# With partial configuration
romcal3 = Romcal(
calendar="france",
locale="fr",
epiphany_on_sunday=True,
)
Romcal Instance
liturgical_calendar(year)
Generate the complete liturgical calendar for a given year.
calendar = romcal.liturgical_calendar(2026)
# calendar is dict[str, list[dict]]
# Keys are dates in "YYYY-MM-DD" format
for date, days in calendar.items():
for day in days:
print(f"{date}: {day['fullname']} ({day['rank']})")
mass_calendar(year)
Generate a mass-centric view of the calendar organized by civil date and mass time.
mass_calendar = romcal.mass_calendar(2026)
# mass_calendar is dict[str, list[dict]]
# Evening masses appear on the previous civil day
easter_vigil_day = mass_calendar.get("2026-04-04")
if easter_vigil_day:
vigil = next((m for m in easter_vigil_day if m["mass_time"] == "EASTER_VIGIL"), None)
if vigil:
print(vigil["liturgical_date"]) # "2026-04-05"
get_date(id, year)
Get a liturgical date by its ID.
easter = romcal.get_date("easter_sunday", 2026) # "2026-04-05"
ash_wed = romcal.get_date("ash_wednesday", 2026) # "2026-02-18"
pentecost = romcal.get_date("pentecost_sunday", 2026) # "2026-05-24"
christmas = romcal.get_date("christmas", 2026) # "2026-12-25"
Any date ID from the liturgical calendar can be used (e.g., easter_sunday, christmas, ordinary_time_5_monday).
Properties
Access the resolved configuration:
print(romcal.calendar) # "france"
print(romcal.locale) # "fr"
print(romcal.epiphany_on_sunday) # True
print(romcal.ascension_on_sunday) # False
print(romcal.corpus_christi_on_sunday) # True
print(romcal.easter_calculation_type) # "GREGORIAN"
print(romcal.context) # "GREGORIAN"
Key Types
For detailed documentation on liturgical types (seasons, ranks, precedence, colors, cycles, mass times), see the romcal documentation.
Error Handling
All operations may raise RomcalError:
from romcal import Romcal, RomcalError
try:
romcal = Romcal()
# Year must be >= 1583 (Gregorian calendar adoption)
calendar = romcal.liturgical_calendar(1500)
except RomcalError as e:
print(f"Romcal error: {e}")
Development
Requirements
Setup
cd bindings/python
# Create virtual environment
uv venv
# Install build tools
uv pip install maturin uniffi-bindgen
# Build and install the native extension
uv run maturin develop
# Install dev dependencies (pytest, ruff, etc.)
uv pip install pytest taskipy ruff mypy
Available Tasks
Using taskipy:
task build # maturin build --release
task develop # maturin develop
task generate-types # Generate Pydantic types from JSON schema
task test # pytest tests/ -v
task test-run # pytest tests/ (without verbose)
task format # ruff format .
task format-check # ruff format --check .
task lint # ruff check .
task lint-fix # ruff check --fix .
task typecheck # mypy src/
Testing
task test # Run tests with verbose output
task test-run # Run tests once
Project Structure
bindings/python/
├── src/
│ └── romcal/
│ ├── __init__.py # Main entry point, API wrapper
│ ├── types.py # Generated types from JSON schema (Pydantic)
│ └── _uniffi/ # Generated UniFFI bindings
├── tests/
│ ├── conftest.py # Pytest fixtures (data loading)
│ ├── test_config.py # Configuration tests
│ ├── test_calendar.py # Calendar generation tests
│ └── test_data_loading.py # Data loading tests
├── examples/
│ └── basic_usage.py # Usage example with data loading
└── pyproject.toml # Project configuration
Running Examples
# Basic usage example (loads data from /data folder)
python examples/basic_usage.py
Regenerating Types
If you modify Rust types in core/src/, you need to regenerate types.py:
uv run task generate-types
This uses datamodel-codegen to generate Pydantic models from JSON schema.
Related
- romcal - Main Romcal project
- romcal - Core Rust library
- romcal-cli - Command-line interface
- romcal (TypeScript) - TypeScript/JavaScript binding
License
Apache License 2.0. See LICENSE for details.
Metadata
Release files for romcal 4.0.0b6
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| romcal-4.0.0b6.tar.gz | 194.0 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| romcal-4.0.0b6-py3-none-win_arm64.whl | Python 3 | none | Windows ARM64 | Details |
| romcal-4.0.0b6-py3-none-win_amd64.whl | Python 3 | none | Windows x86-64 | Details |
| romcal-4.0.0b6-py3-none-musllinux_1_2_x86_64.whl | Python 3 | none | Linux musl 1.2+ x86-64 | Details |
| romcal-4.0.0b6-py3-none-musllinux_1_2_aarch64.whl | Python 3 | none | Linux musl 1.2+ ARM64 | Details |
| romcal-4.0.0b6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | Python 3 | none | Linux glibc 2.17+ x86-64 | Details |
| romcal-4.0.0b6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | Python 3 | none | Linux glibc 2.17+ ARM64 | Details |
| romcal-4.0.0b6-py3-none-macosx_11_0_arm64.whl | Python 3 | none | macOS 11.0+ ARM64 | Details |
| romcal-4.0.0b6-py3-none-macosx_10_12_x86_64.whl | Python 3 | none | macOS 10.12+ x86-64 | Details |
Total release size: 10.4 MB
Release files / romcal-4.0.0b6.tar.gz
| Download URL | romcal-4.0.0b6.tar.gz |
|---|---|
| Size | 194.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3d0d5b3a32c92b9d7ceddf2d38afcb0e34e2411bb24cc81ccd2b330200199a4e
|
|
BLAKE2b-256 checksum How to use checksums |
6f0406b6db8f39d02dea3231c9d7f4538e59a20a43ce4908f467135d520215c4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jan 27, 2026.
Transparency logRelease files / romcal-4.0.0b6-py3-none-win_arm64.whl
| Download URL | romcal-4.0.0b6-py3-none-win_arm64.whl |
|---|---|
| Size | 1.1 MB |
| Tags | Python 3 Windows ARM64 |
|
SHA-256 checksum How to use checksums |
88e5f356b4120f8ab843a1c0abfac59d1355765bc47501d473aea4da89bf0302
|
|
BLAKE2b-256 checksum How to use checksums |
72a291163c05f98e0a74a357fa45e23152ed87d8b13db2a9d5d94adaa706e59b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jan 27, 2026.
Transparency logRelease files / romcal-4.0.0b6-py3-none-win_amd64.whl
| Download URL | romcal-4.0.0b6-py3-none-win_amd64.whl |
|---|---|
| Size | 1.1 MB |
| Tags | Python 3 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
0b6352dee0e27425bdcc9224b42d79c56aa759692ca521b0d3ed9cddb9feeb96
|
|
BLAKE2b-256 checksum How to use checksums |
7df337581b4800b3248f1899815ac9c7b5494fd5eb3b884d155dec7ea1d6ce18
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jan 27, 2026.
Transparency logRelease files / romcal-4.0.0b6-py3-none-musllinux_1_2_x86_64.whl
| Download URL | romcal-4.0.0b6-py3-none-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 1.5 MB |
| Tags | Linux musl 1.2+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
a693b46e9a6c5d0ab1dc5e65a9ed8ddfc2f972300da11b600f0d7ed8d6e18f72
|
|
BLAKE2b-256 checksum How to use checksums |
db6f07ef1fc6baffd8dd61b08d6bb2ddab63e9e3210fd12fc1e60d57b41880c4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jan 27, 2026.
Transparency logRelease files / romcal-4.0.0b6-py3-none-musllinux_1_2_aarch64.whl
| Download URL | romcal-4.0.0b6-py3-none-musllinux_1_2_aarch64.whl |
|---|---|
| Size | 1.5 MB |
| Tags | Linux musl 1.2+ ARM64 Python 3 |
|
SHA-256 checksum How to use checksums |
21a2536529c56004f237828f6f85aa22a68fa9da65b407d72cb3f94bb16c91b1
|
|
BLAKE2b-256 checksum How to use checksums |
174b73ea37da40fcce20ce116c4044a1a69c0f92c926d33fdf835e93d78650d2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jan 27, 2026.
Transparency logRelease files / romcal-4.0.0b6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | romcal-4.0.0b6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 1.3 MB |
| Tags | Linux glibc 2.17+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
3c697e1e8ebbc4275fde01394094c48494a5dcfd12f2cb1cf746052c3aa41ae5
|
|
BLAKE2b-256 checksum How to use checksums |
b74f0418a218fbd5b71bd5230136a66612ddd6247b7969fd7d0b9045fb0f0c85
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jan 27, 2026.
Transparency logRelease files / romcal-4.0.0b6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | romcal-4.0.0b6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 1.3 MB |
| Tags | Linux glibc 2.17+ ARM64 Python 3 |
|
SHA-256 checksum How to use checksums |
5e5280e74cabadab7780a5bba9b8b12e160cdf025505d8a2406250605da7f7d2
|
|
BLAKE2b-256 checksum How to use checksums |
21ba72a84aebccb4ebd3590b6d23e3a182308d106246307668f11061aca8bfaa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jan 27, 2026.
Transparency logRelease files / romcal-4.0.0b6-py3-none-macosx_11_0_arm64.whl
| Download URL | romcal-4.0.0b6-py3-none-macosx_11_0_arm64.whl |
|---|---|
| Size | 1.2 MB |
| Tags | Python 3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
76485af13f2ed8d6bb1a5009f59abcd8c556bef7cd927d15c3de78534fb2bd4e
|
|
BLAKE2b-256 checksum How to use checksums |
0d5cc67ad583d599b81c32d156135b561bd0bb4f14da5d77bc3ded2f2784455f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jan 27, 2026.
Transparency logRelease files / romcal-4.0.0b6-py3-none-macosx_10_12_x86_64.whl
| Download URL | romcal-4.0.0b6-py3-none-macosx_10_12_x86_64.whl |
|---|---|
| Size | 1.2 MB |
| Tags | Python 3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
131a99e2a30db4d8186cc2116a3e1d154049b78218c3cc46ddcdd3c2ec49f805
|
|
BLAKE2b-256 checksum How to use checksums |
9d8f778cf2522115115f3ef8baabec05ed63bbb207070406e3bb60a3e451685f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jan 27, 2026.
Transparency log