Skip to main content
Pre-release

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

  • Python 3.11 or later
  • uv (recommended) or pip
  • Rust 1.85 or later

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.

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)

Source distribution for romcal 4.0.0b6
File Size Uploaded
romcal-4.0.0b6.tar.gz 194.0 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for romcal 4.0.0b6
File
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 log

Release 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 log

Release 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 log

Release 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 log

Release 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 log

Release 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 log

Release 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 log

Release 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 log

Release 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
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page