0
# Calendar Management
1
2
Comprehensive calendar operations including object retrieval, search functionality, synchronization, and calendar object management with full support for events, todos, and journals.
3
4
## Capabilities
5
6
### Calendar Object Retrieval
7
8
Retrieve different types of calendar objects (events, todos, journals, free/busy) from calendar collections with filtering and type-specific access methods.
9
10
```python { .api }
11
class Calendar(DAVObject):
12
def events(self):
13
"""
14
Get all events in this calendar.
15
16
Returns:
17
list[Event]: List of Event objects
18
"""
19
20
def todos(self):
21
"""
22
Get all todos/tasks in this calendar.
23
24
Returns:
25
list[Todo]: List of Todo objects
26
"""
27
28
def journals(self):
29
"""
30
Get all journal entries in this calendar.
31
32
Returns:
33
list[Journal]: List of Journal objects
34
"""
35
36
def freebusy(self):
37
"""
38
Get all free/busy objects in this calendar.
39
40
Returns:
41
list[FreeBusy]: List of FreeBusy objects
42
"""
43
44
def objects(self, load_objects=False, sort=None):
45
"""
46
Get all calendar objects of all types.
47
48
Parameters:
49
- load_objects: bool, whether to load full object data
50
- sort: str, sort order for objects
51
52
Returns:
53
list[CalendarObjectResource]: All objects in calendar
54
"""
55
56
def objects_by_sync_token(self, sync_token=None, load_objects=True):
57
"""
58
Retrieve objects using WebDAV synchronization for efficient updates.
59
60
Parameters:
61
- sync_token: str, synchronization token from previous sync
62
- load_objects: bool, whether to load full object data (default True)
63
64
Returns:
65
tuple: (objects, new_sync_token) where objects is list of
66
CalendarObjectResource and new_sync_token is str
67
"""
68
```
69
70
**Usage Examples:**
71
72
```python
73
import caldav
74
75
# Get calendar from principal
76
client = caldav.DAVClient(url="...", username="...", password="...")
77
principal = client.principal()
78
calendar = principal.calendars()[0]
79
80
# Get all events
81
all_events = calendar.events()
82
print(f"Found {len(all_events)} events")
83
84
# Get all todos
85
all_todos = calendar.todos()
86
for todo in all_todos:
87
summary = todo.icalendar_component.get('SUMMARY', 'No title')
88
print(f"Todo: {summary}")
89
90
# Note: No general objects() method available
91
# Use specific methods: calendar.events(), calendar.todos(), calendar.journals()
92
93
# Efficient synchronization
94
sync_token = None
95
while True:
96
objects, new_sync_token = calendar.objects_by_sync_token(
97
sync_token=sync_token,
98
load_objects=True
99
)
100
101
if objects:
102
print(f"Found {len(objects)} changed objects")
103
# Process changed objects
104
for obj in objects:
105
print(f"Updated: {obj.id}")
106
107
sync_token = new_sync_token
108
break # In real usage, would check for changes periodically
109
```
110
111
### Calendar Object Creation
112
113
Create and save new calendar objects with support for different object types and creation options.
114
115
```python { .api }
116
def save_event(self, ical, no_overwrite=False, no_create=False):
117
"""
118
Save an event to this calendar.
119
120
Parameters:
121
- ical: str, iCalendar data (VCALENDAR format)
122
- no_overwrite: bool, prevent overwriting existing events (default False)
123
- no_create: bool, prevent creating new events (default False)
124
125
Returns:
126
Event: Saved Event object
127
128
Raises:
129
ConsistencyError: If no_overwrite=True and event exists
130
NotFoundError: If no_create=True and event doesn't exist
131
"""
132
133
def save_todo(self, ical, no_overwrite=False, no_create=False):
134
"""
135
Save a todo/task to this calendar.
136
137
Parameters:
138
- ical: str, iCalendar data (VCALENDAR format)
139
- no_overwrite: bool, prevent overwriting existing todos
140
- no_create: bool, prevent creating new todos
141
142
Returns:
143
Todo: Saved Todo object
144
"""
145
146
def save_journal(self, ical, no_overwrite=False, no_create=False):
147
"""
148
Save a journal entry to this calendar.
149
150
Parameters:
151
- ical: str, iCalendar data (VCALENDAR format)
152
- no_overwrite: bool, prevent overwriting existing journals
153
- no_create: bool, prevent creating new journals
154
155
Returns:
156
Journal: Saved Journal object
157
"""
158
159
# Generic object creation
160
def save_object(self, objclass, ical=None, no_overwrite=False, no_create=False, **ical_data):
161
"""
162
Save calendar object of any type.
163
164
Parameters:
165
- objclass: class, calendar object class (Event, Todo, Journal, FreeBusy)
166
- ical: str, iCalendar data (alternative to **ical_data)
167
- no_overwrite: bool, prevent overwriting existing objects
168
- no_create: bool, prevent creating new objects
169
- **ical_data: additional iCalendar properties
170
171
Returns:
172
CalendarObjectResource: Saved object
173
"""
174
175
def save_with_invites(self, ical, attendees, **attendeeoptions):
176
"""
177
Save calendar object and send invitations to attendees.
178
179
Parameters:
180
- ical: str, iCalendar data
181
- attendees: list[str], attendee email addresses
182
- **attendeeoptions: additional attendee options
183
184
Returns:
185
CalendarObjectResource: Saved object with invitations sent
186
"""
187
188
# Convenient aliases
189
def add_event(self, ical, no_overwrite=False, no_create=False):
190
"""Alias for save_event."""
191
192
def add_todo(self, ical, no_overwrite=False, no_create=False):
193
"""Alias for save_todo."""
194
195
def add_journal(self, ical, no_overwrite=False, no_create=False):
196
"""Alias for save_journal."""
197
```
198
199
**Usage Examples:**
200
201
```python
202
# Create a new event
203
event_ical = """BEGIN:VCALENDAR
204
VERSION:2.0
205
PRODID:-//My App//My App//EN
206
BEGIN:VEVENT
207
UID:meeting-001@example.com
208
DTSTART:20250915T140000Z
209
DTEND:20250915T150000Z
210
SUMMARY:Team Meeting
211
DESCRIPTION:Weekly team sync meeting
212
LOCATION:Conference Room A
213
END:VEVENT
214
END:VCALENDAR"""
215
216
# Save the event
217
event = calendar.save_event(event_ical)
218
print(f"Created event with UID: {event.id}")
219
220
# Create a todo
221
todo_ical = """BEGIN:VCALENDAR
222
VERSION:2.0
223
PRODID:-//My App//My App//EN
224
BEGIN:VTODO
225
UID:task-001@example.com
226
SUMMARY:Complete project documentation
227
DESCRIPTION:Finish writing the API documentation
228
DUE:20250920T170000Z
229
PRIORITY:1
230
STATUS:NEEDS-ACTION
231
END:VTODO
232
END:VCALENDAR"""
233
234
# Save with no overwrite to prevent accidents
235
todo = calendar.save_todo(todo_ical, no_overwrite=True)
236
237
# Create journal entry
238
journal_ical = """BEGIN:VCALENDAR
239
VERSION:2.0
240
PRODID:-//My App//My App//EN
241
BEGIN:VJOURNAL
242
UID:journal-001@example.com
243
DTSTART:20250915T090000Z
244
SUMMARY:Daily standup notes
245
DESCRIPTION:Discussed sprint progress and blockers
246
END:VJOURNAL
247
END:VCALENDAR"""
248
249
journal = calendar.add_journal(journal_ical)
250
```
251
252
### Object Lookup
253
254
Find specific calendar objects by URL or UID for direct access and manipulation.
255
256
```python { .api }
257
def event_by_url(self, href):
258
"""
259
Get event by its URL/href.
260
261
Parameters:
262
- href: str, event URL or href
263
264
Returns:
265
Event: Event object or None if not found
266
"""
267
268
def event_by_uid(self, uid):
269
"""
270
Get event by its UID.
271
272
Parameters:
273
- uid: str, event UID
274
275
Returns:
276
Event: Event object or None if not found
277
"""
278
279
def todo_by_uid(self, uid):
280
"""
281
Get todo by its UID.
282
283
Parameters:
284
- uid: str, todo UID
285
286
Returns:
287
Todo: Todo object or None if not found
288
"""
289
290
def journal_by_uid(self, uid):
291
"""
292
Get journal entry by its UID.
293
294
Parameters:
295
- uid: str, journal UID
296
297
Returns:
298
Journal: Journal object or None if not found
299
"""
300
301
def object_by_uid(self, uid):
302
"""
303
Get any calendar object by its UID.
304
305
Parameters:
306
- uid: str, object UID
307
308
Returns:
309
CalendarObjectResource: Object or None if not found
310
"""
311
```
312
313
### Advanced Search
314
315
Comprehensive search functionality with support for XML queries, component filters, property filters, and date range searches.
316
317
```python { .api }
318
def search(self, xml_query=None, comp_filter=None, prop_filter=None,
319
text_match=None, start=None, end=None, expand=False, verify_expand=True):
320
"""
321
Advanced search for calendar objects with multiple filter options.
322
323
Parameters:
324
- xml_query: str, raw CalDAV XML query
325
- comp_filter: str, component filter (e.g., "VEVENT", "VTODO")
326
- prop_filter: dict, property filters {property: value}
327
- text_match: str, text search in summaries and descriptions
328
- start: datetime, start of date range
329
- end: datetime, end of date range
330
- expand: bool, expand recurring events within date range
331
- verify_expand: bool, verify expanded events (default True)
332
333
Returns:
334
list[CalendarObjectResource]: Matching calendar objects
335
"""
336
337
def date_search(self, start, end=None, compfilter=None, expand=False, verify_expand=True):
338
"""
339
Search for calendar objects within a date range.
340
341
Parameters:
342
- start: datetime, start of search range
343
- end: datetime, end of search range (if None, searches from start forward)
344
- compfilter: str, component type filter ("VEVENT", "VTODO", "VJOURNAL")
345
- expand: bool, expand recurring events within range
346
- verify_expand: bool, verify expanded recurring events
347
348
Returns:
349
list[CalendarObjectResource]: Objects within date range
350
"""
351
```
352
353
**Usage Examples:**
354
355
```python
356
from datetime import datetime, timedelta
357
358
# Find events in the next week
359
start_date = datetime.now()
360
end_date = start_date + timedelta(days=7)
361
362
upcoming_events = calendar.date_search(
363
start=start_date,
364
end=end_date,
365
compfilter="VEVENT",
366
expand=True # Expand recurring events
367
)
368
369
print(f"Found {len(upcoming_events)} upcoming events")
370
for event in upcoming_events:
371
summary = event.icalendar_component.get('SUMMARY', 'No title')
372
dtstart = event.icalendar_component.get('DTSTART').dt
373
print(f" {dtstart}: {summary}")
374
375
# Search for todos with text matching
376
urgent_todos = calendar.search(
377
comp_filter="VTODO",
378
text_match="urgent",
379
prop_filter={"STATUS": "NEEDS-ACTION"}
380
)
381
382
# Complex search with XML query
383
xml_query = """
384
<C:calendar-query xmlns:C="urn:ietf:params:xml:ns:caldav">
385
<D:prop xmlns:D="DAV:">
386
<D:getetag/>
387
<C:calendar-data/>
388
</D:prop>
389
<C:filter>
390
<C:comp-filter name="VCALENDAR">
391
<C:comp-filter name="VEVENT">
392
<C:prop-filter name="SUMMARY">
393
<C:text-match collation="i;ascii-casemap">meeting</C:text-match>
394
</C:prop-filter>
395
</C:comp-filter>
396
</C:comp-filter>
397
</C:filter>
398
</C:calendar-query>"""
399
400
meetings = calendar.search(xml_query=xml_query)
401
402
# Look up specific objects
403
specific_event = calendar.event_by_uid("meeting-001@example.com")
404
if specific_event:
405
print(f"Found event: {specific_event.icalendar_component['SUMMARY']}")
406
407
# Find any object type by UID
408
any_object = calendar.object_by_uid("some-uid@example.com")
409
if any_object:
410
print(f"Object type: {any_object.__class__.__name__}")
411
```
412
413
### Free/Busy Operations
414
415
Request and manage free/busy information for scheduling and availability coordination.
416
417
```python { .api }
418
def freebusy_request(self, start, end, attendees=None):
419
"""
420
Request free/busy information for a time range.
421
422
Parameters:
423
- start: datetime, start of time range
424
- end: datetime, end of time range
425
- attendees: list[str], attendee email addresses (optional)
426
427
Returns:
428
FreeBusy: Free/busy information object
429
"""
430
```
431
432
### Calendar Properties
433
434
Access and manage calendar-specific properties and capabilities.
435
436
```python { .api }
437
@property
438
def supported_calendar_component_set(self):
439
"""Get supported calendar component types for this calendar."""
440
441
def get_supported_components(self):
442
"""
443
Get the set of supported component types.
444
445
Returns:
446
set[str]: Set of supported component types (VEVENT, VTODO, etc.)
447
"""
448
```
449
450
**Usage Examples:**
451
452
```python
453
# Check what components this calendar supports
454
supported = calendar.get_supported_components()
455
print(f"Calendar supports: {', '.join(supported)}")
456
457
# Only create todos if supported
458
if 'VTODO' in supported:
459
todo = calendar.save_todo(todo_ical)
460
else:
461
print("This calendar doesn't support todos")
462
463
# Request free/busy for scheduling
464
from datetime import datetime, timedelta
465
466
meeting_start = datetime(2025, 9, 20, 14, 0) # 2 PM
467
meeting_end = meeting_start + timedelta(hours=1)
468
469
freebusy_info = calendar.freebusy_request(
470
start=meeting_start,
471
end=meeting_end,
472
attendees=["attendee1@example.com", "attendee2@example.com"]
473
)
474
475
# Check availability (implementation depends on server response format)
476
if freebusy_info:
477
print("Free/busy information retrieved successfully")
478
```
479
480
## Search Filter Examples
481
482
```python { .api }
483
# Common component filters
484
COMPONENT_FILTERS = {
485
"events": "VEVENT",
486
"todos": "VTODO",
487
"tasks": "VTODO", # alias
488
"journals": "VJOURNAL",
489
"freebusy": "VFREEBUSY"
490
}
491
492
# Common property filters
493
PROPERTY_FILTERS = {
494
# Todo status filters
495
"pending_todos": {"STATUS": "NEEDS-ACTION"},
496
"completed_todos": {"STATUS": "COMPLETED"},
497
"in_progress_todos": {"STATUS": "IN-PROCESS"},
498
499
# Event status filters
500
"confirmed_events": {"STATUS": "CONFIRMED"},
501
"tentative_events": {"STATUS": "TENTATIVE"},
502
"cancelled_events": {"STATUS": "CANCELLED"},
503
504
# Priority filters
505
"high_priority": {"PRIORITY": "1"},
506
"medium_priority": {"PRIORITY": "5"},
507
"low_priority": {"PRIORITY": "9"}
508
}
509
```