Small Python-PDI tutorial

Author: Peter Gebauer <peter at restamus dot org>



1 Getting started

Want to try the library? Here's how you get started.

1.1 Why does this package exist?

The project started out as a way for me to learn Python, but also because I wanted the ability to access vCard, vCalendar and iCalendar formats. The actual file formats in themselves are extremely simple compared to other meta-data formats like XML.

vCard and iCalendar is widely used on the Internet and not many free softwares support them yet. I'm hoping this package will at least bring those standards to the Python community.

1.2 Installing Python-PDI

As with all Python stuff, adding a path to where the pdi package roams is enough. So, if your pdi package is located in /usr/local/lib/python2.2/site-packages/pdi you should include /usr/local/lib/python2.2/site-packages/ in your PYTHONPATH.

1.3 Running the examples

You can try if it works by runnning one of examples in the examples directory that came with the distribution of Python-PDI.

One of the examples looks like this, you can try this code.

from pdi.vcalendar import VCalendar
import pdi.parser

calendar = pdi.parser.fromFile("swe-holidays.ics", ICalendar())


2 The PDI file formats

PDI file formats are meta-data carriers. All components and properties must be started at the beginning of each line and end with a CRLF. That means component and property definitions cannot span over several lines. Property values, however, can.

2.1 Components

where <COMPONENT> is the name of the component. The component block may in it's turn contain
properties and/or components.

2.2 Properties

[    content lines
where <PROPERTY> is the name of the property and <VALUE> holds the value. Optional VALUE will explicitly specify the type.

When properties have values need to span over several lines you can issue content line mode. You do this by indenting the next line with one space (US ASCII 32) or one tab (US ASCII 9). Each content line is ended the same way as components and properties in general, with a CRLF.

2.3 Examples

Here's a simple component called SCUM.


The same component with some properties in it. One property of unknown type and one date-type property.

Now, the same component with properties and sub components.
THIRDPROPERTY:You can have properties in sub components too!
THE-FOXY-PROPERTY:Properties can contain alpha and some non-alpha characters.

3 Using the API

This API contains some predefined components and property types as well as utilities for parsing PDI data. The distribution of Python-PDI should have come with example files (in the examples directory) that are runnable.

3.1 Using the components

The following example will create a calendar and print it. Instead of sending the output the stdout you can send it to a file.

from pdi.icalendar import ICalendar, VEvent
from pdi.core import UnknownProperty

# Create a calendar and add some properties to it
calendar = ICalendar()
calendar.addProperties([UnknownProperty('PRODID', '1234-50'),
                        UnknownProperty('VERSION', '2.0'),
                        UnknownProperty('CALSCALE', 'GREGORIAN')

# Add an event to the calendar and add properties to the event
event = calendar.addComponent(VEvent())
event.addProperties([UnknownProperty('UID', '12837-64316346-346346-346'),
                     UnknownProperty('SUMMARY', 'Meeting with Ewing Oil.')

# Validate! Make sure we have everything we need.
# We can skip the validation, though.

# Dump it!

3.2 Parsing data

This example will populate an ICalendar object with data from a file.

from pdi.icalendar import ICalendar
import pdi.parser

# Parse the damn thing.
calendar = pdi.parser.fromFile("swe-holidays.ics", ICalendar())

# Dump it!


4 Extending the API

Because of the constant flood of new features constantly being added the API has been designed so that it is easy to keep with the changes.

Unfortunately, almost every software vendor thinks they are smarter than the people that invented the "original" format. This is why things like HTML, XML and SQL comes in so many different flavors, even though exakt and central standards exist. The same goes for vCard and iCalendar formats.

If you want, as an example, Outlook-specific stuff to work with your iCalendar application you can subclass ICalendar and create your own OutlookCalendar class complete with subcomponents, properties, and property types specific to Outlooks iCalendar-style format.

4.1 Extending components

When extending components it's important that you find out what differs from already existing standards with the one you are trying to implement. Could be that it works with the existing vCard or iCalendar formats, could be it doesn't. Read the specs carefully before proceeding.

To add functionality to the already existing iCalendar format, all you got to do is extend the existing class:

from pdi.vcalendar import VCalendar, VJournal
from pdi.core import Component

class MyCalendar(VCalendar):

    def __init__(self, parent = None):
        super(MyCalendar, self).__init__(parent)
        ... Add your MUST, MAY, RECOMMEND
        ... and NOT types of subcomponents and
        ... properties here!

Adding subcomponents and properties to your new format is essential since that is what the changes are made of. We will now add three new properties and disallow journal subcomponents:

        ... this is inside your __init__
        # Add two new mandatory properties
        self.registerProperties(['SENDER', 'VERIFICATION'], pdi.core.RULE_MUST)
        # Add a property that is allowed, but not mandatory
        self.registerProperty('DEALER', pdi.core.RULE_MAY)

We will now disallow journal subcomponents:

        ... still inside your __init__
        # Disallow journal components, because our app really doesn't want them
        self.registerComponent(VJournal, pdi.core.RULE_NOT)

That is pretty much how these objects are extended. Perhaps, in a future, these rules can be read from a DTD-style file, but for now coding the rules is the only way.

4.2 Adding new types

The existing types should be sufficient, but if you feel the need to create new types, it is possible.

The following example will create a new type for a specific type of unique ID's.

from pdi.core import Component
import re

class SpecialUIDProperty(Property):

    # This method is called whenever it's value is set when it's added to component
    # from parsed data.
    def _validate(self, value):
        # We require a 16 digit, hexadecimal number!
        regExp = re.compile("^[0-9][A-F]")
        if len(value) != 16 or regExp.match(value):
            self.invalidValue("must be 16 digit hexadecimal number", value)
            return None
        return 1

    # This is the type name that will be used in files.
    def getType(self):  
        return "SPEC-UID"

If you need to return the value in a special type of format you can override the pdi.core.Property.getValue(self) method.


5 Other resources

If you need to download specific parts, read specifications, report bugs, etc.

5.1 Reference manual (epydoc)

The epydoc reference manual will be helpful for those looking to extend components or add new types. It is available on the Savannah project site.

5.2 Savannah project site

5.3 RFC's and specifications

6 License

Python-PDI - Library for Personal Data Interchange. Copyright (C) 2002-2003 Peter Gebauer

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

Read the file COPYING that comes with the distribution of this software or download it from!

Last modified: Sun Nov 24 14:37:06 CET 2002