icaldav
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.
Why icaldav?
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 (httpx) |
⚠️ Partial wrapper module | ❌ Sync only |
| Data Engine | ✅ ical (Pydantic v2) |
❌ icalendar / vobject |
❌ None (raw XML/strings) |
| Recurrence Handling | ✅ Local & exact (Timeline) |
❌ Server-dependent | ❌ None |
| Incremental Sync | ✅ RFC 6578 + ETag Fallback | ⚠️ Experimental | ❌ Manual |
| Embeddable Server | ✅ ASGI Router included | ❌ Client only | ❌ Client only |
| Type Safety | ✅ Strict py.typed |
⚠️ In progress | ❌ None |
Key Features
- ⚡ Async Client (
CalDavClient): Built withasyncioandhttpxfor high-performance HTTP/2 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.
Installation
uv add icaldav
Or with pip:
pip install icaldav
Requires Python 3.12+.
Quickstart
Syncing a Remote Calendar Down to Local Storage
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())
Embedding a CalDAV Server Endpoint
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",
)
License
Apache-2.0
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file icaldav-0.0.1.tar.gz.
File metadata
- Download URL: icaldav-0.0.1.tar.gz
- Upload date:
- Size: 7.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6d9d35d510c27bcd5fed6a2807b6f592f5bd3d2629d458a87a44b72a14aa2149
|
|
| MD5 |
1ada9935776f7e5110578b1cb00b99db
|
|
| BLAKE2b-256 |
8cecc935600828e2c9f44250d5f6cd67ad6c563d945565dfb9499b7bd13e5f7a
|
Provenance
The following attestation bundles were made for icaldav-0.0.1.tar.gz:
Publisher:
publish.yaml on allenporter/icaldav
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
icaldav-0.0.1.tar.gz -
Subject digest:
6d9d35d510c27bcd5fed6a2807b6f592f5bd3d2629d458a87a44b72a14aa2149 - Sigstore transparency entry: 2210077058
- Sigstore integration time:
-
Permalink:
allenporter/icaldav@b53d2f761e428de7efebd63eb6a7bccb1ea15e40 -
Branch / Tag:
refs/tags/0.0.1 - Owner: https://github.com/allenporter
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yaml@b53d2f761e428de7efebd63eb6a7bccb1ea15e40 -
Trigger Event:
release
-
Statement type:
File details
Details for the file icaldav-0.0.1-py3-none-any.whl.
File metadata
- Download URL: icaldav-0.0.1-py3-none-any.whl
- Upload date:
- Size: 7.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0eda504db92f4e992e397f2e8b72f668a2356cf61a1e84f8bc9e2847b6009459
|
|
| MD5 |
d1dbb153f7b351540fafaae225b2098c
|
|
| BLAKE2b-256 |
8f335008f311dfa52d1ebd8a4e1e9eb35fe1ea0cf5d0f587685bd8e63f5e636c
|
Provenance
The following attestation bundles were made for icaldav-0.0.1-py3-none-any.whl:
Publisher:
publish.yaml on allenporter/icaldav
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
icaldav-0.0.1-py3-none-any.whl -
Subject digest:
0eda504db92f4e992e397f2e8b72f668a2356cf61a1e84f8bc9e2847b6009459 - Sigstore transparency entry: 2210077074
- Sigstore integration time:
-
Permalink:
allenporter/icaldav@b53d2f761e428de7efebd63eb6a7bccb1ea15e40 -
Branch / Tag:
refs/tags/0.0.1 - Owner: https://github.com/allenporter
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yaml@b53d2f761e428de7efebd63eb6a7bccb1ea15e40 -
Trigger Event:
release
-
Statement type: