[PyObjC-svn] r2465 - in trunk/pyobjc/pyobjc-core: . Lib/objc Modules/objc PyObjCTest

[email protected] Tue, 04 May 2010 13:56:44 -0500
Newsgroups gmane.comp.python.pyobjc.cvs
Message-ID <[email protected]>
Author: ronaldoussoren
Date: Tue May  4 13:56:44 2010
New Revision: 2465

Log:
Implement support for encoding Python objects using
an NSArchiver that doesn't support Keyed Archiving.


Added:
   trunk/pyobjc/pyobjc-core/Modules/objc/coder-category.m
Modified:
   trunk/pyobjc/pyobjc-core/Lib/objc/_pycoder.py
   trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonString.m
   trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonUnicode.m
   trunk/pyobjc/pyobjc-core/NEWS.txt
   trunk/pyobjc/pyobjc-core/PyObjCTest/test_archive_python.py

Modified: trunk/pyobjc/pyobjc-core/Lib/objc/_pycoder.py
==============================================================================
--- trunk/pyobjc/pyobjc-core/Lib/objc/_pycoder.py	(original)
+++ trunk/pyobjc/pyobjc-core/Lib/objc/_pycoder.py	Tue May  4 13:56:44 2010
@@ -19,7 +19,7 @@
 from pickle import PicklingError, UnpicklingError, whichmodule
 
 
-
+# FIXME: This requires manual wrappers from the Foundation bindings
 def setupPythonObject():
     OC_PythonObject = objc.lookUpClass("OC_PythonObject")
 
@@ -73,20 +73,35 @@
         if not callable(func):
             raise PicklingError("func from reduce should be callable")
 
+        if coder.allowsKeyedCoding():
+            coder.encodeInt_forKey_(kOP_REDUCE, kKIND)
+            coder.encodeObject_forKey_(func, kFUNC)
+            coder.encodeObject_forKey_(args, kARGS)
+            if listitems is None:
+                coder.encodeObject_forKey_(None, kLIST)
+            else:
+                coder.encodeObject_forKey_(list(listitems), kLIST)
 
-        coder.encodeInt_forKey_(kOP_REDUCE, kKIND)
-        coder.encodeObject_forKey_(func, kFUNC)
-        coder.encodeObject_forKey_(args, kARGS)
-        if listitems is None:
-            coder.encodeObject_forKey_(None, kLIST)
-        else:
-            coder.encodeObject_forKey_(list(listitems), kLIST)
+            if dictitems is None:
+                coder.encodeObject_forKey_(None, kDICT)
+            else:
+                coder.encodeObject_forKey_(dict(dictitems), kDICT)
+            coder.encodeObject_forKey_(state, kSTATE)
 
-        if dictitems is None:
-            coder.encodeObject_forKey_(None, kDICT)
         else:
-            coder.encodeObject_forKey_(dict(dictitems), kDICT)
-        coder.encodeObject_forKey_(state, kSTATE)
+            coder.__pyobjc__encodeInt_(kOP_REDUCE)
+            coder.encodeObject_(func)
+            coder.encodeObject_(args)
+            if listitems is None:
+                coder.encodeObject_(None)
+            else:
+                coder.encodeObject_(list(listitems))
+
+            if dictitems is None:
+                coder.encodeObject_(None)
+            else:
+                coder.encodeObject_(dict(dictitems))
+            coder.encodeObject_(state)
 
     if sys.version_info[0] == 2:
         def save_inst(coder, obj):
@@ -98,9 +113,15 @@
 
             cls = obj.__class__
 
-            coder.encodeInt32_forKey_(kOP_INST, kKIND)
-            coder.encodeObject_forKey_(cls, kCLASS)
-            coder.encodeObject_forKey_(args, kARGS)
+            if coder.allowsKeyedCoding():
+                coder.encodeInt32_forKey_(kOP_INST, kKIND)
+                coder.encodeObject_forKey_(cls, kCLASS)
+                coder.encodeObject_forKey_(args, kARGS)
+
+            else:
+                coder.__pyobjc__encodeInt32_(kOP_INST)
+                coder.encodeObject_(cls)
+                coder.encodeObject_(args)
 
             try:
                 getstate = obj.__getstate__
@@ -110,65 +131,114 @@
             else:
                 state = getstate()
 
-            coder.encodeObject_forKey_(state, kSTATE)
+            if coder.allowsKeyedCoding():
+                coder.encodeObject_forKey_(state, kSTATE)
+
+            else:
+                coder.encodeObject_(state)
 
         encode_dispatch[InstanceType] = save_inst
 
 
     def save_none(coder, obj):
-        coder.encodeInt_forKey_(kOP_NONE, kKIND)
+        if coder.allowsKeyedCoding():
+            coder.encodeInt_forKey_(kOP_NONE, kKIND)
+        else:
+            coder.__pyobjc__encodeInt_(kOP_NONE)
     encode_dispatch[type(None)] = save_none
 
     def save_bool(coder, obj):
-        coder.encodeInt_forKey_(kOP_BOOL, kKIND)
-        coder.encodeBool_forKey_(bool(obj), kVALUE)
+        if coder.allowsKeyedCoding():
+            coder.encodeInt_forKey_(kOP_BOOL, kKIND)
+            coder.encodeBool_forKey_(bool(obj), kVALUE)
+        else:
+            coder.__pyobjc__encodeInt_(kOP_BOOL)
+            coder.__pyobjc__encodeBool_(bool(obj))
     encode_dispatch[bool] = save_bool
 
     if sys.version_info[0] == 2:
         def save_int(coder, obj):
-            coder.encodeInt_forKey_(kOP_INT, kKIND)
-            coder.encodeInt64_forKey_(obj, kVALUE)
+            if coder.allowsKeyedCoding():
+                coder.encodeInt_forKey_(kOP_INT, kKIND)
+                coder.encodeInt64_forKey_(obj, kVALUE)
+            else:
+                coder.__pyobjc__encodeInt_(kOP_INT)
+                coder.__pyobjc__encodeInt64_(obj)
         encode_dispatch[int] = save_int
 
         def save_long(coder, obj):
-            coder.encodeInt_forKey_(kOP_LONG, kKIND)
-            coder.encodeObject_forKey_(unicode(repr(obj)), kVALUE)
+            if coder.allowsKeyedCoding():
+                coder.encodeInt_forKey_(kOP_LONG, kKIND)
+                coder.encodeObject_forKey_(unicode(repr(obj)), kVALUE)
+            else:
+                coder.__pyobjc__encodeInt_(kOP_LONG)
+                coder.encodeObject_(unicode(repr(obj)))
+
         encode_dispatch[long] = save_long
 
     else:
         def save_int(coder, obj):
-            coder.encodeInt_forKey_(kOP_LONG, kKIND)
-            coder.encodeObject_forKey_(unicode(repr(obj)), kVALUE)
+            if coder.allowsKeyedCoding():
+                coder.encodeInt_forKey_(kOP_LONG, kKIND)
+                coder.encodeObject_forKey_(unicode(repr(obj)), kVALUE)
+            else:
+                coder.__pyobjc__encodeInt_(kOP_LONG)
+                coder.encodeObject_(unicode(repr(obj)))
         encode_dispatch[int] = save_int
 
     def save_float(coder, obj):
         # Encode floats as strings, this seems to be needed to get
         # 100% reliable round-trips.
-        coder.encodeInt_forKey_(kOP_FLOAT_STR, kKIND)
-        coder.encodeObject_forKey_(unicode(repr(obj)), kVALUE)
+        if coder.allowsKeyedCoding():
+            coder.encodeInt_forKey_(kOP_FLOAT_STR, kKIND)
+            coder.encodeObject_forKey_(unicode(repr(obj)), kVALUE)
+        else:
+            coder.__pyobjc__encodeInt_(kOP_FLOAT_STR)
+            coder.encodeObject_(unicode(repr(obj)))
         #coder.encodeDouble_forKey_(obj, kVALUE)
     encode_dispatch[float] = save_float
 
     def save_string(coder, obj):
-        coder.encodeInt_forKey_(kOP_STRING, kKIND)
-        coder.encodeBytes_length_forKey_(obj, len(obj), kVALUE)
+        if coder.allowsKeyedCoding():
+            coder.encodeInt_forKey_(kOP_STRING, kKIND)
+            coder.encodeBytes_length_forKey_(obj, len(obj), kVALUE)
+        else:
+            encodeInt_(kOP_STRING)
+            coder.encodeBytes_length_(obj, len(obj))
+
     encode_dispatch[str] = save_string
 
     
     def save_tuple(coder, obj):
-        coder.encodeInt_forKey_(kOP_TUPLE, kKIND)
-        coder.encodeObject_forKey_(NSArray.arrayWithArray_(obj), kVALUE)
+        if coder.allowsKeyedCoding():
+            coder.encodeInt_forKey_(kOP_TUPLE, kKIND)
+            coder.encodeObject_forKey_(NSArray.arrayWithArray_(obj), kVALUE)
+
+        else:
+            coder.__pyobjc__encodeInt_(kOP_TUPLE)
+            coder.encodeObject_(NSArray.arrayWithArray_(obj))
     encode_dispatch[tuple] = save_tuple
 
     def save_list(coder, obj):
-        coder.encodeInt_forKey_(kOP_LIST, kKIND)
-        coder.encodeObject_forKey_(NSArray.arrayWithArray_(obj), kVALUE)
+        if coder.allowsKeyedCoding():
+            coder.encodeInt_forKey_(kOP_LIST, kKIND)
+            coder.encodeObject_forKey_(NSArray.arrayWithArray_(obj), kVALUE)
+
+        else:
+            coder.__pyobjc__encodeInt_(kOP_LIST)
+            coder.encodeObject_(NSArray.arrayWithArray_(obj))
     encode_dispatch[list] = save_list
 
     def save_dict(coder, obj):
-        coder.encodeInt_forKey_(kOP_DICT, kKIND)
-        v = NSDictionary.dictionaryWithDictionary_(obj)
-        coder.encodeObject_forKey_(v, kVALUE)
+        if coder.allowsKeyedCoding():
+            coder.encodeInt_forKey_(kOP_DICT, kKIND)
+            v = NSDictionary.dictionaryWithDictionary_(obj)
+            coder.encodeObject_forKey_(v, kVALUE)
+        else:
+            coder.__pyobjc__encodeInt_(kOP_DICT)
+            v = NSDictionary.dictionaryWithDictionary_(obj)
+            coder.encodeObject_(v)
+
     encode_dispatch[dict] = save_dict
 
     def save_global(coder, obj, name=None):
@@ -196,14 +266,26 @@
                     (obj, module, name))
 
         code = copy_reg._extension_registry.get((module, name))
-        if code:
-            coder.encodeInt_forKey_(kOP_GLOBAL_EXT, kKIND)
-            coder.encodeInt_forKey_(code, kCODE)
+
+        if coder.allowsKeyedCoding():
+            if code:
+                coder.encodeInt_forKey_(kOP_GLOBAL_EXT, kKIND)
+                coder.encodeInt_forKey_(code, kCODE)
+
+            else:
+                coder.encodeInt_forKey_(kOP_GLOBAL, kKIND)
+                coder.encodeObject_forKey_(unicode(module), kMODULE)
+                coder.encodeObject_forKey_(unicode(name), kNAME)
 
         else:
-            coder.encodeInt_forKey_(kOP_GLOBAL, kKIND)
-            coder.encodeObject_forKey_(unicode(module), kMODULE)
-            coder.encodeObject_forKey_(unicode(name), kNAME)
+            if code:
+                coder.__pyobjc__encodeInt_(kOP_GLOBAL_EXT)
+                coder.__pyobjc__encodeInt_(code)
+
+            else:
+                coder.__pyobjc__encodeInt_(kOP_GLOBAL)
+                coder.encodeObject_(unicode(module))
+                coder.encodeObject_(unicode(name))
 
     if sys.version_info[0] == 2:
         encode_dispatch[ClassType] = save_global
@@ -219,39 +301,68 @@
     decode_dispatch[kOP_NONE] = load_none
 
     def load_bool(coder, setValue):
-        return coder.decodeBoolForKey_(kVALUE)
+        if coder.allowsKeyedCoding():
+            return coder.decodeBoolForKey_(kVALUE)
+        else:
+            return coder.__pyobjc__decodeBool()
+
     decode_dispatch[kOP_BOOL] = load_bool
 
     def load_int(coder, setValue):
-        return int(coder.decodeInt64ForKey_(kVALUE))
+        if coder.allowsKeyedCoding():
+            return int(coder.decodeInt64ForKey_(kVALUE))
+        else:
+            return int(coder.__pyobjc__decodeInt64())
     decode_dispatch[kOP_INT] = load_int
 
     def load_long(coder, setValue):
-        return long(coder.decodeObjectForKey_(kVALUE))
+        if coder.allowsKeyedCoding():
+            return long(coder.decodeObjectForKey_(kVALUE))
+        else:
+            return long(coder.decodeObject())
     decode_dispatch[kOP_LONG] = load_long
 
     def load_float(coder, setValue):
-        return coder.decodeFloatForKey_(kVALUE)
+        if coder.allowsKeyedCoding():
+            return coder.decodeFloatForKey_(kVALUE)
+        else:
+            raise RuntimeError("Unexpected encoding")
     decode_dispatch[kOP_FLOAT] = load_float
 
     def load_float_str(coder, setValue):
-        return float(coder.decodeObjectForKey_(kVALUE))
+        if coder.allowsKeyedCoding():
+            return float(coder.decodeObjectForKey_(kVALUE))
+        else:
+            return float(coder.decodeObject())
     decode_dispatch[kOP_FLOAT_STR] = load_float_str
 
     def load_tuple(coder, setValue):
-        return tuple(coder.decodeObjectForKey_(kVALUE))
+        if coder.allowsKeyedCoding():
+            return tuple(coder.decodeObjectForKey_(kVALUE))
+        else:
+            return tuple(coder.decodeObject())
+
     decode_dispatch[kOP_TUPLE] = load_tuple
 
     def load_list(coder, setValue):
-        return list(coder.decodeObjectForKey_(kVALUE))
+        if coder.allowsKeyedCoding():
+            return list(coder.decodeObjectForKey_(kVALUE))
+        else:
+            return list(coder.decodeObject())
     decode_dispatch[kOP_LIST] = load_list
 
     def load_dict(coder, setValue):
-        return dict(coder.decodeObjectForKey_(kVALUE))
+        if coder.allowsKeyedCoding():
+            return dict(coder.decodeObjectForKey_(kVALUE))
+        else:
+            return dict(coder.decodeObject())
     decode_dispatch[kOP_DICT] = load_dict
 
     def load_global_ext(coder, setValue):
-        code = coder.intForKey_(kCODE)
+        if coder.allowsKeyedCoding():
+            code = coder.intForKey_(kCODE)
+        else:
+            code = coder.__pyobjc__decodeInt()
         nil = []
         obj = copy_reg._extension_cache.get(code, nil)
         if obj is not nil:
@@ -268,8 +379,13 @@
     decode_dispatch[kOP_GLOBAL_EXT] = load_global_ext
 
     def load_global(coder, setValue):
-        module = coder.decodeObjectForKey_(kMODULE)
-        name = coder.decodeObjectForKey_(kNAME)
+        if coder.allowsKeyedCoding():
+            module = coder.decodeObjectForKey_(kMODULE)
+            name = coder.decodeObjectForKey_(kNAME)
+        else:
+            module = coder.decodeObject()
+            name = coder.decodeObject()
+
         __import__(module)
         mod = sys.modules[module]
         klass = getattr(mod, name)
@@ -279,8 +395,13 @@
 
 
     def load_inst(coder, setValue):
-        cls = coder.decodeObjectForKey_(kCLASS)
-        initargs = coder.decodeObjectForKey_(kARGS)
+        if coder.allowsKeyedCoding():
+            cls = coder.decodeObjectForKey_(kCLASS)
+            initargs = coder.decodeObjectForKey_(kARGS)
+        else:
+            cls = coder.decodeObject()
+            initargs = coder.decodeObject()
+
 
         instantiated = 0
         if (sys.version_info[0] == 2 and not initargs and 
@@ -308,7 +429,10 @@
         # of the object state which we'll retrieve next.
         setValue(value)
 
-        state = coder.decodeObjectForKey_(kSTATE)
+        if coder.allowsKeyedCoding():
+            state = coder.decodeObjectForKey_(kSTATE)
+        else:
+            state = coder.decodeObject()
         setstate = getattr(value, "__setstate__", None)
         if setstate is not None:
             setstate(state)
@@ -334,8 +458,12 @@
         
 
     def load_reduce(coder, setValue):
-        func = coder.decodeObjectForKey_(kFUNC)
-        args = coder.decodeObjectForKey_(kARGS)
+        if coder.allowsKeyedCoding():
+            func = coder.decodeObjectForKey_(kFUNC)
+            args = coder.decodeObjectForKey_(kARGS)
+        else:
+            func = coder.decodeObject()
+            args = coder.decodeObject()
 
         value = func(*args)
 
@@ -345,9 +473,15 @@
         # of the object state which we'll retrieve next.
         setValue(value)
 
-        listitems = coder.decodeObjectForKey_(kLIST)
-        dictitems = coder.decodeObjectForKey_(kDICT)
-        state = coder.decodeObjectForKey_(kSTATE)
+        if coder.allowsKeyedCoding():
+            listitems = coder.decodeObjectForKey_(kLIST)
+            dictitems = coder.decodeObjectForKey_(kDICT)
+            state = coder.decodeObjectForKey_(kSTATE)
+        else:
+            listitems = coder.decodeObject()
+            dictitems = coder.decodeObject()
+            state = coder.decodeObject()
+
         setstate = getattr(value, "__setstate__", None)
         if setstate:
             setstate(state)
@@ -434,7 +568,10 @@
         save_reduce(coder, *rv)
 
     def pyobjectDecode(coder, setValue):
-        tp = coder.decodeIntForKey_(kKIND)
+        if coder.allowsKeyedCoding():
+            tp = coder.decodeIntForKey_(kKIND)
+        else:
+            tp = coder.__pyobjc__decodeInt()
         f = decode_dispatch.get(tp)
         if f is None:
             raise UnpicklingError("Unknown object kind: %s"%(tp,))

Modified: trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonString.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonString.m	(original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonString.m	Tue May  4 13:56:44 2010
@@ -157,6 +157,25 @@
 	return self;
 }
 
+-initWithBytes:(void*)bytes length:(NSUInteger)length encoding:(NSStringEncoding)encoding
+{
+	NSString* tmpval = [[NSString alloc] initWithBytes:bytes length:length encoding:encoding];
+
+	PyObjC_BEGIN_WITH_GIL
+		value = PyString_FromString([tmpval UTF8String]);
+		if (value == NULL) {
+			PyObjC_GIL_FORWARD_EXC();
+		}
+		PyString_InternInPlace(&value);
+
+	PyObjC_END_WITH_GIL
+
+	[tmpval release];
+	return self;
+}
+
+
+
 
 /* 
  * Helper method for initWithCoder, needed to deal with

Modified: trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonUnicode.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonUnicode.m	(original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonUnicode.m	Tue May  4 13:56:44 2010
@@ -173,6 +173,26 @@
 	return self;
 }
 
+-initWithBytes:(void*)bytes length:(NSUInteger)length encoding:(NSStringEncoding)encoding
+{
+#ifndef PyObjC_UNICODE_FAST_PATH
+# error "Wide UNICODE builds are not supported at the moment"
+#endif
+	NSString* tmpval = [[NSString alloc] initWithBytes:bytes length:length encoding:encoding];
+	Py_ssize_t charcount = [tmpval length];
+
+
+	PyObjC_BEGIN_WITH_GIL
+		value = PyUnicode_FromUnicode(NULL, charcount);
+		if (value == NULL) {
+			PyObjC_GIL_FORWARD_EXC();
+		}
+		[tmpval getCharacters:PyUnicode_AS_UNICODE(value)];
+
+	PyObjC_END_WITH_GIL;
+	[tmpval release];
+	return self;
+}
 
 /* 
  * Helper method for initWithCoder, needed to deal with

Modified: trunk/pyobjc/pyobjc-core/NEWS.txt
==============================================================================
--- trunk/pyobjc/pyobjc-core/NEWS.txt	(original)
+++ trunk/pyobjc/pyobjc-core/NEWS.txt	Tue May  4 13:56:44 2010
@@ -7,6 +7,9 @@
 Version 2.3a0
 -------------
 
+- PyObjC's support for ``NSCoding`` now also works with plain ``NSArchiver``
+  instances, not just with ``NSKeyedArchiver``.
+
 - (This item is currenlty only true for python3, need tests for python 2.x)
 
   NSDictionary now fully implements the dict API, except for the differences

Modified: trunk/pyobjc/pyobjc-core/PyObjCTest/test_archive_python.py
==============================================================================
--- trunk/pyobjc/pyobjc-core/PyObjCTest/test_archive_python.py	(original)
+++ trunk/pyobjc/pyobjc-core/PyObjCTest/test_archive_python.py	Tue May  4 13:56:44 2010
@@ -14,6 +14,7 @@
 from PyObjCTest.fnd import NSData, NSArray, NSDictionary
 from PyObjCTest.fnd import NSMutableArray, NSMutableDictionary
 
+import Foundation
 
 # 
 # First set of tests: the stdlib tests for pickling, this
@@ -57,95 +58,99 @@
     # For some reason NSCoding support doesn't work on OSX 10.4 yet, ignore these
     # tests for now
     class TestKeyedArchiveSimple (TestCase):
+        def setUp(self):
+            self.archiverClass = NSKeyedArchiver
+            self.unarchiverClass = NSKeyedUnarchiver
+        
         def testBasicObjects(self):
-            buf = NSKeyedArchiver.archivedDataWithRootObject_(a_function)
+            buf = self.archiverClass.archivedDataWithRootObject_(a_function)
             self.assertIsInstance(buf, NSData)
-            v = NSKeyedUnarchiver.unarchiveObjectWithData_(buf)
+            v = self.unarchiverClass.unarchiveObjectWithData_(buf)
             self.assertIsObject(v, a_function)
 
-            buf = NSKeyedArchiver.archivedDataWithRootObject_(a_classic_class)
+            buf = self.archiverClass.archivedDataWithRootObject_(a_classic_class)
             self.assertIsInstance(buf, NSData)
-            v = NSKeyedUnarchiver.unarchiveObjectWithData_(buf)
+            v = self.unarchiverClass.unarchiveObjectWithData_(buf)
             self.assertIsObject(v, a_classic_class)
 
-            buf = NSKeyedArchiver.archivedDataWithRootObject_(a_newstyle_class)
+            buf = self.archiverClass.archivedDataWithRootObject_(a_newstyle_class)
             self.assertIsInstance(buf, NSData)
-            v = NSKeyedUnarchiver.unarchiveObjectWithData_(buf)
+            v = self.unarchiverClass.unarchiveObjectWithData_(buf)
             self.assertIsObject(v, a_newstyle_class)
 
             o = a_classic_class()
             o.x = 42
-            buf = NSKeyedArchiver.archivedDataWithRootObject_(o)
+            buf = self.archiverClass.archivedDataWithRootObject_(o)
             self.assertIsInstance(buf, NSData)
-            v = NSKeyedUnarchiver.unarchiveObjectWithData_(buf)
+            v = self.unarchiverClass.unarchiveObjectWithData_(buf)
             self.assertIsInstance(v, a_classic_class)
             self.assertEquals(o.x, 42)
 
-            buf = NSKeyedArchiver.archivedDataWithRootObject_(u"hello")
+            buf = self.archiverClass.archivedDataWithRootObject_(u"hello")
             self.assertIsInstance(buf, NSData)
-            v = NSKeyedUnarchiver.unarchiveObjectWithData_(buf)
+            v = self.unarchiverClass.unarchiveObjectWithData_(buf)
             self.assertIsInstance(v, unicode)
 
-            buf = NSKeyedArchiver.archivedDataWithRootObject_("hello")
+            buf = self.archiverClass.archivedDataWithRootObject_("hello")
             self.assertIsInstance(buf, NSData)
-            v = NSKeyedUnarchiver.unarchiveObjectWithData_(buf)
+            v = self.unarchiverClass.unarchiveObjectWithData_(buf)
             self.assertIsInstance(v, str)
             self.assertEquals(v, "hello")
 
-            buf = NSKeyedArchiver.archivedDataWithRootObject_(sys.maxint * 4)
+            buf = self.archiverClass.archivedDataWithRootObject_(sys.maxint * 4)
             self.assertIsInstance(buf, NSData)
-            v = NSKeyedUnarchiver.unarchiveObjectWithData_(buf)
+            v = self.unarchiverClass.unarchiveObjectWithData_(buf)
             self.assertIsInstance(v, long)
             self.assertEquals(v, sys.maxint * 4)
 
-            buf = NSKeyedArchiver.archivedDataWithRootObject_(sys.maxint ** 4)
+            buf = self.archiverClass.archivedDataWithRootObject_(sys.maxint ** 4)
             self.assertIsInstance(buf, NSData)
-            v = NSKeyedUnarchiver.unarchiveObjectWithData_(buf)
+            v = self.unarchiverClass.unarchiveObjectWithData_(buf)
             self.assertIsInstance(v, long)
             self.assertEquals(v, sys.maxint ** 4)
 
         def testSimpleLists(self):
             o = []
-            buf = NSKeyedArchiver.archivedDataWithRootObject_(o)
+            buf = self.archiverClass.archivedDataWithRootObject_(o)
             self.assertIsInstance(buf, NSData)
-            v = NSKeyedUnarchiver.unarchiveObjectWithData_(buf)
+            v = self.unarchiverClass.unarchiveObjectWithData_(buf)
             self.assertIsInstance(v, list)
             self.assertEquals(v, o)
 
             o = [u"hello", 42]
-            buf = NSKeyedArchiver.archivedDataWithRootObject_(o)
+            buf = self.archiverClass.archivedDataWithRootObject_(o)
             self.assertIsInstance(buf, NSData)
-            v = NSKeyedUnarchiver.unarchiveObjectWithData_(buf)
+            v = self.unarchiverClass.unarchiveObjectWithData_(buf)
             self.assertIsInstance(v, list)
             self.assertEquals(v, o)
 
         def testSimpleTuples(self):
             o = ()
-            buf = NSKeyedArchiver.archivedDataWithRootObject_(o)
+            buf = self.archiverClass.archivedDataWithRootObject_(o)
             self.assertIsInstance(buf, NSData)
-            v = NSKeyedUnarchiver.unarchiveObjectWithData_(buf)
+            v = self.unarchiverClass.unarchiveObjectWithData_(buf)
             self.assertIsInstance(v, tuple)
             self.assertEquals(v, o)
 
             o = (u"hello", 42)
-            buf = NSKeyedArchiver.archivedDataWithRootObject_(o)
+            buf = self.archiverClass.archivedDataWithRootObject_(o)
             self.assertIsInstance(buf, NSData)
-            v = NSKeyedUnarchiver.unarchiveObjectWithData_(buf)
+            v = self.unarchiverClass.unarchiveObjectWithData_(buf)
             self.assertIsInstance(v, tuple)
             self.assertEquals(v, o)
 
         def testSimpleDicts(self):
             o = {}
-            buf = NSKeyedArchiver.archivedDataWithRootObject_(o)
+            buf = self.archiverClass.archivedDataWithRootObject_(o)
             self.assertIsInstance(buf, NSData)
-            v = NSKeyedUnarchiver.unarchiveObjectWithData_(buf)
+            v = self.unarchiverClass.unarchiveObjectWithData_(buf)
             self.assertIsInstance(v, dict)
             self.assertEquals(v, o)
 
             o = {u"hello": u"bar", 42: 1.5 }
-            buf = NSKeyedArchiver.archivedDataWithRootObject_(o)
+            buf = self.archiverClass.archivedDataWithRootObject_(o)
             self.assertIsInstance(buf, NSData)
-            v = NSKeyedUnarchiver.unarchiveObjectWithData_(buf)
+            v = self.unarchiverClass.unarchiveObjectWithData_(buf)
             self.assertIsInstance(v, dict)
             self.assertEquals(v, o)
 
@@ -154,17 +159,17 @@
                     u"hello": { 1:2 },
                     u"world": u"foobar"
                 }
-            buf = NSKeyedArchiver.archivedDataWithRootObject_(o)
+            buf = self.archiverClass.archivedDataWithRootObject_(o)
             self.assertIsInstance(buf, NSData)
-            v = NSKeyedUnarchiver.unarchiveObjectWithData_(buf)
+            v = self.unarchiverClass.unarchiveObjectWithData_(buf)
             self.assertIsInstance(v, dict)
             self.assertEquals(v, o)
 
             o = {}
             o[u'self'] = o
-            buf = NSKeyedArchiver.archivedDataWithRootObject_(o)
+            buf = self.archiverClass.archivedDataWithRootObject_(o)
             self.assertIsInstance(buf, NSData)
-            v = NSKeyedUnarchiver.unarchiveObjectWithData_(buf)
+            v = self.unarchiverClass.unarchiveObjectWithData_(buf)
             self.assertIsInstance(v, dict)
             self.assertIsObject(v[u'self'], v)
 
@@ -172,9 +177,9 @@
             o = [ 1, 2, 3, (5, (u'a', u'b'), 6), {1:2} ]
             o[-1] = o
 
-            buf = NSKeyedArchiver.archivedDataWithRootObject_(o)
+            buf = self.archiverClass.archivedDataWithRootObject_(o)
             self.assertIsInstance(buf, NSData)
-            v = NSKeyedUnarchiver.unarchiveObjectWithData_(buf)
+            v = self.unarchiverClass.unarchiveObjectWithData_(buf)
             self.assertIsInstance(v, list)
             self.assertIsObject(v[-1], v)
             self.assertEquals(v[:-1], o[:-1])
@@ -183,9 +188,9 @@
             o = a_classic_class()
             o.value = o
 
-            buf = NSKeyedArchiver.archivedDataWithRootObject_(o)
+            buf = self.archiverClass.archivedDataWithRootObject_(o)
             self.assertIsInstance(buf, NSData)
-            v = NSKeyedUnarchiver.unarchiveObjectWithData_(buf)
+            v = self.unarchiverClass.unarchiveObjectWithData_(buf)
 
             self.assertIsInstance(v, a_classic_class)
             self.assertIsObject(v.value, v)
@@ -203,9 +208,9 @@
             o2 = pickle.loads(b)
             print "+++", o2.value is o2
 
-            buf = NSKeyedArchiver.archivedDataWithRootObject_(o)
+            buf = self.archiverClass.archivedDataWithRootObject_(o)
             self.assertIsInstance(buf, NSData)
-            v = NSKeyedUnarchiver.unarchiveObjectWithData_(buf)
+            v = self.unarchiverClass.unarchiveObjectWithData_(buf)
 
             self.assertIsInstance(v, a_reducing_class)
             print type(v.value)
@@ -220,18 +225,18 @@
             i.attr = d
             l.append(i)
 
-            buf = NSKeyedArchiver.archivedDataWithRootObject_(l)
+            buf = self.archiverClass.archivedDataWithRootObject_(l)
             self.assertIsInstance(buf, NSData)
-            v = NSKeyedUnarchiver.unarchiveObjectWithData_(buf)
+            v = self.unarchiverClass.unarchiveObjectWithData_(buf)
 
             self.assertEquals(len(v), 1)
             self.assertEquals(dir(v[0]), dir(i))
             self.assertEquals(v[0].attr.keys(), [1])
             self.assertIsObject(v[0].attr[1], v)
 
-            buf = NSKeyedArchiver.archivedDataWithRootObject_(d)
+            buf = self.archiverClass.archivedDataWithRootObject_(d)
             self.assertIsInstance(buf, NSData)
-            v = NSKeyedUnarchiver.unarchiveObjectWithData_(buf)
+            v = self.unarchiverClass.unarchiveObjectWithData_(buf)
             self.assertIsObject(v[1][0].attr, v)
             
 
@@ -240,9 +245,9 @@
             o = a_classic_class()
             t = (o, o, o)
 
-            buf = NSKeyedArchiver.archivedDataWithRootObject_(t)
+            buf = self.archiverClass.archivedDataWithRootObject_(t)
             self.assertIsInstance(buf, NSData)
-            v = NSKeyedUnarchiver.unarchiveObjectWithData_(buf)
+            v = self.unarchiverClass.unarchiveObjectWithData_(buf)
 
             self.assertIsInstance(v, tuple)
             self.assertEquals(len(v), 3)
@@ -250,6 +255,10 @@
             self.assertIsObject(v[0], v[1])
             self.assertIsObject(v[0], v[2])
 
+    class TestArchiveSimple (TestKeyedArchiveSimple):
+        def setUp(self):
+            self.archiverClass = NSArchiver
+            self.unarchiverClass = NSUnarchiver
 
 
     class TestKeyedArchivePlainPython (TestCase, test.pickletester.AbstractPickleTests):
@@ -259,7 +268,7 @@
             test.pickletester.protocols = (2,)
 
         def tearDown(self):
-            test.pickletester.protoocols = self._protocols
+            test.pickletester.protocols = self._protocols
 
 
         def dumps(self, arg, proto=0, fast=0):
@@ -422,6 +431,22 @@
                 y = self.loads(s)
                 self.assertEqual(y._reduce_called, 1)
 
+    class TestArchivePlainPython (TestKeyedArchivePlainPython):
+        def setUp(self):
+            self._protocols = test.pickletester.protocols
+            test.pickletester.protocols = (2,)
+
+        def tearDown(self):
+            test.pickletester.protocols = self._protocols
+
+
+        def dumps(self, arg, proto=0, fast=0):
+            # Ignore proto and fast
+            return NSArchiver.archivedDataWithRootObject_(arg)
+
+        def loads(self, buf):
+            return NSUnarchiver.unarchiveObjectWithData_(buf)
+
 
     #
     # Disable testing of plain Archiving for now, need full support
@@ -475,6 +500,13 @@
             self.assertIsObject(p2.lst[0], p1)
            
 
+    class TestArchiveMixedGraphs (TestKeyedArchiveMixedGraphs):
+        def dumps(self, arg, proto=0, fast=0):
+            # Ignore proto and fast
+            return NSArchiver.archivedDataWithRootObject_(arg)
+
+        def loads(self, buf):
+            return NSUnarchiver.unarchiveObjectWithData_(buf)
 
 
 

------------------------------------------------------------------------------