SF patch# 1769016 by James Brotchie.

Change plistlib to use bytes instead of strings.
Fix test_plistlib accordingly.
This commit is contained in:
Guido van Rossum 2007-08-07 14:26:40 +00:00
parent ca8dd9182e
commit cd869d8d41
2 changed files with 45 additions and 53 deletions

View file

@ -12,8 +12,8 @@
with a file name or a (readable) file object as the only argument. It
returns the top level object (again, usually a dictionary).
To work with plist data in strings, you can use readPlistFromString()
and writePlistToString().
To work with plist data in bytes objects, you can use readPlistFromBytes()
and writePlistToBytes().
Values can be strings, integers, floats, booleans, tuples, lists,
dictionaries, Data or datetime.datetime objects. String values (including
@ -21,7 +21,7 @@
UTF-8.
The <data> plist type is supported through the Data class. This is a
thin wrapper around a Python string.
thin wrapper around a Python bytes object.
Generate Plist example:
@ -36,8 +36,8 @@
aTrueValue=True,
aFalseValue=False,
),
someData = Data("<binary gunk>"),
someMoreData = Data("<lots of binary gunk>" * 10),
someData = Data(b"<binary gunk>"),
someMoreData = Data(b"<lots of binary gunk>" * 10),
aDate = datetime.datetime.fromtimestamp(time.mktime(time.gmtime())),
)
# unicode keys are possible, but a little awkward to use:
@ -52,7 +52,7 @@
__all__ = [
"readPlist", "writePlist", "readPlistFromString", "writePlistToString",
"readPlist", "writePlist", "readPlistFromBytes", "writePlistToBytes",
"readPlistFromResource", "writePlistToResource",
"Plist", "Data", "Dict"
]
@ -60,7 +60,7 @@
import binascii
import datetime
from cStringIO import StringIO
from io import BytesIO
import re
@ -71,7 +71,7 @@ def readPlist(pathOrFile):
"""
didOpen = 0
if isinstance(pathOrFile, str):
pathOrFile = open(pathOrFile)
pathOrFile = open(pathOrFile, 'rb')
didOpen = 1
p = PlistParser()
rootObject = p.parse(pathOrFile)
@ -86,7 +86,7 @@ def writePlist(rootObject, pathOrFile):
"""
didOpen = 0
if isinstance(pathOrFile, str):
pathOrFile = open(pathOrFile, "w")
pathOrFile = open(pathOrFile, 'wb')
didOpen = 1
writer = PlistWriter(pathOrFile)
writer.writeln("<plist version=\"1.0\">")
@ -96,16 +96,16 @@ def writePlist(rootObject, pathOrFile):
pathOrFile.close()
def readPlistFromString(data):
"""Read a plist data from a string. Return the root object.
def readPlistFromBytes(data):
"""Read a plist data from a bytes object. Return the root object.
"""
return readPlist(StringIO(data))
return readPlist(BytesIO(data))
def writePlistToString(rootObject):
"""Return 'rootObject' as a plist-formatted string.
def writePlistToBytes(rootObject):
"""Return 'rootObject' as a plist-formatted bytes object.
"""
f = StringIO()
f = BytesIO()
writePlist(rootObject, f)
return f.getvalue()
@ -145,7 +145,6 @@ def writePlistToResource(rootObject, path, restype='plst', resid=0):
class DumbXMLWriter:
def __init__(self, file, indentLevel=0, indent="\t"):
self.file = file
self.stack = []
@ -172,9 +171,12 @@ def simpleElement(self, element, value=None):
def writeln(self, line):
if line:
self.file.write(self.indentLevel * self.indent + line + "\n")
else:
self.file.write("\n")
# plist has fixed encoding of utf-8
if isinstance(line, str):
line = line.encode('utf-8')
self.file.write(self.indentLevel * self.indent)
self.file.write(line)
self.file.write('\n')
# Contents should conform to a subset of ISO 8601
@ -355,13 +357,15 @@ def _encodeBase64(s, maxlinelength=76):
for i in range(0, len(s), maxbinsize):
chunk = s[i : i + maxbinsize]
pieces.append(binascii.b2a_base64(chunk))
return "".join(pieces)
return b''.join(pieces)
class Data:
"""Wrapper for binary data."""
def __init__(self, data):
if not isinstance(data, bytes):
raise TypeError("data must be as bytes")
self.data = data
def fromBase64(cls, data):
@ -426,11 +430,7 @@ def addObject(self, value):
self.stack[-1].append(value)
def getData(self):
data = "".join(self.data)
try:
data = data.encode("ascii")
except UnicodeError:
pass
data = ''.join(self.data)
self.data = []
return data

View file

@ -9,7 +9,7 @@
# This test data was generated through Cocoa's NSDictionary class
TESTDATA = """<?xml version="1.0" encoding="UTF-8"?>
TESTDATA = b"""<?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">
@ -109,9 +109,9 @@ def _create(self):
aFalseValue=False,
deeperDict=dict(a=17, b=32.5, c=[1, 2, "text"]),
),
someData = plistlib.Data("<binary gunk>"),
someMoreData = plistlib.Data("<lots of binary gunk>\0\1\2\3" * 10),
nestedData = [plistlib.Data("<lots of binary gunk>\0\1\2\3" * 10)],
someData = plistlib.Data(b"<binary gunk>"),
someMoreData = plistlib.Data(b"<lots of binary gunk>\0\1\2\3" * 10),
nestedData = [plistlib.Data(b"<lots of binary gunk>\0\1\2\3" * 10)],
aDate = datetime.datetime(2004, 10, 26, 10, 33, 33),
)
pl['\xc5benraa'] = "That was a unicode key."
@ -128,40 +128,32 @@ def test_io(self):
pl2 = plistlib.readPlist(test_support.TESTFN)
self.assertEqual(dict(pl), dict(pl2))
def test_string(self):
def test_bytes(self):
pl = self._create()
data = plistlib.writePlistToString(pl)
pl2 = plistlib.readPlistFromString(data)
data = plistlib.writePlistToBytes(pl)
pl2 = plistlib.readPlistFromBytes(data)
self.assertEqual(dict(pl), dict(pl2))
data2 = plistlib.writePlistToString(pl2)
data2 = plistlib.writePlistToBytes(pl2)
self.assertEqual(data, data2)
def test_appleformatting(self):
pl = plistlib.readPlistFromString(TESTDATA)
data = plistlib.writePlistToString(pl)
pl = plistlib.readPlistFromBytes(TESTDATA)
data = plistlib.writePlistToBytes(pl)
self.assertEqual(data, TESTDATA,
"generated data was not identical to Apple's output")
def test_appleformattingfromliteral(self):
pl = self._create()
pl2 = plistlib.readPlistFromString(TESTDATA)
pl2 = plistlib.readPlistFromBytes(TESTDATA)
self.assertEqual(dict(pl), dict(pl2),
"generated data was not identical to Apple's output")
def test_stringio(self):
from StringIO import StringIO
f = StringIO()
def test_bytesio(self):
from io import BytesIO
b = BytesIO()
pl = self._create()
plistlib.writePlist(pl, f)
pl2 = plistlib.readPlist(StringIO(f.getvalue()))
self.assertEqual(dict(pl), dict(pl2))
def test_cstringio(self):
from cStringIO import StringIO
f = StringIO()
pl = self._create()
plistlib.writePlist(pl, f)
pl2 = plistlib.readPlist(StringIO(f.getvalue()))
plistlib.writePlist(pl, b)
pl2 = plistlib.readPlist(BytesIO(b.getvalue()))
self.assertEqual(dict(pl), dict(pl2))
def test_controlcharacters(self):
@ -170,17 +162,17 @@ def test_controlcharacters(self):
testString = "string containing %s" % c
if i >= 32 or c in "\r\n\t":
# \r, \n and \t are the only legal control chars in XML
plistlib.writePlistToString(testString)
plistlib.writePlistToBytes(testString)
else:
self.assertRaises(ValueError,
plistlib.writePlistToString,
plistlib.writePlistToBytes,
testString)
def test_nondictroot(self):
test1 = "abc"
test2 = [1, 2, 3, "abc"]
result1 = plistlib.readPlistFromString(plistlib.writePlistToString(test1))
result2 = plistlib.readPlistFromString(plistlib.writePlistToString(test2))
result1 = plistlib.readPlistFromBytes(plistlib.writePlistToBytes(test1))
result2 = plistlib.readPlistFromBytes(plistlib.writePlistToBytes(test2))
self.assertEqual(test1, result1)
self.assertEqual(test2, result2)