A modern, local-first CalDAV client engine and embeddable ASGI server for Python, powered by ical.
icaldav transforms CalDAV from a notoriously brittle network protocol into a fast, reliable local synchronization pipeline. By pairing ical's type-safe data processing and recurrence engine with an asyncio-native sync engine and embeddable server router, icaldav completes the Python calendar ecosystem.
For a detailed breakdown of the local-first synchronization model, dual-path sync engine, and server scope, see the Design Document.
Interacting with CalDAV servers in Python has historically meant navigating fragmented RFC support, heavy server-side search bugs, and complex XML queries. icaldav redefines CalDAV integration by adopting a local-first synchronization architecture:
Rather than relying on distant servers to perform complex date filtering or recurrence expansions, icaldav efficiently streams raw .ics payloads into local storage and delegates data modeling, validation, and timeline generation to ical.
| Feature | icaldav |
python-caldav |
Raw WebDAV Tools |
|---|---|---|---|
Async Native (asyncio) |
✅ First-class (aiohttp) |
❌ Sync only | |
| Data Engine | ✅ ical (Pydantic v2) |
❌ icalendar / vobject |
❌ None (raw XML/strings) |
| Recurrence Handling | ✅ Local & exact (Timeline) |
icalendar) |
❌ None |
| Incremental Sync | ✅ RFC 6578 + ETag Fallback | ❌ Manual | |
| Embeddable Server | ✅ ASGI Router included | ❌ Client only | ❌ Client only |
| Type Safety | ✅ Strict py.typed |
❌ None |
- ⚡ Async Client (
CalDavClient): Built withasyncioandaiohttpfor high-performance HTTP communication and type-safeicalPydantic models. - 🔄 Resilient Sync Engine (
CalDavSyncManager): Supports RFC 6578 (WebDAV Collection Synchronization) for single-request delta fetches, with automatic ETag fallback for non-RFC 6578 servers (e.g. Radicale, iCloud). - 🧩 Local-First Recurrence & Queries: Performs time-range slicing and recurrence expansions locally via
ical'sTimeline, avoiding server-sidecalendar-querybugs. - 🚀 Embeddable ASGI Server Router (
CalDavRouter): Mount a minimalist CalDAV server endpoint into FastAPI, Starlette, oraiohttpapplications to expose calendars to native iOS, macOS, or Thunderbird clients.
uv add icaldavOr with pip:
pip install icaldavRequires Python 3.12+.
import asyncio
from icaldav import CalDavClient, CalDavSyncManager
from icaldav.store import SQLiteStore
async def main():
async with CalDavClient(
url="https://caldav.example.com",
username="user",
password="password",
) as client:
# Discover calendar collections
calendars = await client.get_calendars()
calendar = calendars[0]
# Sync events down to a local store
store = SQLiteStore("calendar_cache.db")
sync_manager = CalDavSyncManager(client=client, collection=calendar, store=store)
await sync_manager.run()
# Query locally using `ical`'s timeline
local_calendar = await store.get_calendar()
for event in local_calendar.timeline.today():
print(f"{event.start}: {event.summary}")
asyncio.run(main())from fastapi import FastAPI
from icaldav.server import CalDavRouter
from icaldav.provider import LocalCalendarProvider
app = FastAPI()
# Expose local calendars to native mobile & desktop clients
app.include_router(
CalDavRouter(provider=LocalCalendarProvider()),
prefix="/caldav",
)Apache-2.0