.. include:: ========================================= VObject - An iCalendar and vCard Library ========================================= :Author: Jeffrey Harris :Date: $Date: 2006-02-10 $ .. image:: ui/chandler/OSAFLogo.png :alt: Open Source Applications Foundation logo .. This document has been placed in the public domain. .. |bullet| unicode:: U+02022 .. |mode| unicode:: U+00D8 .. capital o with stroke .. footer:: Addison, Texas |bullet| February 24, 2006 Start ===== You may have heard of vCard and vCalendar. Bad Name ======== You probably asked yourself: .. class:: incremental * Why not iThis and iThat? `That would be sexier.` Versit ====== Blame it on the Versit_ consortium. .. class:: incremental * The i screamers won for vCalendar 2.0, anyway * It's called iCalendar Standards ========= Who uses the various standards? .. class:: incremental * vCard 2.1 `- Palm` * vCard 3.0 `- vendors that like sane specifications` * vCalendar 1.0 - Palm * vCalendar 2.0 - vendors that believe in timezones Syntax ====== These formats have similar, odd, syntax. * Chandler needed to handle at least the later, IETF versions Not Invented Here ================= Attempting to avoid NIH syndrome, looked for existing options. They tended to be: .. class:: incremental * written in Perl, or * written in C with underwhelming Python bindings, or * tightly coupled to big codebases Genesis ======= So I had a thought. .. class:: center scale .. image:: images/overshoulder.jpg :alt: Jeffrey having a thought Goal ==== A library for contact and event data. * Apache licensed * native Python Name ==== Isn't vobject a boring name? .. class:: incremental * Yes * Can't blame this one on Versit_ * Please suggest a better one Failed to avoid NIH =================== Lots of Python iCalendar code written simultaneously. * SchoolTool_'s GPL library * Max M's LGPL icalendar_ package * vobject_, Apache licensed Features ======== * Line wrapping * Character escaping * Python tzinfo to VTIMEZONE conversion * DURATION to timedelta * DATE to date, DATE-TIME to datetime * Iterable recurrence rules, returning Python datetimes iCalendar data structures ========================= iCalendar maps nicely to XML. :: BEGIN:VEVENT DTSTART;TZID=US/Pacific:200602092000 END:VEVENT 200602092000 xCalendar ========= Why didn't they just use XML? .. class:: incremental * I have no clue. * OK, I do have a clue. XML hadn't taken off yet * xCalendar exists, not used much Parsing ======= vobject parses iCalendar-style syntax * creates a tree of simple Python objects * values are just unicode Simple data =========== At this point, the tree contains: * Generic objects, attributes are boring unicode We want: * Native Python objects based on context Transformation ============== Can they transform themselves? .. class:: center scale .. image:: images/superman.png :alt: Superman changing outfits Behaviors ========= Items in the tree can be assigned behaviors. .. class:: incremental * I'm told these should be called strategies * Tough * I like behavior better Behaviors Continued =================== Once a behavior is applied, a component: * Knows how to behave * Knows what behaviors its children should have Behaviors provide a transformToNative method. An ics file =========== .. sidebar:: BayPiggies.ics .. class:: tiny :: BEGIN:VCALENDAR VERSION:2.0 PRODID:Irrelevant BEGIN:VTIMEZONE TZID:US/Pacific ... [elided for brevity] END:VTIMEZONE BEGIN:VEVENT SUMMARY:BayPiggies UID:1234XYZ@foobar DTSTART;TZID=US/Pacific:20060209T193000 DTEND;TZID=US/Pacific:20060209T210000 RRULE:FREQ=MONTHLY;BYDAY=+2TH END:VEVENT END:VCALENDAR Parsing example =============== >>> import vobject >>> f = file('BayPiggies.ics') >>> cal = vobject.readOne(f) Working with trees ================== >>> ev = cal.vevent >>> ev.summary >>> ev.summary.value u'BayPiggies' Datetimes and timezones ======================= >>> start = cal.vevent.dtstart >>> print start.value 2006-02-09 19:30:00-08:00 >>> tz = start.value.tzinfo >>> tz >>> cal.vevent.dtend.value - start.value datetime.timedelta(0, 5400) Recurrence ========== >>> cal.vevent.rruleset >>> for dt in cal.vevent.rruleset[:3]: ... print dt 2006-02-09 19:30:00-08:00 2006-03-09 19:30:00-08:00 2006-04-13 19:30:00-07:00 iCalendar from scratch ====================== Of course, you can go the other direction. >>> import vobject >>> cal = vobject.iCalendar() >>> ev = cal.add('vevent') >>> start = ev.add('dtstart') iCalendar from scratch (2) ========================== >>> from datetime import datetime >>> start.value = datetime(2006,2,9,7,30, tzinfo = tz) >>> ev.add('summary').value = "BayPiggies" >>> cal.prettyPrint() VCALENDAR VEVENT DTSTART: 2006-02-09 07:30:00-08:00 SUMMARY: BayPiggies Serializing =========== Walking through the output: >>> lines = cal.serialize().splitlines() >>> print '\n'.join(lines[0:3]) BEGIN:VCALENDAR VERSION:2.0 PRODID:-//PYVOBJECT//NONSGML Version 1//EN Serializing timezones ===================== A VTIMEZONE is calculated from the tzinfo class. >>> print '\n'.join(lines[3:12]) BEGIN:VTIMEZONE TZID:US/Pacific BEGIN:STANDARD DTSTART:20001029T020000 RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 TZNAME:US/Pacific TZOFFSETFROM:-0700 TZOFFSETTO:-0800 END:STANDARD Generating required lines ========================= UID is required, so VEVENT's behavior generated one. >>> print '\n'.join(lines[20:]) BEGIN:VEVENT UID:20060210T024827Z-20213@Wind DTSTART;TZID=US/Pacific:20060209T073000 SUMMARY:BayPiggies END:VEVENT END:VCALENDAR Areas for improvement ===================== * Sprints - serializing and parsing * xCalendar * hCalendar * hCard * Working with multiple VEVENTs * More powerful recurrence expansion .. _Versit: http://en.wikipedia.org/wiki/Versit .. _SchoolTool: http://www.schooltool.org/ .. _icalendar: http://codespeak.net/icalendar/ .. _vobject: http://vobject.skyhouseconsulting.com/