Save the ions!

Introducing (python-)caldav

During the last few days, I’ve been busy writing a CalDAV client library for work. This is a requirement because we are going to integrate calendars from various sources in one of our websites.

CalDAV is clearly the way to go, but as far as libraries go, the only one I’ve been able to find was CalDAVClientLibrary, which, quite frankly, scares me. I’m already familiar with CalendarServer, and I can’t qualify that as “lightweight”, “simple” or “easily installable”.

CalDAV

In case you don’t know what CalDAV is, it’s an extension to webdav for calendaring, and is defined in rfc4791. If you don’t feel like reading all of this, it’s mostly HTTP with XML requests and responses, but not always, which is why it gets kind of weird…

Example requests

Creating a calendar:

MKCOL /calendars/pythoncaldav-test HTTP/1.1
Host: example.com
Accept-Encoding: identity
Content-Length: 249

<?xml version='1.0' encoding='utf-8'?>
<D:mkcol xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:D="DAV:">
  <D:set>
    <D:prop>
      <D:resourcetype>
        <D:collection>
          <C:calendar-collection/>
        </D:collection>
      </D:resourcetype>
      <D:displayname>Yep
    </D:prop>
  </D:set>
</D:mkcol>

Deleting a calendar:

DELETE /calendars/pythoncaldav-test HTTP/1.1
Host: example.com
Accept-Encoding: identity

caldav

The version I just released is the very beginning of the project: it has basic functionality, but lacks many things, such as error handling and full support for the protocol. The documentation also needs a lot more work.

Example

I tried keeping the API very simple, and close to what an ORM would be used like, here’s an example:

import caldav
from caldav.lib.namespace import ns

# Principal url
url = "https://user:pass@hostname/user/Calendar"
vcal = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VEVENT
UID:1234567890
DTSTAMP:20100510T182145Z
DTSTART:20100512T170000Z
DTEND:20100512T180000Z
SUMMARY:This is an event
END:VEVENT
END:VCALENDAR
"""

client = caldav.DAVClient(url)
principal = caldav.Principal(url)
calendars = principal.calendars()
if len(calendars) > 0:
    calendar = calendars[0]
    print "Using calendar", calendar

    print "Renaming"
    calendar.set_properties({ns("D", "displayname"): "Test calendar",})
    print calendar.get_properties([ns("D", "displayname"),])

    event = caldav.Event(client, data = vcal, parent = calendar).save()
    print "Event", event, "created"

    print "Looking for events after 2010-05-01"
    results = calendar.date_search("20100501T000000Z")
    for event in results:
        print "Found", event

Links

I released caldav and its documentation on pypi, and the code is on bitbucket:

Contributions are welcome!

3 Responses

  1. Radu Savutiu says:

    Hi,
    I have been using your caldav client with success (0.1.3 thou).
    It also features a webdav client, which I have managed to use as a CardDav client :) (with very limited functionality – add a contact and delete contact).
    I cannot manage retrieving contacts thou, using SELECT WebDav command.
    Are you at all interested in implementing a CardDav client for Python?

  2. cyril says:

    Hi Radu, it’s great to receive feedback on this, thanks :)
    It could be a good idea to have a separate module for CardDAV, I’m not sure I will have the time to do that just now.
    I’m not quite sure what the issue could be for the select, I’ll send you an email for that.

Leave a Reply