Skip to main content

Liturgical calendar library for calculating Catholic liturgical dates and calendars

Project description

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.

Related

License

Apache License 2.0. See LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

romcal-4.0.0b6.tar.gz (194.0 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

romcal-4.0.0b6-py3-none-win_arm64.whl (1.1 MB view details)

Uploaded Python 3Windows ARM64

romcal-4.0.0b6-py3-none-win_amd64.whl (1.1 MB view details)

Uploaded Python 3Windows x86-64

romcal-4.0.0b6-py3-none-musllinux_1_2_x86_64.whl (1.5 MB view details)

Uploaded Python 3musllinux: musl 1.2+ x86-64

romcal-4.0.0b6-py3-none-musllinux_1_2_aarch64.whl (1.5 MB view details)

Uploaded Python 3musllinux: musl 1.2+ ARM64

romcal-4.0.0b6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.3 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

romcal-4.0.0b6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.3 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

romcal-4.0.0b6-py3-none-macosx_11_0_arm64.whl (1.2 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

romcal-4.0.0b6-py3-none-macosx_10_12_x86_64.whl (1.2 MB view details)

Uploaded Python 3macOS 10.12+ x86-64

File details

Details for the file romcal-4.0.0b6.tar.gz.

File metadata

  • Download URL: romcal-4.0.0b6.tar.gz
  • Upload date:
  • Size: 194.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for romcal-4.0.0b6.tar.gz
Algorithm Hash digest
SHA256 3d0d5b3a32c92b9d7ceddf2d38afcb0e34e2411bb24cc81ccd2b330200199a4e
MD5 83a8dbcccd5fdf04d069aa298ad67600
BLAKE2b-256 6f0406b6db8f39d02dea3231c9d7f4538e59a20a43ce4908f467135d520215c4

See more details on using hashes here.

Provenance

The following attestation bundles were made for romcal-4.0.0b6.tar.gz:

Publisher: publish.yml on emagnier/romcal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file romcal-4.0.0b6-py3-none-win_arm64.whl.

File metadata

  • Download URL: romcal-4.0.0b6-py3-none-win_arm64.whl
  • Upload date:
  • Size: 1.1 MB
  • Tags: Python 3, Windows ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for romcal-4.0.0b6-py3-none-win_arm64.whl
Algorithm Hash digest
SHA256 88e5f356b4120f8ab843a1c0abfac59d1355765bc47501d473aea4da89bf0302
MD5 dbd41f0e6a06dba08ede10966f3cd3d8
BLAKE2b-256 72a291163c05f98e0a74a357fa45e23152ed87d8b13db2a9d5d94adaa706e59b

See more details on using hashes here.

Provenance

The following attestation bundles were made for romcal-4.0.0b6-py3-none-win_arm64.whl:

Publisher: publish.yml on emagnier/romcal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file romcal-4.0.0b6-py3-none-win_amd64.whl.

File metadata

  • Download URL: romcal-4.0.0b6-py3-none-win_amd64.whl
  • Upload date:
  • Size: 1.1 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for romcal-4.0.0b6-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 0b6352dee0e27425bdcc9224b42d79c56aa759692ca521b0d3ed9cddb9feeb96
MD5 64cf3c618eea54a35b37c211370fd732
BLAKE2b-256 7df337581b4800b3248f1899815ac9c7b5494fd5eb3b884d155dec7ea1d6ce18

See more details on using hashes here.

Provenance

The following attestation bundles were made for romcal-4.0.0b6-py3-none-win_amd64.whl:

Publisher: publish.yml on emagnier/romcal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file romcal-4.0.0b6-py3-none-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for romcal-4.0.0b6-py3-none-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 a693b46e9a6c5d0ab1dc5e65a9ed8ddfc2f972300da11b600f0d7ed8d6e18f72
MD5 bd66bc93e123381221567c04a354d2be
BLAKE2b-256 db6f07ef1fc6baffd8dd61b08d6bb2ddab63e9e3210fd12fc1e60d57b41880c4

See more details on using hashes here.

Provenance

The following attestation bundles were made for romcal-4.0.0b6-py3-none-musllinux_1_2_x86_64.whl:

Publisher: publish.yml on emagnier/romcal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file romcal-4.0.0b6-py3-none-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for romcal-4.0.0b6-py3-none-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 21a2536529c56004f237828f6f85aa22a68fa9da65b407d72cb3f94bb16c91b1
MD5 14e638f8551c9e82e8875b48d457f233
BLAKE2b-256 174b73ea37da40fcce20ce116c4044a1a69c0f92c926d33fdf835e93d78650d2

See more details on using hashes here.

Provenance

The following attestation bundles were made for romcal-4.0.0b6-py3-none-musllinux_1_2_aarch64.whl:

Publisher: publish.yml on emagnier/romcal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file romcal-4.0.0b6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for romcal-4.0.0b6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 3c697e1e8ebbc4275fde01394094c48494a5dcfd12f2cb1cf746052c3aa41ae5
MD5 0b20b4dad08e0ae1e33346e21327c756
BLAKE2b-256 b74f0418a218fbd5b71bd5230136a66612ddd6247b7969fd7d0b9045fb0f0c85

See more details on using hashes here.

Provenance

The following attestation bundles were made for romcal-4.0.0b6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: publish.yml on emagnier/romcal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file romcal-4.0.0b6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for romcal-4.0.0b6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 5e5280e74cabadab7780a5bba9b8b12e160cdf025505d8a2406250605da7f7d2
MD5 ff01d49fde55961e51fcaf279db952d7
BLAKE2b-256 21ba72a84aebccb4ebd3590b6d23e3a182308d106246307668f11061aca8bfaa

See more details on using hashes here.

Provenance

The following attestation bundles were made for romcal-4.0.0b6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: publish.yml on emagnier/romcal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file romcal-4.0.0b6-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for romcal-4.0.0b6-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 76485af13f2ed8d6bb1a5009f59abcd8c556bef7cd927d15c3de78534fb2bd4e
MD5 c8c511ce20216ccc970720841570c7ca
BLAKE2b-256 0d5cc67ad583d599b81c32d156135b561bd0bb4f14da5d77bc3ded2f2784455f

See more details on using hashes here.

Provenance

The following attestation bundles were made for romcal-4.0.0b6-py3-none-macosx_11_0_arm64.whl:

Publisher: publish.yml on emagnier/romcal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file romcal-4.0.0b6-py3-none-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for romcal-4.0.0b6-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 131a99e2a30db4d8186cc2116a3e1d154049b78218c3cc46ddcdd3c2ec49f805
MD5 d8262d868f8c7c2917b58ac7d7fc2191
BLAKE2b-256 9d8f778cf2522115115f3ef8baabec05ed63bbb207070406e3bb60a3e451685f

See more details on using hashes here.

Provenance

The following attestation bundles were made for romcal-4.0.0b6-py3-none-macosx_10_12_x86_64.whl:

Publisher: publish.yml on emagnier/romcal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page