CalDAV (RFC4791) client library for Python with comprehensive calendar server interaction capabilities
npx @tessl/cli install tessl/pypi-caldav@2.0.0A comprehensive Python client library for the CalDAV protocol (RFC4791) that enables developers to interact with calendar servers. CalDAV provides complete functionality for calendar management including creating and modifying calendars, managing events, todos, and journal entries, and handling recurring events across popular CalDAV servers.
pip install caldavimport caldavMain client class:
from caldav import DAVClientFor backward compatibility, all classes can be imported directly:
from caldav import Principal, Calendar, Event, Todo, Journalimport caldav
from datetime import datetime
# Connect to CalDAV server
client = caldav.DAVClient(
url="https://calendar.server.com/caldav/",
username="user@example.com",
password="password"
)
# Get the principal (user account)
principal = client.principal()
# Get all calendars
calendars = principal.calendars()
calendar = calendars[0] # Use first calendar
# Create a new event
event_ical = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp//Example App//EN
BEGIN:VEVENT
UID:example-event-001
DTSTART:20250910T140000Z
DTEND:20250910T150000Z
SUMMARY:Important Meeting
DESCRIPTION:Discuss project milestones
END:VEVENT
END:VCALENDAR"""
# Save the event to the calendar
event = calendar.save_event(event_ical)
print(f"Created event: {event.id}")
# Search for events in date range
events = calendar.date_search(
start=datetime(2025, 9, 1),
end=datetime(2025, 9, 30)
)
for event in events:
print(f"Event: {event.icalendar_component['SUMMARY']}")CalDAV follows the WebDAV/CalDAV protocol hierarchy:
The library abstracts the complexity of the CalDAV protocol while providing full access to advanced features like recurring events, free/busy scheduling, and server-specific extensions.
Core client functionality for connecting to CalDAV servers with various authentication methods including Basic, Digest, and Bearer token authentication.
class DAVClient:
def __init__(self, url, proxy=None, username=None, password=None,
auth=None, timeout=None, headers=None, ssl_verify_cert=True,
ssl_cert=None, huge_tree=False, auth_type='auto'): ...
def principal(self, url=None): ...def get_davclient(check_config_file=True, config_file=None, config_section=None,
testconfig=False, environment=True, name=None, **config_data): ...Client Connection & Authentication
Principal management and calendar discovery functionality for finding and accessing user calendars and calendar collections.
class Principal:
def calendars(self): ...
def make_calendar(self, name=None, cal_id=None, supported_calendar_component_set=None): ...
def freebusy_request(self, start, end, attendees): ...
class CalendarSet:
def calendars(self): ...
def make_calendar(self, name=None, cal_id=None, supported_calendar_component_set=None): ...Principal & Calendar Discovery
Calendar operations including creating, configuring, and managing calendar collections with support for different calendar component types.
class Calendar:
def events(self): ...
def todos(self): ...
def journals(self): ...
def objects_by_sync_token(self, sync_token=None, load_objects=True): ...
def search(self, xml_query=None, comp_filter=None, prop_filter=None,
text_match=None, start=None, end=None, expand=False, verify_expand=True): ...
def date_search(self, start, end=None, compfilter=None, expand=False, verify_expand=True): ...
def save_event(self, ical, no_overwrite=False, no_create=False): ...
def save_todo(self, ical, no_overwrite=False, no_create=False): ...
def save_journal(self, ical, no_overwrite=False, no_create=False): ...Comprehensive event management including creation, modification, deletion, and handling of recurring events with full iCalendar support.
class Event(CalendarObjectResource):
def get_dtstart(self): ...
def get_dtend(self): ...
def get_duration(self): ...
def set_dtstart(self, dtstart): ...
def set_dtend(self, dtend): ...
def set_duration(self, duration): ...Todo/task management functionality with support for due dates, completion tracking, and task hierarchies.
class Todo(CalendarObjectResource):
def complete(self, completion_timestamp=None, handle_rrule=True): ...
def get_due(self): ...
def get_dtstart(self): ...
def set_due(self, due): ...
def set_dtstart(self, dtstart): ...Journal entry management and free/busy scheduling functionality for calendar coordination and availability management.
class Journal(CalendarObjectResource): ...
class FreeBusy(CalendarObjectResource): ...class DAVObject:
"""Base class for all DAV objects with common DAV operations."""
def __init__(self, client=None, url=None, parent=None, name=None, id=None, props=None): ...
def propfind(self, props=None, depth="0"): ...
def proppatch(self, body): ...
def delete(self): ...
def get_property(self, prop): ...
def set_properties(self, props): ...
class CalendarObjectResource(DAVObject):
"""Base class for calendar objects (events, todos, journals, freebusy)."""
def __init__(self, client=None, url=None, data=None, parent=None, id=None): ...
def load(self): ...
def save(self): ...
def copy(self, new_parent): ...
def move(self, new_parent): ...
def expand(self, start, end): ...
def change_uid(self, new_uid=None): ...class DAVError(Exception): ...
class AuthorizationError(DAVError): ...
class PropsetError(DAVError): ...
class ProppatchError(DAVError): ...
class PropfindError(DAVError): ...
class ReportError(DAVError): ...
class MkcolError(DAVError): ...
class MkcalendarError(DAVError): ...
class PutError(DAVError): ...
class DeleteError(DAVError): ...
class NotFoundError(DAVError): ...
class ConsistencyError(DAVError): ...
class ResponseError(DAVError): ...def get_davclient(check_config_file=True, config_file=None, config_section=None,
testconfig=False, environment=True, name=None, **config_data):
"""
Factory function to create DAVClient from configuration.
Parameters:
- check_config_file: bool, whether to look for config files
- config_file: str, specific config file path
- config_section: str, section name in config file
- testconfig: bool, use test configuration
- environment: bool, read from environment variables
- name: str, configuration name/profile
- **config_data: additional configuration parameters
Returns:
DAVClient: Configured client instance
"""
def create_ical(ical_fragment=None, objtype=None, language="en_DK", **props):
"""
Create iCalendar object from fragment or properties.
Parameters:
- ical_fragment: str, partial iCalendar data
- objtype: str, object type ('VEVENT', 'VTODO', 'VJOURNAL')
- language: str, language for the calendar
- **props: additional iCalendar properties
Returns:
str: Complete iCalendar data
"""
def add_alarm(ical, alarm):
"""
Add alarm/reminder to iCalendar object.
Parameters:
- ical: str, iCalendar data
- alarm: dict or str, alarm configuration
Returns:
str: iCalendar data with alarm added
"""
def fix(event):
"""
Fix common iCalendar issues and validate format.
Parameters:
- event: str, iCalendar data to fix
Returns:
str: Fixed iCalendar data
"""class SynchronizableCalendarObjectCollection:
"""
Cached collection with sync support for efficient calendar updates.
"""
def __init__(self, calendar, objects, sync_token):
"""
Initialize synchronized collection.
Parameters:
- calendar: Calendar, parent calendar
- objects: list, initial objects
- sync_token: str, synchronization token
"""
def __iter__(self):
"""Iterator support for collection."""
def __len__(self):
"""Length support for collection."""
def objects_by_url(self):
"""
Get objects mapped by URL.
Returns:
dict: URL to object mapping
"""
def sync(self):
"""
Synchronize collection with server.
Returns:
tuple: (updated_objects, new_sync_token)
"""def make(url):
"""
Create URL object from string.
Parameters:
- url: str, URL string
Returns:
URL: URL object with CalDAV-specific methods
"""
def ns(prefix, tag=None):
"""
Create namespaced XML tag for CalDAV/WebDAV operations.
Parameters:
- prefix: str, namespace prefix ('dav', 'caldav', etc.)
- tag: str, optional tag name
Returns:
str: Namespaced XML tag
"""def to_wire(text):
"""
Convert text to wire format for HTTP transmission.
Parameters:
- text: str, text to convert
Returns:
bytes: Wire-formatted text
"""
def to_local(text):
"""
Convert text from wire format to local format.
Parameters:
- text: bytes, wire-formatted text
Returns:
str: Local text format
"""
def to_normal_str(text):
"""
Convert text to normal string format.
Parameters:
- text: str or bytes, text to normalize
Returns:
str: Normalized string
"""
def to_unicode(text):
"""
Convert text to unicode string.
Parameters:
- text: str or bytes, text to convert
Returns:
str: Unicode string
"""