objects – Object definitions

A “DAV object” is anything we get from the caldav server or push into the caldav server, notably principal, calendars and calendar events.

(This file has become huge and will be split up prior to the next release. I think it makes sense moving the CalendarObjectResource class hierarchy into a separate file)

class caldav.objects.Calendar(client: DAVClient | None = None, url: str | ParseResult | SplitResult | URL | None = None, parent: DAVObject | None = None, name: str | None = None, id: str | None = None, props=None, **extra)

The Calendar object is used to represent a calendar collection. Refer to the RFC for details: https://tools.ietf.org/html/rfc4791#section-5.3.1

add_event(ical: str | None = None, no_overwrite: bool = False, no_create: bool = False, **ical_data) Event

Add a new event to the calendar, with the given ical.

Parameters:
  • ical - ical object (text)

  • no_overwrite - existing calendar objects should not be overwritten

  • no_create - don’t create a new object, existing calendar objects should be updated

  • ical_data - passed to lib.vcal.create_ical

add_journal(ical: str | None = None, no_overwrite: bool = False, no_create: bool = False, **ical_data) Journal

Add a new journal entry to the calendar, with the given ical.

Parameters:
  • ical - ical object (text)

add_todo(ical: str | None = None, no_overwrite: bool = False, no_create: bool = False, **ical_data) Todo

Add a new task to the calendar, with the given ical.

Parameters:
  • ical - ical object (text)

build_date_search_query(start, end: datetime | None = None, compfilter: Literal['VEVENT'] | None = 'VEVENT', expand: bool | Literal['maybe'] = 'maybe')

WARNING: DEPRECATED

build_search_xml_query(comp_class=None, todo=None, ignore_completed1=None, ignore_completed2=None, ignore_completed3=None, event=None, filters=None, expand=None, start=None, end=None, props=None, **kwargs)

This method will produce a caldav search query as an etree object.

It is primarily to be used from the search method. See the documentation for the search method for more information.

calendar_multiget(event_urls: Iterable[URL]) List[Event]

get multiple events’ data @author mtorange@gmail.com @type events list of Event

Deprecated. Use self.search() instead.

Search events by date in the calendar. Recurring events are expanded if they are occurring during the specified time frame and if an end timestamp is given.

Parameters:
  • start = datetime.today().

  • end = same as above.

  • compfilter = defaults to events only. Set to None to fetch all calendar components.

  • expand - should recurrent events be expanded? (to preserve backward-compatibility the default “maybe” will be changed into True unless the date_search is open-ended)

  • verify_expand - not in use anymore, but kept for backward compatibility

Returns:
  • [CalendarObjectResource(), …]

event_by_url(href, data: Any | None = None) Event

Returns the event with the given URL

events() List[Event]

List all events from the calendar.

Returns:
  • [Event(), …]

freebusy_request(start: datetime, end: datetime) FreeBusy

Search the calendar, but return only the free/busy information.

Parameters:
  • start = datetime.today().

  • end = same as above.

Returns:
  • [FreeBusy(), …]

get_supported_components() List[Any]

returns a list of component types supported by the calendar, in string format (typically [‘VJOURNAL’, ‘VTODO’, ‘VEVENT’])

journals() List[Journal]

List all journals from the calendar.

Returns:
  • [Journal(), …]

object_by_uid(uid: str, comp_filter: CompFilter | None = None, comp_class: CalendarObjectResource | None = None) Event

Get one event from the calendar.

Parameters:
  • uid: the event uid

  • comp_class: filter by component type (Event, Todo, Journal)

  • comp_filter: for backward compatibility

Returns:
  • Event() or None

objects(sync_token: Any | None = None, load_objects: bool = False) SynchronizableCalendarObjectCollection

objects_by_sync_token aka objects

Do a sync-collection report, ref RFC 6578 and https://github.com/python-caldav/caldav/issues/87

This method will return all objects in the calendar if no sync_token is passed (the method should then be referred to as “objects”), or if the sync_token is unknown to the server. If a sync-token known by the server is passed, it will return objects that are added, deleted or modified since last time the sync-token was set.

If load_objects is set to True, the objects will be loaded - otherwise empty CalendarObjectResource objects will be returned.

This method will return a SynchronizableCalendarObjectCollection object, which is an iterable.

objects_by_sync_token(sync_token: Any | None = None, load_objects: bool = False) SynchronizableCalendarObjectCollection

objects_by_sync_token aka objects

Do a sync-collection report, ref RFC 6578 and https://github.com/python-caldav/caldav/issues/87

This method will return all objects in the calendar if no sync_token is passed (the method should then be referred to as “objects”), or if the sync_token is unknown to the server. If a sync-token known by the server is passed, it will return objects that are added, deleted or modified since last time the sync-token was set.

If load_objects is set to True, the objects will be loaded - otherwise empty CalendarObjectResource objects will be returned.

This method will return a SynchronizableCalendarObjectCollection object, which is an iterable.

save()

The save method for a calendar is only used to create it, for now. We know we have to create it when we don’t have a url.

Returns:
  • self

save_event(ical: str | None = None, no_overwrite: bool = False, no_create: bool = False, **ical_data) Event

Add a new event to the calendar, with the given ical.

Parameters:
  • ical - ical object (text)

  • no_overwrite - existing calendar objects should not be overwritten

  • no_create - don’t create a new object, existing calendar objects should be updated

  • ical_data - passed to lib.vcal.create_ical

save_journal(ical: str | None = None, no_overwrite: bool = False, no_create: bool = False, **ical_data) Journal

Add a new journal entry to the calendar, with the given ical.

Parameters:
  • ical - ical object (text)

save_todo(ical: str | None = None, no_overwrite: bool = False, no_create: bool = False, **ical_data) Todo

Add a new task to the calendar, with the given ical.

Parameters:
  • ical - ical object (text)

save_with_invites(ical: str, attendees, **attendeeoptions) None

sends a schedule request to the server. Equivalent with save_event, save_todo, etc, but the attendees will be added to the ical object before sending it to the server.

search(xml=None, comp_class: _CC | None = None, todo: bool | None = None, include_completed: bool = False, sort_keys: Sequence[str] = (), sort_reverse: bool = False, expand: bool | Literal['server'] | Literal['client'] = False, split_expanded: bool = True, props: List[CalendarData] | None = None, **kwargs) List[_CC]

Creates an XML query, does a REPORT request towards the server and returns objects found, eventually sorting them before delivery.

This method contains some special logics to ensure that it can consistently return a list of pending tasks on any server implementation. In the future it may also include workarounds and client side filtering to make sure other search results are consistent on different server implementations.

LEGACY WARNING: the expand attribute currently takes four possible values - True, False, server and client. The two latter value were hastily added just prior to launching version 1.4, the API may be reconsidered and changed without notice when launching version 2.0

Parameters supported:

  • xml - use this search query, and ignore other filter parameters

  • comp_class - set to event, todo or journal to restrict search to this resource type. Some server implementations require this to be set.

  • todo - sets comp_class to Todo, and restricts search to pending tasks, unless the next parameter is set …

  • include_completed - include completed tasks

  • event - sets comp_class to event

  • text attribute search parameters: category, uid, summary, omment, description, location, status

  • no-category, no-summary, etc … search for objects that does not have those attributes. TODO: WRITE TEST CODE!

  • expand - expand recurring objects

  • start, end: do a time range search

  • filters - other kind of filters (in lxml tree format)

  • sort_keys - list of attributes to use when sorting

  • sort_reverse - reverse the sorting order

not supported yet: * negated text match * attribute not set

todos(sort_keys: Sequence[str] = ('due', 'priority'), include_completed: bool = False, sort_key: str | None = None) List[Todo]

fetches a list of todo events (refactored to a wrapper around search)

Parameters:
  • sort_keys: use this field in the VTODO for sorting (iterable of lower case string, i.e. (‘priority’,’due’)).

  • include_completed: boolean - by default, only pending tasks are listed

  • sort_key: DEPRECATED, for backwards compatibility with version 0.4.

class caldav.objects.CalendarObjectResource(client: DAVClient | None = None, url: str | ParseResult | SplitResult | URL | None = None, data: Any | None = None, parent: Any | None = None, id: Any | None = None, props: Any | None = None)

Ref RFC 4791, section 4.1, a “Calendar Object Resource” can be an event, a todo-item, a journal entry, or a free/busy entry

add_attendee(attendee, no_default_parameters: bool = False, **parameters) None

For the current (event/todo/journal), add an attendee.

The attendee can be any of the following: * A principal * An email address prepended with “mailto:” * An email address without the “mailto:”-prefix * A two-item tuple containing a common name and an email address * (not supported, but planned: an ical text line starting with the word “ATTENDEE”)

Any number of attendee parameters can be given, those will be used as defaults unless no_default_parameters is set to True:

partstat=NEEDS-ACTION cutype=UNKNOWN (unless a principal object is given) rsvp=TRUE role=REQ-PARTICIPANT schedule-agent is not set

add_organizer() None

goes via self.client, finds the principal, figures out the right attendee-format and adds an organizer line to the event

copy(keep_uid: bool = False, new_parent: Any | None = None) Self

Events, todos etc can be copied within the same calendar, to another calendar or even to another caldav server

property data

vCal representation of the object as normal string

expand_rrule(start: datetime, end: datetime) None

This method will transform the calendar content of the event and expand the calendar data from a “master copy” with RRULE set and into a “recurrence set” with RECURRENCE-ID set and no RRULE set. The main usage is for client-side expansion in case the calendar server does not support server-side expansion. It should be safe to save back to the server, the server should recognize it as recurrences and should not edit the “master copy”. If doing a self.load, the calendar content will be replaced with the “master copy”. However, as of 2022-10 there is no test code verifying this.

Parameters:
  • event – Event

  • start – datetime

  • end – datetime

get_dtend()

A VTODO may have due or duration set. Return or calculate due.

WARNING: this method is likely to be deprecated and moved to the icalendar library. If you decide to use it, please put caldav<2.0 in the requirements.

get_due()

A VTODO may have due or duration set. Return or calculate due.

WARNING: this method is likely to be deprecated and moved to the icalendar library. If you decide to use it, please put caldav<2.0 in the requirements.

get_duration() timedelta

According to the RFC, either DURATION or DUE should be set for a task, but never both - implicitly meaning that DURATION is the difference between DTSTART and DUE (personally I believe that’s stupid. If a task takes five minutes to complete - say, fill in some simple form that should be delivered before midnight at new years eve, then it feels natural for me to define “duration” as five minutes, DTSTART to “some days before new years eve” and DUE to 20xx-01-01 00:00:00 - but I digress.

This method will return DURATION if set, otherwise the difference between DUE and DTSTART (if both of them are set).

TODO: should be fixed for Event class as well (only difference is that DTEND is used rather than DUE) and possibly also for Journal (defaults to one day, probably?)

WARNING: this method is likely to be deprecated and moved to the icalendar library. If you decide to use it, please put caldav<3.0 in the requirements.

get_relatives(reltypes: Container[str] | None = None, relfilter: Callable[[Any], bool] | None = None, fetch_objects: bool = True, ignore_missing: bool = True) defaultdict[str, Set[str]]

By default, loads all objects pointed to by the RELATED-TO property and loads the related objects.

It’s possible to filter, either by passing a set or a list of acceptable relation types in reltypes, or by passing a lambda function in relfilter.

TODO: Make it possible to also check up reverse relationships

TODO: this is partially overlapped by plann.lib._relships_by_type in the plann tool. Should consolidate the code.

property icalendar_component

icalendar component - should not be used with recurrence sets

property icalendar_instance

icalendar instance of the object

property instance: Component | None

vobject instance of the object

load(only_if_unloaded: bool = False) Self

(Re)load the object from the caldav server.

save(no_overwrite: bool = False, no_create: bool = False, obj_type: str | None = None, increase_seqno: bool = True, if_schedule_tag_match: bool = False) Self

Save the object, can be used for creation and update.

no_overwrite and no_create will check if the object exists. Those two are mutually exclusive. Some servers don’t support searching for an object uid without explicitly specifying what kind of object it should be, hence obj_type can be passed. obj_type is only used in conjunction with no_overwrite and no_create.

Returns:
  • self

set_relation(other, reltype=None, set_reverse=True) None

Sets a relation between this object and another object (given by uid or object).

property vobject_instance: Component | None

vobject instance of the object

property wire_data

vCal representation of the object in wire format (UTF-8, CRLN)

class caldav.objects.CalendarSet(client: DAVClient | None = None, url: str | ParseResult | SplitResult | URL | None = None, parent: DAVObject | None = None, name: str | None = None, id: str | None = None, props=None, **extra)

A CalendarSet is a set of calendars.

calendar(name: str | None = None, cal_id: str | None = None) Calendar

The calendar method will return a calendar object. If it gets a cal_id but no name, it will not initiate any communication with the server

Parameters:
  • name: return the calendar with this display name

  • cal_id: return the calendar with this calendar id or URL

Returns:
  • Calendar(…)-object

calendars() List[Calendar]

List all calendar collections in this set.

Returns:
  • [Calendar(), …]

make_calendar(name: str | None = None, cal_id: str | None = None, supported_calendar_component_set: Any | None = None) Calendar

Utility method for creating a new calendar.

Parameters:
  • name: the display name of the new calendar

  • cal_id: the uuid of the new calendar

  • supported_calendar_component_set: what kind of objects (EVENT, VTODO, VFREEBUSY, VJOURNAL) the calendar should handle. Should be set to [‘VTODO’] when creating a task list in Zimbra - in most other cases the default will be OK.

Returns:
  • Calendar(…)-object

class caldav.objects.DAVObject(client: DAVClient | None = None, url: str | ParseResult | SplitResult | URL | None = None, parent: DAVObject | None = None, name: str | None = None, id: str | None = None, props=None, **extra)

Base class for all DAV objects. Can be instantiated by a client and an absolute or relative URL, or from the parent object.

children(type: str | None = None) List[Tuple[URL, Any, Any]]

List children, using a propfind (resourcetype) on the parent object, at depth = 1.

TODO: This is old code, it’s querying for DisplayName and ResourceTypes prop and returning a tuple of those. Those two are relatively arbitrary. I think it’s mostly only calendars having DisplayName, but it may make sense to ask for the children of a calendar also as an alternative way to get all events? It should be redone into a more generic method, and it should probably return a dict rather than a tuple. We should also look over to see if there is any code duplication.

delete() None

Delete the object.

get_display_name()

Get calendar display name

get_properties(props: Sequence[BaseElement] | None = None, depth: int = 0, parse_response_xml: bool = True, parse_props: bool = True)

Get properties (PROPFIND) for this object.

With parse_response_xml and parse_props set to True a best-attempt will be done on decoding the XML we get from the server - but this works only for properties that don’t have complex types. With parse_response_xml set to False, a DAVResponse object will be returned, and it’s up to the caller to decode. With parse_props set to false but parse_response_xml set to true, xml elements will be returned rather than values.

Parameters:
  • props = [dav.ResourceType(), dav.DisplayName(), …]

Returns:
  • {proptag: value, …}

save() Self

Save the object. This is an abstract method, that all classes derived from DAVObject implement.

Returns:
  • self

set_properties(props: Any | None = None) Self

Set properties (PROPPATCH) for this object.

  • props = [dav.DisplayName(‘name’), …]

Returns:
  • self

class caldav.objects.Event(client: DAVClient | None = None, url: str | ParseResult | SplitResult | URL | None = None, data: Any | None = None, parent: Any | None = None, id: Any | None = None, props: Any | None = None)

The Event object is used to represent an event (VEVENT).

As of 2020-12 it adds nothing to the inheritated class. (I have frequently asked myself if we need those subclasses … perhaps not)

class caldav.objects.FreeBusy(parent, data, url: str | ParseResult | SplitResult | URL | None = None, id: Any | None = None)

The FreeBusy object is used to represent a freebusy response from the server. __init__ is overridden, as a FreeBusy response has no URL or ID. The inheritated methods .save and .load is moot and will probably throw errors (perhaps the class hierarchy should be rethought, to prevent the FreeBusy from inheritating moot methods)

Update: With RFC6638 a freebusy object can have a URL and an ID.

class caldav.objects.Journal(client: DAVClient | None = None, url: str | ParseResult | SplitResult | URL | None = None, data: Any | None = None, parent: Any | None = None, id: Any | None = None, props: Any | None = None)

The Journal object is used to represent a journal entry (VJOURNAL).

As of 2020-12 it adds nothing to the inheritated class. (I have frequently asked myself if we need those subclasses … perhaps not)

class caldav.objects.Principal(client: DAVClient | None = None, url: str | ParseResult | SplitResult | URL | None = None)

This class represents a DAV Principal. It doesn’t do much, except keep track of the URLs for the calendar-home-set, etc.

A principal MUST have a non-empty DAV:displayname property (defined in Section 13.2 of [RFC2518]), and a DAV:resourcetype property (defined in Section 13.9 of [RFC2518]). Additionally, a principal MUST report the DAV:principal XML element in the value of the DAV:resourcetype property.

(TODO: the resourcetype is actually never checked, and the DisplayName is not stored anywhere)

calendar(name: str | None = None, cal_id: str | None = None, cal_url: str | None = None) Calendar

The calendar method will return a calendar object. It will not initiate any communication with the server.

calendar_user_address_set() List[str | None]

defined in RFC6638

calendars() List[Calendar]

Return the principials calendars

get_vcal_address() vCalAddress

Returns the principal, as an icalendar.vCalAddress object

make_calendar(name: str | None = None, cal_id: str | None = None, supported_calendar_component_set: Any | None = None) Calendar

Convenience method, bypasses the self.calendar_home_set object. See CalendarSet.make_calendar for details.

class caldav.objects.ScheduleInbox(client: DAVClient | None = None, principal: Principal | None = None, url: str | ParseResult | SplitResult | URL | None = None)
class caldav.objects.ScheduleMailbox(client: DAVClient | None = None, principal: Principal | None = None, url: str | ParseResult | SplitResult | URL | None = None)

RFC6638 defines an inbox and an outbox for handling event scheduling.

TODO: As ScheduleMailboxes works a bit like calendars, I’ve chosen to inheritate the Calendar class, but this is a bit incorrect, a ScheduleMailbox is a collection, but not really a calendar. We should create a common base class for ScheduleMailbox and Calendar eventually.

get_items()

TODO: work in progress TODO: perhaps this belongs to the super class?

class caldav.objects.ScheduleOutbox(client: DAVClient | None = None, principal: Principal | None = None, url: str | ParseResult | SplitResult | URL | None = None)
class caldav.objects.SynchronizableCalendarObjectCollection(calendar, objects, sync_token)

This class may hold a cached snapshot of a calendar, and changes in the calendar can easily be copied over through the sync method.

To create a SynchronizableCalendarObjectCollection object, use calendar.objects(load_objects=True)

objects_by_url()

returns a dict of the contents of the SynchronizableCalendarObjectCollection, URLs -> objects.

sync() Tuple[Any, Any]

This method will contact the caldav server, request all changes from it, and sync up the collection

class caldav.objects.Todo(client: DAVClient | None = None, url: str | ParseResult | SplitResult | URL | None = None, data: Any | None = None, parent: Any | None = None, id: Any | None = None, props: Any | None = None)

The Todo object is used to represent a todo item (VTODO). A Todo-object can be completed. Extra logic for different ways to complete one recurrence of a recurrent todo. Extra logic to handle due vs duration.

complete(completion_timestamp: datetime | None = None, handle_rrule: bool = False, rrule_mode: Literal['safe', 'this_and_future'] = 'safe') None

Marks the task as completed.

Parameters:
  • completion_timestamp - datetime object. Defaults to datetime.now().

  • handle_rrule - if set to True, the library will try to be smart if the task is recurring. The default is False, for backward compatibility. I may consider making this one mandatory.

  • rrule_mode - The RFC leaves a lot of room for interpretation on how to handle recurring tasks, and what works on one server may break at another. The following modes are accepted: * this_and_future - see doc for _complete_recurring_thisandfuture for details * safe - see doc for _complete_recurring_safe for details

set_due(due, move_dtstart=False, check_dependent=False)

The RFC specifies that a VTODO cannot have both due and duration, so when setting due, the duration field must be evicted

check_dependent=True will raise some error if there exists a parent calendar component (through RELATED-TO), and the parents due or dtend is before the new dtend).

WARNING: this method is likely to be deprecated and parts of it moved to the icalendar library. If you decide to use it, please put caldav<2.0 in the requirements.

WARNING: the check_dependent-logic may be rewritten to support RFC9253 in 1.x already

set_duration(duration, movable_attr='DTSTART')

If DTSTART and DUE/DTEND is already set, one of them should be moved. Which one? I believe that for EVENTS, the DTSTART should remain constant and DTEND should be moved, but for a task, I think the due date may be a hard deadline, hence by default we’ll move DTSTART.

TODO: can this be written in a better/shorter way?

WARNING: this method is likely to be deprecated and moved to the icalendar library. If you decide to use it, please put caldav<2.0 in the requirements.

uncomplete() None

Undo completion - marks a completed task as not completed

caldav.objects.errmsg(r) str

Utility for formatting a response xml tree to an error string