Permalink
Browse files

Merge branch 'master' of git://github.com/kelleyk/biplist into kelley…

…k-master

Conflicts:
	biplist/__init__.py
  • Loading branch information...
wooster committed Jun 19, 2012
2 parents d8319c0 + 31419a5 commit 4bf73ec538040a4d5bcc4850d9a23666b407d975
Showing with 117 additions and 87 deletions.
  1. +3 −0 .gitignore
  2. +2 −0 AUTHORS
  3. +48 −37 biplist/__init__.py
  4. +8 −11 setup.py
  5. +2 −2 tests/test_invalid.py
  6. +2 −1 tests/test_utils.py
  7. +26 −18 tests/test_valid.py
  8. +21 −18 tests/test_write.py
  9. +5 −0 tox.ini
View
@@ -11,5 +11,8 @@ Icon*
# Emacs noise
*~
+# tox noise
+*.egg
+
# other noise
.svn
View
@@ -1 +1,3 @@
Andrew Wooster (andrew@planetaryscale.com)
+
+Ported to Python 3 by Kevin Kelley (kelleyk@kelleyk.net)
View
@@ -44,8 +44,8 @@
print "Not a plist:", e
"""
+import sys
from collections import namedtuple
-from cStringIO import StringIO
import calendar
import datetime
import math
@@ -54,6 +54,8 @@
import sys
import time
+import six
+
__all__ = [
'Uid', 'Data', 'readPlist', 'writePlist', 'readPlistFromString',
'writePlistToString', 'InvalidPlistException', 'NotBinaryPlistException'
@@ -67,7 +69,7 @@ class Uid(int):
def __repr__(self):
return "Uid(%d)" % self
-class Data(str):
+class Data(six.binary_type):
"""Wrapper around str types for representing Data values."""
pass
@@ -83,18 +85,18 @@ def readPlist(pathOrFile):
"""Raises NotBinaryPlistException, InvalidPlistException"""
didOpen = False
result = None
- if isinstance(pathOrFile, (str, unicode)):
+ if isinstance(pathOrFile, (six.binary_type, six.text_type)):
pathOrFile = open(pathOrFile, 'rb')
didOpen = True
try:
reader = PlistReader(pathOrFile)
result = reader.parse()
- except NotBinaryPlistException, e:
+ except NotBinaryPlistException as e:
try:
pathOrFile.seek(0)
result = plistlib.readPlist(pathOrFile)
result = wrapDataObject(result, for_binary=True)
- except Exception, e:
+ except Exception as e:
raise InvalidPlistException(e)
if didOpen:
pathOrFile.close()
@@ -109,7 +111,7 @@ def wrapDataObject(o, for_binary=False):
o = wrapDataObject(list(o), for_binary)
o = tuple(o)
elif isinstance(o, list):
- for i in xrange(len(o)):
+ for i in range(len(o)):
o[i] = wrapDataObject(o[i], for_binary)
elif isinstance(o, dict):
for k in o:
@@ -122,7 +124,7 @@ def writePlist(rootObject, pathOrFile, binary=True):
return plistlib.writePlist(rootObject, pathOrFile)
else:
didOpen = False
- if isinstance(pathOrFile, (str, unicode)):
+ if isinstance(pathOrFile, (six.binary_type, six.text_type)):
pathOrFile = open(pathOrFile, 'wb')
didOpen = True
writer = PlistWriter(pathOrFile)
@@ -132,22 +134,25 @@ def writePlist(rootObject, pathOrFile, binary=True):
return result
def readPlistFromString(data):
- return readPlist(StringIO(data))
+ return readPlist(six.BytesIO(data))
def writePlistToString(rootObject, binary=True):
if not binary:
rootObject = wrapDataObject(rootObject, binary)
- return plistlib.writePlistToString(rootObject)
+ if six.PY3:
+ return plistlib.writePlistToBytes(rootObject)
+ else:
+ return plistlib.writePlistToString(rootObject)
else:
- io = StringIO()
+ io = six.BytesIO()
writer = PlistWriter(io)
writer.writeRoot(rootObject)
return io.getvalue()
def is_stream_binary_plist(stream):
stream.seek(0)
header = stream.read(7)
- if header == 'bplist0':
+ if header == six.b('bplist0'):
return True
else:
return False
@@ -201,7 +206,7 @@ def readRoot(self):
offset_i += 1
self.setCurrentOffsetToObjectNumber(self.trailer.topLevelObjectNumber)
result = self.readObject()
- except TypeError, e:
+ except TypeError as e:
raise InvalidPlistException(e)
return result
@@ -387,7 +392,7 @@ def __repr__(self):
return "<BoolWrapper: %s>" % self.value
class PlistWriter(object):
- header = 'bplist00bybiplist1.0'
+ header = six.b('bplist00bybiplist1.0')
file = None
byteCounts = None
trailer = None
@@ -455,7 +460,7 @@ def writeRoot(self, root):
output = self.writeOffsetTable(output)
output += pack('!xxxxxxBBQQQ', *self.trailer)
self.file.write(output)
-
+
def wrapRoot(self, root):
if isinstance(root, bool):
if root is True:
@@ -469,7 +474,7 @@ def wrapRoot(self, root):
return HashableWrapper(n)
elif isinstance(root, dict):
n = {}
- for key, value in root.iteritems():
+ for key, value in six.iteritems(root):
n[self.wrapRoot(key)] = self.wrapRoot(value)
return HashableWrapper(n)
elif isinstance(root, list):
@@ -492,7 +497,7 @@ def check_key(key):
raise InvalidPlistException('Dictionary keys cannot be null in plists.')
elif isinstance(key, Data):
raise InvalidPlistException('Data cannot be dictionary keys in plists.')
- elif not isinstance(key, (str, unicode)):
+ elif not isinstance(key, (six.binary_type, six.text_type)):
raise InvalidPlistException('Keys must be strings.')
def proc_size(size):
@@ -514,7 +519,7 @@ def proc_size(size):
elif isinstance(obj, Uid):
size = self.intSize(obj)
self.incrementByteCount('uidBytes', incr=1+size)
- elif isinstance(obj, (int, long)):
+ elif isinstance(obj, six.integer_types):
size = self.intSize(obj)
self.incrementByteCount('intBytes', incr=1+size)
elif isinstance(obj, (float)):
@@ -525,7 +530,7 @@ def proc_size(size):
elif isinstance(obj, Data):
size = proc_size(len(obj))
self.incrementByteCount('dataBytes', incr=1+size)
- elif isinstance(obj, (str, unicode)):
+ elif isinstance(obj, (six.text_type, six.binary_type)):
size = proc_size(len(obj))
self.incrementByteCount('stringBytes', incr=1+size)
elif isinstance(obj, HashableWrapper):
@@ -544,7 +549,7 @@ def proc_size(size):
elif isinstance(obj, dict):
size = proc_size(len(obj))
self.incrementByteCount('dictBytes', incr=1+size)
- for key, value in obj.iteritems():
+ for key, value in six.iteritems(obj):
check_key(key)
self.computeOffsets(key, asReference=True)
self.computeOffsets(value, asReference=True)
@@ -573,18 +578,18 @@ def writeObject(self, obj, output, setReferencePosition=False):
object was written.
"""
def proc_variable_length(format, length):
- result = ''
+ result = six.b('')
if length > 0b1110:
result += pack('!B', (format << 4) | 0b1111)
result = self.writeObject(length, result)
else:
result += pack('!B', (format << 4) | length)
return result
- if isinstance(obj, unicode) and obj == u'':
+ if isinstance(obj, six.text_type) and obj == six.u(''):
# The Apple Plist decoder can't decode a zero length Unicode string.
- obj = ''
-
+ obj = six.b('')
+
if setReferencePosition:
self.referencePositions[obj] = len(output)
@@ -599,7 +604,7 @@ def proc_variable_length(format, length):
size = self.intSize(obj)
output += pack('!B', (0b1000 << 4) | size - 1)
output += self.binaryInt(obj)
- elif isinstance(obj, (int, long)):
+ elif isinstance(obj, six.integer_types):
bytes = self.intSize(obj)
root = math.log(bytes, 2)
output += pack('!B', (0b0001 << 4) | int(root))
@@ -616,15 +621,14 @@ def proc_variable_length(format, length):
elif isinstance(obj, Data):
output += proc_variable_length(0b0100, len(obj))
output += obj
- elif isinstance(obj, (str, unicode)):
- if isinstance(obj, unicode):
- bytes = obj.encode('utf_16_be')
- output += proc_variable_length(0b0110, len(bytes)/2)
- output += bytes
- else:
- bytes = obj
- output += proc_variable_length(0b0101, len(bytes))
- output += bytes
+ elif isinstance(obj, six.text_type):
+ bytes = obj.encode('utf_16_be')
+ output += proc_variable_length(0b0110, len(bytes)//2)
+ output += bytes
+ elif isinstance(obj, six.binary_type):
+ bytes = obj
+ output += proc_variable_length(0b0101, len(bytes))
+ output += bytes
elif isinstance(obj, HashableWrapper):
obj = obj.value
if isinstance(obj, (set, list, tuple)):
@@ -645,7 +649,7 @@ def proc_variable_length(format, length):
keys = []
values = []
objectsToWrite = []
- for key, value in obj.iteritems():
+ for key, value in six.iteritems(obj):
keys.append(key)
values.append(value)
for key in keys:
@@ -663,9 +667,16 @@ def proc_variable_length(format, length):
def writeOffsetTable(self, output):
"""Writes all of the object reference offsets."""
all_positions = []
- writtenReferences = self.writtenReferences.items()
- writtenReferences.sort(lambda x,y: cmp(x[1], y[1]))
+ writtenReferences = list(self.writtenReferences.items())
+ writtenReferences.sort(key=lambda x: x[1])
for obj,order in writtenReferences:
+ # Porting note: Elsewhere we deliberately replace empty unicdoe strings
+ # with empty binary strings, but the empty unicode string
+ # goes into writtenReferences. This isn't an issue in Py2
+ # because u'' and b'' have the same hash; but it is in
+ # Py3, where they don't.
+ if six.PY3 and obj == six.u(''):
+ obj = six.b('')
position = self.referencePositions.get(obj)
if position is None:
raise InvalidPlistException("Error while writing offsets table. Object not found. %s" % obj)
@@ -679,7 +690,7 @@ def binaryReal(self, obj):
return result
def binaryInt(self, obj, bytes=None):
- result = ''
+ result = six.b('')
if bytes is None:
bytes = self.intSize(obj)
if bytes == 1:
View
@@ -12,23 +12,20 @@
major, minor, micro, releaselevel, serial = sys.version_info
-if major == 2 and minor < 6:
- print("Python >= 2.6 is required to use this module.")
- sys.exit(1)
-elif major >= 3:
- print("There is no support for Python 3 yet in this module.")
+if major <= 1 or (major == 2 and minor < 6) or (major == 3 and minor < 2):
+ # N.B.: Haven't tested with older py3k versions.
+ print('This module supports Python 2 >= 2.6 and Python 3 >= 3.2.')
sys.exit(1)
author = 'Andrew Wooster'
email = 'andrew@planetaryscale.com'
-version = '0.4'
+version = '0.5'
desc = 'biplist is a library for reading/writing binary plists.'
setup(
name = 'biplist',
version = version,
- url = 'https://github.com/wooster/biplist',
- download_url = 'https://github.com/wooster/biplist/downloads/biplist-0.4.tar.gz',
+ url = 'https://github.com/kelleyk/py3k-biplist',
license = 'BSD',
description = desc,
long_description =
@@ -38,7 +35,7 @@
format for property lists on OS X. This is a library for generating binary
plists which can be read by OS X, iOS, or other clients.
-This module requires Python 2.6 or higher.""",
+This module requires Python 2.6 or higher or Python 3.2 or higher.""",
author = author,
author_email = email,
packages = find_packages(),
@@ -55,6 +52,6 @@
],
setup_requires = ['nose', 'coverage'],
test_suite = 'nose.collector',
- install_requires = [
- ],
+ install_requires = ['six'],
+ requires = ['six'],
)
View
@@ -17,14 +17,14 @@ def testEmptyFile(self):
def testTooShort(self):
try:
- readPlistFromString("bplist0")
+ readPlistFromString(six.b("bplist0"))
self.fail("Should not successfully read plist which is too short.")
except InvalidPlistException as e:
pass
def testInvalid(self):
try:
- readPlistFromString("bplist0-------------------------------------")
+ readPlistFromString(six.b("bplist0-------------------------------------"))
self.fail("Should not successfully read invalid plist.")
except InvalidPlistException as e:
pass
View
@@ -1,6 +1,7 @@
import os
import subprocess
import sys
+import six
def data_path(path):
return os.path.join(os.path.dirname(globals()["__file__"]), 'data', path)
@@ -12,7 +13,7 @@ def run_command(args, verbose = False):
p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
stdin, stdout = (p.stdin, p.stdout)
output = stdout.read()
- output = output.strip("\n")
+ output = output.strip(six.b("\n"))
status = stdin.close()
p.wait()
return p.returncode, output
Oops, something went wrong.

0 comments on commit 4bf73ec

Please sign in to comment.