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

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 Romcal

# With calendar and locale
romcal1 = Romcal(calendar="france", locale="fr")

# With full configuration
romcal2 = Romcal(
    calendar="france",
    locale="fr",
    context="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 str "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 str "GREGORIAN" "GREGORIAN" or "JULIAN" Easter calculation
calendar_definitions_json str None JSON string of calendar definitions
resources_json str None JSON string of locale resources

Loading Calendar Data

Without loading data, only the Proper of Time is available. To include the General Roman Calendar, particular calendars, and localized names, load calendar definitions and resources:

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
romcal = Romcal(
    calendar="france",
    locale="fr",
    calendar_definitions_json=json.dumps(load_calendar_definitions()),
    resources_json=json.dumps(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.10 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

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.0b2.tar.gz (183.9 kB view details)

Uploaded Source

Built Distribution

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

romcal-4.0.0b2-py3-none-macosx_11_0_arm64.whl (711.4 kB view details)

Uploaded Python 3macOS 11.0+ ARM64

File details

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

File metadata

  • Download URL: romcal-4.0.0b2.tar.gz
  • Upload date:
  • Size: 183.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: maturin/1.10.2

File hashes

Hashes for romcal-4.0.0b2.tar.gz
Algorithm Hash digest
SHA256 403eb4b1be3e04c4a997f7bb08b69f98f60d73b40cc3c1592b814adecec7c33b
MD5 e21b953c599022df3964de41cc881376
BLAKE2b-256 1eed2d14fcf4eb5fc0141e888810d3516eb975e7b3e3cc5b210d0767a5e6e14c

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for romcal-4.0.0b2-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 8edcbd43c8d21b3c99fd737aaa891a3535baa6cc038f24e817dd96ce2ace42a7
MD5 aef6e46327bdfcba787d603bb23b7f72
BLAKE2b-256 5b31ea3cbbbb7ab17e99a591a69bd33ed1dae61750f6327f5938ebca9a23c830

See more details on using hashes here.

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