--- /tmp/plistlib.py 2010-04-20 20:59:37.000000000 +0000 +++ plistlib.py 2011-02-02 18:56:26.000000000 +0000 @@ -81,15 +81,17 @@ return rootObject -def writePlist(rootObject, pathOrFile): +def writePlist(rootObject, pathOrFile, ignoreNone=False): """Write 'rootObject' to a .plist file. 'pathOrFile' may either be a - file name or a (writable) file object. + file name or a (writable) file object. If 'ignoreNone' is set then + the writer will delete keys from the plist file that have a value of + None. Without this a TypeError is raised when None is encountered. """ didOpen = 0 if isinstance(pathOrFile, (str, unicode)): pathOrFile = open(pathOrFile, "w") didOpen = 1 - writer = PlistWriter(pathOrFile) + writer = PlistWriter(pathOrFile, ignoreNone=ignoreNone) writer.writeln("") writer.writeValue(rootObject) writer.writeln("") @@ -103,11 +105,12 @@ return readPlist(StringIO(data)) -def writePlistToString(rootObject): - """Return 'rootObject' as a plist-formatted string. +def writePlistToString(rootObject, ignoreNone=False): + """Return 'rootObject' as a plist-formatted string. `ignoreNone` is the + same as writePlist. """ f = StringIO() - writePlist(rootObject, f) + writePlist(rootObject, f, ignoreNone) return f.getvalue() @@ -229,9 +232,10 @@ class PlistWriter(DumbXMLWriter): - def __init__(self, file, indentLevel=0, indent="\t", writeHeader=1): + def __init__(self, file, indentLevel=0, indent="\t", writeHeader=1, ignoreNone=False): if writeHeader: file.write(PLISTHEADER) + self.ignoreNone = ignoreNone DumbXMLWriter.__init__(self, file, indentLevel, indent) def writeValue(self, value): @@ -277,6 +281,8 @@ for key, value in items: if not isinstance(key, (str, unicode)): raise TypeError("keys must be strings") + if self.ignoreNone and value is None: + continue self.simpleElement("key", key) self.writeValue(value) self.endElement("dict") --- /mnt/home/bob/Python-2.7.1/Lib/test/test_plistlib.py 2010-04-21 06:00:35.000000000 +0000 +++ test_plistlib.py 2011-02-02 19:04:16.000000000 +0000 @@ -163,6 +163,33 @@ pl2 = plistlib.readPlist(StringIO(f.getvalue())) self.assertEqual(dict(pl), dict(pl2)) + def test_writing_none(self): + """Tests that the ignoreNone flag is working properly. + + Generates plist files using writePlistToString() and writePlist(). + Verifies that without ignoreNone a TypeError is raised and that + with ignoreNone generation succeeds. Also verifies that the two + methods are working the same. + """ + from StringIO import StringIO + d = { + 'key1': 'Something juicy', + 'key2': None, + } + self.assertRaises(TypeError, plistlib.writePlistToString, d) + str_output = plistlib.writePlistToString(d, ignoreNone=True) + + f = StringIO() + self.assertRaises(TypeError, plistlib.writePlist, d, f) + + f = StringIO() + plistlib.writePlist(d, f, ignoreNone=True) + file_output = f.getvalue() + + self.assertEqual(str_output, file_output) + + plistlib.readPlistFromString(str_output) + def test_controlcharacters(self): for i in range(128): c = chr(i)