Want to try the library? Here's how you get started.
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.
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.
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()) print(calendar)Contents
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.
BEGIN:<COMPONENT> ... ... ... END:<COMPONENT>where <COMPONENT> is the name of the component. The component block may in it's turn contain properties and/or components.
<PROPERTY>[VALUE=<TYPE>]:<VALUE> [ 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.
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.
BEGIN:SCUM SOMEPROPERTY:This is the value of SOMEPROPERTY. ANOTHERPROPERTY;VALUE=DATE:20021115 END:SCUMNow, the same component with properties and sub components.
BEGIN:SCUM SOMEPROPERTY:This is the value of SOMEPROPERTY. ANOTHERPROPERTY;VALUE=DATE:20021115 BEGIN:SUBSCUM THIRDPROPERTY:You can have properties in sub components too! THE-FOXY-PROPERTY:Properties can contain alpha and some non-alpha characters. END:SUBSCUM END:SCUMContents
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.
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. calendar.validate() # Dump it! print(calendar)
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! print(calendar)Contents
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.
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.
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.Contents
If you need to download specific parts, read specifications, report bugs, etc.
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.
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 http://www.gnu.org/licenses/gpl.txt!Contents