# Python plistservices Module

© 2003 Sarwat Khan, All rights reserved.
Read the License.text file for permitted use and legal disclaimer.

## Table of Contents

- About
- Installing
- Using
- To Do
- Future
- History

## About

plistservices allows you to parse and create CoreFoundation XML Property List objects. Additionally, it provides useful Cocoa-style Date and Data classes. The Date class (which is a subclass of Python 2.3’s datetime.datetime) implements NSDate’s reference date functions, which can be useful when using plists produced by logic in Cocoa software. The Data class is a generic wrapper for string-bytes and is used by plistservices to identify objects that need to be written within <data> tags using base64 encoding instead of as Unicode strings.

Python 2.3 includes plistlib which also offers reading and writing of CoreFoundation property list data. However, the plistlib included with Python 2.3.0 is a bit old and doesn’t support anything other than dictionaries as the root object. Also, it won’t parse dates without PyXML installed (specifically, xml.utils.iso8601. This seems to be a bit of a trick to install on Python 2.3). If you need date support, full plist support, or if using a programming interface that’s very similar to Cocoa is important (because you’re porting code from PyObjC, for example), plistservices is a suitable choice.

### Property List Objects

Property list types are the following: str, unicode, dict, tuple, list, int, long, float, bool, datetime, and plistservices.Data. Additionally, only str and unicode can be used for dict keys. If you need to store other types of data in your XML, you can use pickle to encode and decode your data within Data objects.

### Feature Checklist

- Pure Python module
- Supports any kind of property list file, not just dictionaries
- Supports parsing date objects without needing extra modules
- Includes convenient Cocoa-style Date and Data classes
- The Date class supports parsing ISO 8601 strings as datetime objects
- Full Unicode support

## Installing

Installing is just a matter of giving the install command to setup.py,

> `

>     % sudo python setup.py install

> `

If you’ve never installed a Python module before I suggest you read up on distutils. Python documentation is never direct but you’ll learn something.

### Requires Python 2.3’s datetime Module

plistservices’ Date object inherits Python’s datetime.datetime class, and it’s what’s used as the implementation for the Date property list type. The code was not designed to gracefully work without Python 2.3, but it wouldn’t be that hard to slice out the Date code all together.

If you have a few megabytes to spare, it may be easier to install Python 2.3.

## Using plistservices

There are two functions, `dataFromPropertyList` and `propertyListFromData` to serialize python objects to and from Data objects. So the only things you need to learn are how to use Data objects and those two functions.

Data objects themselves are convenient to work with. For any instance of a Data class, you can send it a `bytes` message to get the raw string that the data object represents. You can create data objects using the Data class methods `dataWithString`, `dataWithContentsOfFile`, and `dataWithOpenFile`. Or you can construct one StringData or FileData objects directly using their init methods.

### Hello, world

Here’s a basic example of creating an XML plist from a Python object,

>     >>> import plistservices
>     >>> from plistservices import Data, Date
>     >>> print plistservices.dataFromPropertyList("Hello, world!").bytes()
>     <?xml version="1.0" encoding="UTF-8"?>
>     <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
>     <plist version="1.0">
>     <string>Hello, world!</string>
>     </plist>

`dataFromPropertyList` expects one of the property list types mentioned before, and returns a plistservices.Data object as a result, or None if it failed. In this example, a `bytes` message was sent to the resulting data object to get the string of XML bytes, which became the target of the `print` statement.

### Data Objects

`dataFromPropertyList` and `propertyListFromData` convert Python objects to and from Data objects. Data objects can be created from a string or a file, and can have their data extracted to a string or saved to a file.

#### Data

Data’s an abstract class. StringData and FileData are concrete subclasses. They implement __init__, __len__, and bytes.

+ (Data) dataWithString:string
  Returns a new Data object that represents the bytes in the given string.
+ (Data) dataWithContentsOfFile:(str)filePath
  Returns a new Data object for the contents of the file specified by filePath. If a file object could not be created from filePath, None is returned.
+ (Data) dataWithOpenFile:(file)foo
  Returns a new Data object whose bytes() accessor will return the data in the given file.
- (str) bytes
  Returns the string of bytes that the Data object represents.
- (None) writeToFile:(str)filePath
  Writes the data to a file specified by the given path. Lets exceptions be raised if they want to.
- (str) description
  Returns a printable, NSData style description of the data.
- (str) cfDescription
  Returns a printable, CFData style description of the data, which also includes the length of the data.
__str__
  Returns a printable, NSData style description of the data. The result is truncated if the length of the data is larger than 96 bytes.
__repr__
  Returns the result of self.description().

### Serializing and Deserializing Data as Property Lists

The plistservices module offers two functions to do the dirty work.

(StringData) dataFromPropertyList:plist
  Returns a Data object with an XML/UTF-8 representation of plist. If plist contains non-plist types (or is not one itself; see the introduction for a rundown on what plist types are), they are represented in the resulting XML as string objects and the function posts a RuntimeWarning.
(object) propertyListFromData:(Data)data
  Returns a property list object from the XML contained in data, or None if the data was invalid property list XML. Posts a UserWarning if it returns None.

You can have `dataFromPropertyList` throw an exception instead returning None in a few ways. One method is by configuring the Python warnings module to filter the `RuntimeWarning` that the function issues,

> `

>     import warnings
>     warnings.filterwarnings("error", category=UserWarning, module='plistservices')

> `

The other way is to call the function differently; pass `noisyErrors=True` to the function and it will raise an unpredictable exception instead of returning None.

### Date and TimeInterval Objects

The plistservices module includes subclasses of datetime.datetime and datetime.timedelta in order to provide some new class methods and a few utility instance methods.

#### Date (datetime.datetime)

Includes a class method to parse ISO 8601 strings and methods to create and compare dates against references dates 1970/1/1 and 2001/1/1.

+ (Date) dateFromStandard8601String:string
  See http://www.w3.org/TR/NOTE-datetime for details or the docstring.
+ (Date) dateWithTimeIntervalSinceReferenceDate:(datetime.timedelta)td
  The reference date is 2001/1/1.
- (TimeInterval) timeIntervalSinceReferenceDate
  Returns the time interval of self since the reference date of 2001/1/1.
+ (Date) dateWithTimeIntervalSince1970:(datetime.timedelta)td
  Description forthcoming.
- (TimeInterval) timeIntervalSince1970
  Description forthcoming.

#### TimeInterval (datetime.timedelta)

Adds the ability to easily determine the number of seconds a time delta duration represents, allowing you to use the result from Date’s reference date methods as Cocoa’s NSTimeInterval stuff.

- (float) duration
  The total duration in seconds that the timedelta instance represents.
+ (float) durationForTimeDelta:(datetime.timedelta)foo
  The total duration in seconds that the timedelta instance `foo` represents.
+ (TimeInterval) timeIntervalWithTimeDelta:(datetime.timedelta)foo
  Creates a TimeInterval object from a timedelta object. This is just so you can send timedelta instances `duration` messages.

## To Do

- ?

## Future

Description forthcoming.

## History

- 2003/8/8: First writeup.
- 2003/9/21: v2: Date.dateWithDateTime wasn’t set as a class method; Date.dateFromStandard8601String always returns a Date instance instead of datetime.datetime.