Hello community,

here is the log from the commit of package python3-biplist for openSUSE:Factory 
checked in at 2016-02-01 19:57:23
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python3-biplist (Old)
 and      /work/SRC/openSUSE:Factory/.python3-biplist.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python3-biplist"

Changes:
--------
--- /work/SRC/openSUSE:Factory/python3-biplist/python3-biplist.changes  
2015-01-14 11:44:42.000000000 +0100
+++ /work/SRC/openSUSE:Factory/.python3-biplist.new/python3-biplist.changes     
2016-02-01 19:57:40.000000000 +0100
@@ -1,0 +2,26 @@
+Mon Feb  1 04:12:01 UTC 2016 - [email protected]
+
+- specfile:
+  * update copyright year
+  * enabled test for all distros
+  * switch to setuptools
+
+- update to version 1.0.1:
+  * Adding back in Python 2.6 support. This will be removed again in a
+    future version.
+
+- changes from version 1.0.0:
+  * This release changes the type of Uid from a subclass of int to a
+    subclass of object.
+  * This change was made to address GitHub issue #9 Ints are being
+    turned into Uids and vice versa when both are present in a plist.
+    + This release also bumps the minimum supported Python versions to
+    2.7 and 3.4.
+
+- changes from version 0.9.1:
+  * Fixes GitHub issue #8 ERROR: testLargeDates
+    (test_valid.TestValidPlistFile)
+  * Fixes #6 Empty Data object converted as empty string
+  * Creates 1-byte strings when possible, per PR #4
+
+-------------------------------------------------------------------

Old:
----
  biplist-0.9.tar.gz

New:
----
  biplist-1.0.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python3-biplist.spec ++++++
--- /var/tmp/diff_new_pack.SXtDwL/_old  2016-02-01 19:57:41.000000000 +0100
+++ /var/tmp/diff_new_pack.SXtDwL/_new  2016-02-01 19:57:41.000000000 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python3-biplist
 #
-# Copyright (c) 2015 SUSE LINUX Products GmbH, Nuernberg, Germany.
+# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -17,7 +17,7 @@
 
 
 Name:           python3-biplist
-Version:        0.9
+Version:        1.0.1
 Release:        0
 Url:            https://github.com/wooster/biplist
 Summary:        A library for reading/writing binary plists
@@ -28,8 +28,8 @@
 BuildRequires:  python3
 BuildRequires:  python3-coverage
 BuildRequires:  python3-devel
-BuildRequires:  python3-distribute
 BuildRequires:  python3-nose
+BuildRequires:  python3-setuptools
 BuildRequires:  python3-six
 BuildArch:      noarch
 
@@ -50,10 +50,7 @@
 python3 setup.py install --prefix=%{_prefix} --root=%{buildroot}
 
 %check
-# Failed on Factory, need to be fixed but does not really critical
-%if 0%{?suse_version} < 1230
 python3 setup.py test
-%endif
 
 %files
 %defattr(-,root,root,-)

++++++ biplist-0.9.tar.gz -> biplist-1.0.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/biplist-0.9/PKG-INFO new/biplist-1.0.1/PKG-INFO
--- old/biplist-0.9/PKG-INFO    2014-10-26 20:09:20.000000000 +0100
+++ new/biplist-1.0.1/PKG-INFO  2016-01-11 09:07:10.000000000 +0100
@@ -1,19 +1,19 @@
 Metadata-Version: 1.1
 Name: biplist
-Version: 0.9
+Version: 1.0.1
 Summary: biplist is a library for reading/writing binary plists.
 Home-page: https://bitbucket.org/wooster/biplist
 Author: Andrew Wooster
 Author-email: [email protected]
 License: BSD
-Download-URL: 
https://bitbucket.org/wooster/biplist/downloads/biplist-0.9.tar.gz
+Download-URL: 
https://bitbucket.org/wooster/biplist/downloads/biplist-1.0.1.tar.gz
 Description: `biplist` is a binary plist parser/generator for Python.
         
         Binary Property List (plist) files provide a faster and smaller 
serialization
         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 or Python 3.2 or higher.
+        This module requires Python 2.6 or higher or Python 3.4 or higher.
 Platform: UNKNOWN
 Classifier: Development Status :: 5 - Production/Stable
 Classifier: Intended Audience :: Developers
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/biplist-0.9/biplist/__init__.py 
new/biplist-1.0.1/biplist/__init__.py
--- old/biplist-0.9/biplist/__init__.py 2014-10-26 20:03:11.000000000 +0100
+++ new/biplist-1.0.1/biplist/__init__.py       2016-01-11 08:41:21.000000000 
+0100
@@ -44,13 +44,12 @@
         print "Not a plist:", e
 """
 
-import sys
 from collections import namedtuple
 import datetime
 import io
 import math
 import plistlib
-from struct import pack, unpack
+from struct import pack, unpack, unpack_from
 from struct import error as struct_error
 import sys
 import time
@@ -79,23 +78,41 @@
 # Apple uses Jan 1, 2001 as a base for all plist date/times.
 apple_reference_date = datetime.datetime.utcfromtimestamp(978307200)
 
-class Uid(int):
+class Uid(object):
     """Wrapper around integers for representing UID values. This
        is used in keyed archiving."""
+    integer = 0
+    def __init__(self, integer):
+        self.integer = integer
+    
     def __repr__(self):
-        return "Uid(%d)" % self
+        return "Uid(%d)" % self.integer
+    
+    def __eq__(self, other):
+        if isinstance(self, Uid) and isinstance(other, Uid):
+            return self.integer == other.integer
+        return False
+    
+    def __cmp__(self, other):
+        return self.integer - other.integer
+    
+    def __lt__(self, other):
+        return self.integer < other.integer
+    
+    def __hash__(self):
+        return self.integer
+    
+    def __int__(self):
+        return int(self.integer)
 
 class Data(bytes):
-    """Wrapper around str types for representing Data values."""
-    pass
+    """Wrapper around bytes to distinguish Data values."""
 
 class InvalidPlistException(Exception):
     """Raised when the plist is incorrectly formatted."""
-    pass
 
 class NotBinaryPlistException(Exception):
     """Raised when a binary plist was expected but not encountered."""
-    pass
 
 def readPlist(pathOrFile):
     """Raises NotBinaryPlistException, InvalidPlistException"""
@@ -379,7 +396,7 @@
     def readAsciiString(self, length):
         result = unpack("!%ds" % length, 
self.contents[self.currentOffset:self.currentOffset+length])[0]
         self.currentOffset += length
-        return result
+        return str(result.decode('ascii'))
     
     def readUnicode(self, length):
         actual_length = length*2
@@ -426,7 +443,9 @@
                 result = int.from_bytes(data, 'big')
             else:
                 for byte in data:
-                    result = (result << 8) | unpack('>B', byte)[0]
+                    if not isinstance(byte, int): # Python3.0-3.1.x return 
ints, 2.x return str
+                        byte = unpack_from('>B', byte)[0]
+                    result = (result << 8) | byte
         else:
             raise InvalidPlistException("Encountered integer longer than 16 
bytes.")
         return result
@@ -456,6 +475,48 @@
     def __repr__(self):
         return "<FloatWrapper: %s>" % self.value
 
+class StringWrapper(object):
+    __instances = {}
+    
+    encodedValue = None
+    encoding = None
+    
+    def __new__(cls, value):
+        '''Ensure we only have a only one instance for any string,
+         and that we encode ascii as 1-byte-per character when possible'''
+        
+        encodedValue = None
+        
+        for encoding in ('ascii', 'utf_16_be'):
+            try:
+               encodedValue = value.encode(encoding)
+            except: pass
+            if encodedValue is not None:
+                if encodedValue not in cls.__instances:
+                    cls.__instances[encodedValue] = super(StringWrapper, 
cls).__new__(cls)
+                    cls.__instances[encodedValue].encodedValue = encodedValue
+                    cls.__instances[encodedValue].encoding = encoding
+                return cls.__instances[encodedValue]
+        
+        raise ValueError('Unable to get ascii or utf_16_be encoding for %s' % 
repr(value))
+    
+    def __len__(self):
+        '''Return roughly the number of characters in this string (half the 
byte length)'''
+        if self.encoding == 'ascii':
+            return len(self.encodedValue)
+        else:
+            return len(self.encodedValue)//2
+    
+    @property
+    def encodingMarker(self):
+        if self.encoding == 'ascii':
+            return 0b0101
+        else:
+            return 0b0110
+    
+    def __repr__(self):
+        return '<StringWrapper (%s): %s>' % (self.encoding, self.encodedValue)
+
 class PlistWriter(object):
     header = b'bplist00bybiplist1.0'
     file = None
@@ -507,10 +568,9 @@
         """
         output = self.header
         wrapped_root = self.wrapRoot(root)
-        should_reference_root = True#not isinstance(wrapped_root, 
HashableWrapper)
-        self.computeOffsets(wrapped_root, asReference=should_reference_root, 
isRoot=True)
+        self.computeOffsets(wrapped_root, asReference=True, isRoot=True)
         self.trailer = 
self.trailer._replace(**{'objectRefSize':self.intSize(len(self.computedUniques))})
-        (_, output) = self.writeObjectReference(wrapped_root, output)
+        self.writeObjectReference(wrapped_root, output)
         output = self.writeObject(wrapped_root, output, 
setReferencePosition=True)
         
         # output size at this point is an upper bound on how big the
@@ -552,6 +612,10 @@
         elif isinstance(root, tuple):
             n = tuple([self.wrapRoot(value) for value in root])
             return HashableWrapper(n)
+        elif isinstance(root, (str, unicode)) and not isinstance(root, Data):
+            return StringWrapper(root)
+        elif isinstance(root, bytes):
+            return Data(root)
         else:
             return root
 
@@ -564,7 +628,7 @@
                 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, (bytes, unicode)):
+            elif not isinstance(key, StringWrapper):
                 raise InvalidPlistException('Keys must be strings.')
         
         def proc_size(size):
@@ -584,7 +648,7 @@
         elif isinstance(obj, BoolWrapper):
             self.incrementByteCount('boolBytes')
         elif isinstance(obj, Uid):
-            size = self.intSize(obj)
+            size = self.intSize(obj.integer)
             self.incrementByteCount('uidBytes', incr=1+size)
         elif isinstance(obj, (int, long)):
             size = self.intSize(obj)
@@ -597,7 +661,7 @@
         elif isinstance(obj, Data):
             size = proc_size(len(obj))
             self.incrementByteCount('dataBytes', incr=1+size)
-        elif isinstance(obj, (unicode, bytes)):
+        elif isinstance(obj, StringWrapper):
             size = proc_size(len(obj))
             self.incrementByteCount('stringBytes', incr=1+size)
         elif isinstance(obj, HashableWrapper):
@@ -621,7 +685,7 @@
                     self.computeOffsets(key, asReference=True)
                     self.computeOffsets(value, asReference=True)
         else:
-            raise InvalidPlistException("Unknown object type.")
+            raise InvalidPlistException("Unknown object type: %s (%s)" % 
(type(obj).__name__, repr(obj)))
 
     def writeObjectReference(self, obj, output):
         """Tries to write an object reference, adding it to the references
@@ -653,9 +717,10 @@
                 result += pack('!B', (format << 4) | length)
             return result
         
-        if isinstance(obj, (str, unicode)) and obj == unicodeEmpty:
-            # The Apple Plist decoder can't decode a zero length Unicode 
string.
-            obj = b''
+        def timedelta_total_seconds(td):
+            # Shim for Python 2.6 compatibility, which doesn't have 
total_seconds.
+            # Make one argument a float to ensure the right calculation.
+            return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 
10.0**6) / 10.0**6
        
         if setReferencePosition:
             self.referencePositions[obj] = len(output)
@@ -668,9 +733,9 @@
             else:
                 output += pack('!B', 0b00001001)
         elif isinstance(obj, Uid):
-            size = self.intSize(obj)
+            size = self.intSize(obj.integer)
             output += pack('!B', (0b1000 << 4) | size - 1)
-            output += self.binaryInt(obj)
+            output += self.binaryInt(obj.integer)
         elif isinstance(obj, (int, long)):
             byteSize = self.intSize(obj)
             root = math.log(byteSize, 2)
@@ -681,16 +746,18 @@
             output += pack('!B', (0b0010 << 4) | 3)
             output += self.binaryReal(obj)
         elif isinstance(obj, datetime.datetime):
-            timestamp = (obj - apple_reference_date).total_seconds()
+            try:
+                timestamp = (obj - apple_reference_date).total_seconds()
+            except AttributeError:
+                timestamp = timedelta_total_seconds(obj - apple_reference_date)
             output += pack('!B', 0b00110011)
             output += pack('!d', float(timestamp))
         elif isinstance(obj, Data):
             output += proc_variable_length(0b0100, len(obj))
             output += obj
-        elif isinstance(obj, unicode):
-            byteData = obj.encode('utf_16_be')
-            output += proc_variable_length(0b0110, len(byteData)//2)
-            output += byteData
+        elif isinstance(obj, StringWrapper):
+            output += proc_variable_length(obj.encodingMarker, len(obj))
+            output += obj.encodedValue
         elif isinstance(obj, bytes):
             output += proc_variable_length(0b0101, len(obj))
             output += obj
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/biplist-0.9/biplist.egg-info/PKG-INFO 
new/biplist-1.0.1/biplist.egg-info/PKG-INFO
--- old/biplist-0.9/biplist.egg-info/PKG-INFO   2014-10-26 20:09:20.000000000 
+0100
+++ new/biplist-1.0.1/biplist.egg-info/PKG-INFO 2016-01-11 09:07:10.000000000 
+0100
@@ -1,19 +1,19 @@
 Metadata-Version: 1.1
 Name: biplist
-Version: 0.9
+Version: 1.0.1
 Summary: biplist is a library for reading/writing binary plists.
 Home-page: https://bitbucket.org/wooster/biplist
 Author: Andrew Wooster
 Author-email: [email protected]
 License: BSD
-Download-URL: 
https://bitbucket.org/wooster/biplist/downloads/biplist-0.9.tar.gz
+Download-URL: 
https://bitbucket.org/wooster/biplist/downloads/biplist-1.0.1.tar.gz
 Description: `biplist` is a binary plist parser/generator for Python.
         
         Binary Property List (plist) files provide a faster and smaller 
serialization
         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 or Python 3.2 or higher.
+        This module requires Python 2.6 or higher or Python 3.4 or higher.
 Platform: UNKNOWN
 Classifier: Development Status :: 5 - Production/Stable
 Classifier: Intended Audience :: Developers
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/biplist-0.9/setup.py new/biplist-1.0.1/setup.py
--- old/biplist-0.9/setup.py    2014-10-26 20:04:50.000000000 +0100
+++ new/biplist-1.0.1/setup.py  2016-01-11 08:36:39.000000000 +0100
@@ -12,21 +12,21 @@
 
 major, minor, micro, releaselevel, serial = sys.version_info
 
-if major <= 1 or (major == 2 and minor < 6) or (major == 3 and minor < 2):
+if major <= 1 or (major == 2 and minor < 6) or (major == 3 and minor < 4):
     # N.B.: Haven't tested with older py3k versions.
-    print('This module supports Python 2 >= 2.6 and Python 3 >= 3.2.')
+    print('This module supports Python 2 >= 2.6 and Python 3 >= 3.4.')
     sys.exit(1)
 
 author = 'Andrew Wooster'
 email = '[email protected]'
-version = '0.9'
+version = '1.0.1'
 desc = 'biplist is a library for reading/writing binary plists.'
 
 setup(
     name = 'biplist',
     version = version,
     url = 'https://bitbucket.org/wooster/biplist',
-    download_url = 
'https://bitbucket.org/wooster/biplist/downloads/biplist-0.9.tar.gz',
+    download_url = 
'https://bitbucket.org/wooster/biplist/downloads/biplist-%s.tar.gz' % version,
     license = 'BSD',
     description = desc,
     long_description = 
@@ -36,7 +36,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 or Python 3.2 or higher.""",
+This module requires Python 2.6 or higher or Python 3.4 or higher.""",
     author = author,
     author_email = email,
     packages = find_packages(),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/biplist-0.9/tests/test_valid.py 
new/biplist-1.0.1/tests/test_valid.py
--- old/biplist-0.9/tests/test_valid.py 2014-10-26 20:03:33.000000000 +0100
+++ new/biplist-1.0.1/tests/test_valid.py       2016-01-10 08:04:45.000000000 
+0100
@@ -19,19 +19,19 @@
     
     def validateSimpleBinaryRoot(self, root):
         self.assertTrue(type(root) == dict, "Root should be dictionary.")
-        self.assertTrue(type(root[b'dateItem']) == datetime.datetime, "date 
should be datetime")
-        us = root[b'dateItem'].microsecond
+        self.assertTrue(type(root['dateItem']) == datetime.datetime, "date 
should be datetime")
+        us = root['dateItem'].microsecond
         if us == 385448:
             # Python 3 doesn't round microseconds to the nearest value.
-            self.assertEqual(root[b'dateItem'], datetime.datetime(2010, 8, 19, 
22, 27, 30, 385448), "dates not equal" )
+            self.assertEqual(root['dateItem'], datetime.datetime(2010, 8, 19, 
22, 27, 30, 385448), "dates not equal" )
         else:
-            self.assertEqual(root[b'dateItem'], datetime.datetime(2010, 8, 19, 
22, 27, 30, 385449), "dates not equal" )
-        self.assertEqual(root[b'numberItem'], -10000000000000000, "number not 
of expected value")
-        self.assertEqual(root[b'unicodeItem'], toUnicode('abc\u212cdef\u2133'))
-        self.assertEqual(root[b'stringItem'], b'Hi there')
-        self.assertEqual(root[b'realItem'], 0.47)
-        self.assertEqual(root[b'boolItem'], True)
-        self.assertEqual(root[b'arrayItem'], [b'item0'])
+            self.assertEqual(root['dateItem'], datetime.datetime(2010, 8, 19, 
22, 27, 30, 385449), "dates not equal" )
+        self.assertEqual(root['numberItem'], -10000000000000000, "number not 
of expected value")
+        self.assertEqual(root['unicodeItem'], toUnicode('abc\u212cdef\u2133'))
+        self.assertEqual(root['stringItem'], 'Hi there')
+        self.assertEqual(root['realItem'], 0.47)
+        self.assertEqual(root['boolItem'], True)
+        self.assertEqual(root['arrayItem'], ['item0'])
         
     def testFileRead(self):
         try:
@@ -55,17 +55,17 @@
         # 0b0101 (ASCII string), so the value being asserted against
         # appears to be what is wrong.
         result = readPlist(data_path('unicode_empty.plist'))
-        self.assertEqual(result, b'')
+        self.assertEqual(result, '')
     
     def testSmallReal(self):
         result = readPlist(data_path('small_real.plist'))
-        self.assertEqual(result, {b'4 byte real':0.5})
+        self.assertEqual(result, {'4 byte real':0.5})
     
     def testLargeIntegers(self):
         result = readPlist(data_path('large_int_limits.plist'))
-        self.assertEqual(result[b'Max 8 Byte Unsigned Integer'], 
18446744073709551615)
-        self.assertEqual(result[b'Min 8 Byte Signed Integer'], 
-9223372036854775808)
-        self.assertEqual(result[b'Max 8 Byte Signed Integer'], 
9223372036854775807)
+        self.assertEqual(result['Max 8 Byte Unsigned Integer'], 
18446744073709551615)
+        self.assertEqual(result['Min 8 Byte Signed Integer'], 
-9223372036854775808)
+        self.assertEqual(result['Max 8 Byte Signed Integer'], 
9223372036854775807)
     
     def testLargeDates(self):
         result = readPlist(data_path("BFPersistentEventInfo.plist"))
@@ -86,15 +86,31 @@
         ...
         """
         result = readPlist(data_path('nskeyedarchiver_example.plist'))
-        self.assertEqual(result, {b'$version': 100000, 
-            b'$objects': 
-                [b'$null',
-                 {b'$class': Uid(3), b'somekey': Uid(2)}, 
-                 b'object value as string',
-                 {b'$classes': [b'Archived', b'NSObject'], b'$classname': 
b'Archived'}
-                 ], 
-            b'$top': {b'root': Uid(1)}, b'$archiver': b'NSKeyedArchiver'})
+        self.assertEqual(result, {
+            '$version': 100000, 
+            '$objects':
+                [
+                       '$null',
+                       {'$class':Uid(3), 'somekey':Uid(2)}, 
+                       'object value as string',
+                       {'$classes':['Archived', 'NSObject'], 
'$classname':'Archived'}
+                ],
+            '$top': {'root':Uid(1)},
+            '$archiver':'NSKeyedArchiver'
+        })
         self.assertEqual("Uid(1)", repr(Uid(1)))
     
+    def testUidComparisons(self):
+        self.assertTrue(Uid(-2) < Uid(-1))
+        self.assertTrue(Uid(-1) < Uid(0))
+        self.assertTrue(Uid(1) > Uid(0))
+        self.assertTrue(Uid(1) > Uid(-2))
+        self.assertTrue(Uid(-1) == Uid(-1))
+        self.assertTrue(Uid(0) == Uid(0))
+        self.assertTrue(Uid(1) == Uid(1))
+        
+        self.assertFalse(1 == Uid(1))
+        self.assertFalse(Uid(0) == 0)
+    
 if __name__ == '__main__':
     unittest.main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/biplist-0.9/tests/test_write.py 
new/biplist-1.0.1/tests/test_write.py
--- old/biplist-0.9/tests/test_write.py 2014-10-26 20:03:11.000000000 +0100
+++ new/biplist-1.0.1/tests/test_write.py       2016-01-10 08:10:36.000000000 
+0100
@@ -1,39 +1,82 @@
+#!/usr/local/env python
+# -*- coding: utf-8 -*-
+
+import datetime, io, os, subprocess, sys, tempfile, unittest
+
 from biplist import *
 from biplist import PlistWriter
-import datetime
-import io
-import os
-#from cStringIO import StringIO
-import subprocess
-import tempfile
 from test_utils import *
-import unittest
 
 try:
     unicode
+    unicodeStr = lambda x: x.decode('utf-8')
+    toUnicode = lambda x: x.decode('unicode-escape')
 except NameError:
     unicode = str
+    unicodeStr = lambda x: x
+    toUnicode = lambda x: x
+try:
+    xrange
+except NameError:
+    xrange = range
 
 class TestWritePlist(unittest.TestCase):
-    def setUp(self):
-        pass
     
-    def roundTrip(self, root, xml=False, expected=None):
-        # 'expected' is more fallout from the
-        # don't-write-empty-unicode-strings issue.
-        plist = writePlistToString(root, binary=(not xml))
+    def roundTrip(self, case, xml=False, expected=None, reprTest=True):
+        # reprTest may fail randomly if True and the values being encoded 
include a dictionary with more
+        # than one key.
+        
+        # convert to plist string
+        plist = writePlistToString(case, binary=(not xml))
         self.assertTrue(len(plist) > 0)
+        
+        # confirm that lint is happy with the result
+        self.lintPlist(plist)        
+        
+        # convert back
         readResult = readPlistFromString(plist)
-        self.assertEqual(readResult, (expected if expected is not None else 
root))
-        self.lintPlist(plist)
-    
-    def lintPlist(self, plistString):
-        if os.path.exists('/usr/bin/plutil'):
-            f = tempfile.NamedTemporaryFile()
-            f.write(plistString)
-            f.flush()
-            name = f.name
-            (status, output) = run_command(['/usr/bin/plutil', '-lint', name])
+        
+        # test equality
+        if reprTest is True:
+            self.assertEqual(repr(case if expected is None else expected), 
repr(readResult))
+        else:
+            self.assertEqual((case if expected is None else expected), 
readResult)
+        
+        # write to file
+        plistFile = tempfile.NamedTemporaryFile(mode='wb+', suffix='.plist')
+        writePlist(case, plistFile, binary=(xml is False))
+        plistFile.seek(0)
+        
+        # confirm that lint is happy with the result
+        self.lintPlist(plistFile)
+        
+        # read back from file
+        fileResult = readPlist(plistFile)
+        
+        # test equality
+        if reprTest is True:
+            self.assertEqual(repr(case if expected is None else expected), 
repr(fileResult))
+        else:
+            self.assertEqual((case if expected is None else expected), 
fileResult)
+    
+    def lintPlist(self, plist):
+        if os.access('/usr/bin/plutil', os.X_OK):
+            plistFile = None
+            plistFilePath = None
+            
+            if hasattr(plist, 'name'):
+                plistFilePath = plist.name
+            else:
+                if hasattr(plist, 'read'):
+                    plistFile = tempfile.NamedTemporaryFile('w%s' % ('b' if 
'b' in plist.mode else ''))
+                    plistFile.write(plist.read())
+                else:
+                    plistFile = tempfile.NamedTemporaryFile('w%s' % ('b' if 
isinstance(plist, bytes) else ''))
+                    plistFile.write(plist)
+                plistFilePath = plistFile.name
+                plistFile.flush()
+
+            status, output = run_command(['/usr/bin/plutil', '-lint', 
plistFilePath])
             if status != 0:
                 self.fail("plutil verification failed (status %d): %s" % 
(status, output))
     
@@ -58,36 +101,32 @@
         self.roundTrip(False)
     
     def testDuplicate(self):
-        l = ["foo" for i in range(0, 100)]
+        l = ["foo" for i in xrange(0, 100)]
         self.roundTrip(l)
         
     def testListRoot(self):
         self.roundTrip([1, 2, 3])
     
     def testDictRoot(self):
-        self.roundTrip({'a':1, 'B':'d'})
+        self.roundTrip({'a':1, 'B':'d'}, reprTest=False)
     
     def mixedNumericTypesHelper(self, cases):
         result = readPlistFromString(writePlistToString(cases))
-        for i in range(0, len(cases)):
+        for i in xrange(0, len(cases)):
             self.assertTrue(cases[i] == result[i])
             self.assertEqual(type(cases[i]), type(result[i]), "Type mismatch 
on %d: %s != %s" % (i, repr(cases[i]), repr(result[i])))
     
-    def reprChecker(self, case):
-        result = readPlistFromString(writePlistToString(case))
-        self.assertEqual(repr(case), repr(result))
-    
     def testBoolsAndIntegersMixed(self):
         self.mixedNumericTypesHelper([0, 1, True, False, None])
         self.mixedNumericTypesHelper([False, True, 0, 1, None])
-        self.reprChecker({unicode('1'):[True, False, 1, 0], unicode('0'):[1, 
2, 0, {unicode('2'):[1, 0, False]}]})
-        self.reprChecker([1, 1, 1, 1, 1, True, True, True, True])
+        self.roundTrip({'1':[True, False, 1, 0], '0':[1, 2, 0, {'2':[1, 0, 
False]}]}, reprTest=False)
+        self.roundTrip([1, 1, 1, 1, 1, True, True, True, True])
     
     def testFloatsAndIntegersMixed(self):
         self.mixedNumericTypesHelper([0, 1, 1.0, 0.0, None])
         self.mixedNumericTypesHelper([0.0, 1.0, 0, 1, None])
-        self.reprChecker({unicode('1'):[1.0, 0.0, 1, 0], unicode('0'):[1, 2, 
0, {unicode('2'):[1, 0, 0.0]}]})
-        self.reprChecker([1, 1, 1, 1, 1, 1.0, 1.0, 1.0, 1.0])
+        self.roundTrip({'1':[1.0, 0.0, 1, 0], '0':[1, 2, 0, {'2':[1, 0, 
0.0]}]}, reprTest=False)
+        self.roundTrip([1, 1, 1, 1, 1, 1.0, 1.0, 1.0, 1.0])
     
     def testSetRoot(self):
         self.roundTrip(set((1, 2, 3)))
@@ -112,36 +151,102 @@
         self.lintPlist(writePlistToString(root))
         self.roundTrip(root)
     
-    def testString(self):
+    def testBytes(self):
         self.roundTrip(b'0')
         self.roundTrip(b'')
-        self.roundTrip({b'a':b''})
+        
+        self.roundTrip([b'0'])
+        self.roundTrip([b''])
+        
+        self.roundTrip({'a': b'0'})
+        self.roundTrip({'a': b''})
     
-    def testLargeDict(self):
-        d = {}
-        for i in range(0, 1000):
-            d['%d' % i] = '%d' % i
-        self.roundTrip(d)
+    def testString(self):
+        self.roundTrip('')
+        self.roundTrip('a')
+        self.roundTrip('1')
+        
+        self.roundTrip([''])
+        self.roundTrip(['a'])
+        self.roundTrip(['1'])
+        
+        self.roundTrip({'a':''})
+        self.roundTrip({'a':'a'})
+        self.roundTrip({'1':'a'})
         
+        self.roundTrip({'a':'a'})
+        self.roundTrip({'a':'1'})
+    
+    def testUnicode(self):
+        # defaulting to 1 byte strings
+        if str != unicode:
+            self.roundTrip(unicodeStr(r''), expected='')
+            self.roundTrip(unicodeStr(r'a'), expected='a')
+            
+            self.roundTrip([unicodeStr(r'a')], expected=['a'])
+            
+            self.roundTrip({'a':unicodeStr(r'a')}, expected={'a':'a'})
+            self.roundTrip({unicodeStr(r'a'):'a'}, expected={'a':'a'})
+            self.roundTrip({unicodeStr(r''):unicodeStr(r'')}, expected={'':''})
+        
+        # TODO: need a 4-byte unicode character
+        self.roundTrip(unicodeStr(r'ü'))
+        self.roundTrip([unicodeStr(r'ü')])
+        self.roundTrip({'a':unicodeStr(r'ü')})
+        self.roundTrip({unicodeStr(r'ü'):'a'})
+        
+        self.roundTrip(toUnicode('\u00b6'))
+        self.roundTrip([toUnicode('\u00b6')])
+        self.roundTrip({toUnicode('\u00b6'):toUnicode('\u00b6')})
+        
+        self.roundTrip(toUnicode('\u1D161'))
+        self.roundTrip([toUnicode('\u1D161')])
+        self.roundTrip({toUnicode('\u1D161'):toUnicode('\u1D161')})
+        
+        # Smiley face emoji
+        self.roundTrip(toUnicode('\U0001f604'))
+        self.roundTrip([toUnicode('\U0001f604'), toUnicode('\U0001f604')])
+        self.roundTrip({toUnicode('\U0001f604'):toUnicode('\U0001f604')})
+    
+    def testNone(self):
+        self.roundTrip(None)
+        self.roundTrip({'1':None})
+        self.roundTrip([None, None, None])
+    
     def testBools(self):
+        self.roundTrip(True)
+        self.roundTrip(False)
+        
         self.roundTrip([True, False])
+        
+        self.roundTrip({'a':True, 'b':False}, reprTest=False)
     
     def testUniques(self):
         root = {'hi':'there', 'halloo':'there'}
-        self.roundTrip(root)
+        self.roundTrip(root, reprTest=False)
+    
+    def testAllEmpties(self):
+        '''Primarily testint that an empty unicode and bytes are not mixed 
up'''
+        self.roundTrip([unicodeStr(''), '', b'', [], {}], expected=['', '', 
b'', [], {}])
     
+    def testLargeDict(self):
+        d = dict((str(x), str(x)) for x in xrange(0, 1000))
+        self.roundTrip(d, reprTest=False)
+        
     def testWriteToFile(self):
         for is_binary in [True, False]:
-            path = '/var/tmp/test.plist'
-            writePlist([1, 2, 3], path, binary=is_binary)
-            self.assertTrue(os.path.exists(path))
-            with open(path, 'rb') as f:
-                self.lintPlist(f.read())
-    
-    def testNone(self):
-        self.roundTrip(None)
-        self.roundTrip({'1':None})
-        self.roundTrip([None, None, None])
+            with tempfile.NamedTemporaryFile(mode='w%s' % ('b' if is_binary 
else ''), suffix='.plist') as plistFile:
+                # clear out the created file
+                os.unlink(plistFile.name)
+                self.assertFalse(os.path.exists(plistFile.name))
+                
+                # write to disk
+                writePlist([1, 2, 3], plistFile.name, binary=is_binary)
+                self.assertTrue(os.path.exists(plistFile.name))
+                
+                with open(plistFile.name, 'r%s' % ('b' if is_binary else '')) 
as f:
+                    fileContents = f.read()
+                    self.lintPlist(fileContents)
     
     def testBadKeys(self):
         try:
@@ -169,7 +274,7 @@
                  -pow(2, 15), pow(2, 15) - 1, 
                  -pow(2, 31), pow(2, 31) - 1, 
                  -pow(2, 63), pow(2, 64) - 1]
-        self.roundTrip(edges)
+        self.roundTrip(edges, reprTest=False)
         
         ioBytes = io.BytesIO()
         writer = PlistWriter(ioBytes)
@@ -185,7 +290,7 @@
                 self.assertEqual(bytelen, got, "Byte size is wrong. Expected 
%d, got %d" % (bytelen, got))
         
         bytes_lists = [list(x) for x in bytes]
-        self.roundTrip(bytes_lists)
+        self.roundTrip(bytes_lists, reprTest=False)
         
         try:
             self.roundTrip([0x10000000000000000, pow(2, 64)])
@@ -193,17 +298,23 @@
         except InvalidPlistException as e:
             pass
     
-    def testWriteData(self):
-        self.roundTrip(Data(b"woohoo"))
-        
-    def testUnicode(self):
-        unicodeRoot = unicode("Mirror's Edge\u2122 for iPad")
-        writePlist(unicodeRoot, "/tmp/odd.plist")
+    def testUnicode2(self):
+        unicodeRoot = toUnicode("Mirror's Edge\u2122 for iPad")
         self.roundTrip(unicodeRoot)
-        unicodeStrings = [unicode("Mirror's Edge\u2122 for iPad"), 
unicode('Weightbot \u2014 Track your Weight in Style')]
+        unicodeStrings = [toUnicode("Mirror's Edge\u2122 for iPad"), 
toUnicode('Weightbot \u2014 Track your Weight in Style')]
         self.roundTrip(unicodeStrings)
-        self.roundTrip({unicode(""):unicode("")}, expected={b'':b''})
-        self.roundTrip(unicode(""), expected=b'')
+        self.roundTrip({toUnicode(""):toUnicode("")}, expected={'':''})
+        self.roundTrip(toUnicode(""), expected='')
+    
+    def testWriteData(self):
+        self.roundTrip(Data(b"woohoo"))
+
+    def testEmptyData(self):
+        data = Data(b'')
+        binplist = writePlistToString(data)
+        plist = readPlistFromString(binplist)
+        self.assertEqual(plist, data)
+        self.assertEqual(type(plist), type(data))
         
     def testUidWrite(self):
         self.roundTrip({'$version': 100000, 
@@ -213,7 +324,14 @@
                  'object value as string', 
                  {'$classes': ['Archived', 'NSObject'], '$classname': 
'Archived'}
                  ], 
-            '$top': {'root': Uid(1)}, '$archiver': 'NSKeyedArchiver'})
+            '$top': {'root': Uid(1)}, '$archiver': 'NSKeyedArchiver'}, 
reprTest=False)
+    
+    def testUidRoundTrip(self):
+        # Per https://github.com/wooster/biplist/issues/9
+        self.roundTrip(Uid(1))
+        self.roundTrip([Uid(1), 1])
+        self.roundTrip([1, Uid(1)])
+        self.roundTrip([Uid(1), Uid(1)])
 
 if __name__ == '__main__':
     unittest.main()


Reply via email to