[PyObjC-svn] r1996 - in trunk/pyobjc/pyobjc-core: . Doc Lib/objc Lib/objc/test Modules/objc Modules/objc/test

[email protected]
Newsgroups gmane.comp.python.pyobjc.cvs
Message-ID <[email protected]>
Author: ronaldoussoren
Date: Thu May  1 03:34:04 2008
New Revision: 1996

Log:
This adds support for the ``NSCoding`` protocol to
OC_PythonObject and friends. This basically means
that it is now possible to use an NSKeyedArchiver
to serialize any Python object that can be pickled.

Notes:
* This does not yet support NSArchiver, adding
  that should be trivial (basicly fall back to 
  using "classic" NSCoding methods when the coder
  doesn't support keyed coding)

* This support is experimental, the code passes
  unittests but I'm not yet fully convinced that
  the unittests are good enough.


Added:
   trunk/pyobjc/pyobjc-core/Lib/objc/_pycoder.py   (contents, props changed)
   trunk/pyobjc/pyobjc-core/Lib/objc/test/test_archive_python.py   (contents, props changed)
   trunk/pyobjc/pyobjc-core/Lib/objc/test/test_pickling_objc.py   (contents, props changed)
   trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonNumber.h   (contents, props changed)
   trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonNumber.m
Removed:
   trunk/pyobjc/pyobjc-core/Lib/objc/test/test_archiving.py
   trunk/pyobjc/pyobjc-core/Modules/objc/pycoder.h
   trunk/pyobjc/pyobjc-core/Modules/objc/pycoder.m
Modified:
   trunk/pyobjc/pyobjc-core/Doc/20api-notes-macosx.txt
   trunk/pyobjc/pyobjc-core/Lib/objc/__init__.py
   trunk/pyobjc/pyobjc-core/Lib/objc/_convenience.py
   trunk/pyobjc/pyobjc-core/Lib/objc/test/test_exceptions.py
   trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonArray.m
   trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonData.m
   trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonDate.m
   trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonDictionary.m
   trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonObject.h
   trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonObject.m
   trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonString.m
   trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonUnicode.m
   trunk/pyobjc/pyobjc-core/Modules/objc/libffi_support.m
   trunk/pyobjc/pyobjc-core/Modules/objc/objc-object.m
   trunk/pyobjc/pyobjc-core/Modules/objc/objc-runtime-compat.m
   trunk/pyobjc/pyobjc-core/Modules/objc/objc_support.m
   trunk/pyobjc/pyobjc-core/Modules/objc/objc_util.m
   trunk/pyobjc/pyobjc-core/Modules/objc/proxy-registry.m
   trunk/pyobjc/pyobjc-core/Modules/objc/pyobjc-api.h
   trunk/pyobjc/pyobjc-core/Modules/objc/pyobjc.h
   trunk/pyobjc/pyobjc-core/Modules/objc/test/exceptions.m
   trunk/pyobjc/pyobjc-core/NEWS.txt

Modified: trunk/pyobjc/pyobjc-core/Doc/20api-notes-macosx.txt
==============================================================================
--- trunk/pyobjc/pyobjc-core/Doc/20api-notes-macosx.txt	(original)
+++ trunk/pyobjc/pyobjc-core/Doc/20api-notes-macosx.txt	Thu May  1 03:34:04 2008
@@ -53,6 +53,14 @@
 Core Objective-C runtime
 ------------------------
 
+In Objective-C you can raise arbitrary values as exceptions using the ``@throw``
+syntax. PyObjC will only convert exception values that are Objective-C
+instances to Python exceptions, raising other values will cause a
+fatal error due to an uncaught exception.
+
+Apple's frameworks only raise instances of ``NSException``, and 
+other exception values are frowned upon (at best).
+
 Addressbook framework
 ---------------------
 

Modified: trunk/pyobjc/pyobjc-core/Lib/objc/__init__.py
==============================================================================
--- trunk/pyobjc/pyobjc-core/Lib/objc/__init__.py	(original)
+++ trunk/pyobjc/pyobjc-core/Lib/objc/__init__.py	Thu May  1 03:34:04 2008
@@ -11,6 +11,11 @@
 
 # Import the namespace from the _objc extension
 def _update(g=globals()):
+
+    # Dummy import of copy_reg, needed 
+    # for py2app.
+    import copy_reg
+
     import _objc
     for k,v in _objc.__dict__.iteritems():
         g.setdefault(k,v)
@@ -20,12 +25,7 @@
 from _convenience import *
 from _bridgesupport import *
 
-# Add useful utility functions below
-if platform == 'MACOSX':
-    from _dyld import *
-else:
-    from _gnustep import *
-
+from _dyld import *
 from _protocols import *
 from _descriptors import *
 from _category import *
@@ -35,6 +35,8 @@
 from _functions import *
 from _locking import *
 
+import _pycoder
+
 # Make sure our global autorelease pool is
 # recycled when the interpreter shuts down.
 # This avoids issue1402 in the python

Modified: trunk/pyobjc/pyobjc-core/Lib/objc/_convenience.py
==============================================================================
--- trunk/pyobjc/pyobjc-core/Lib/objc/_convenience.py	(original)
+++ trunk/pyobjc/pyobjc-core/Lib/objc/_convenience.py	Thu May  1 03:34:04 2008
@@ -556,6 +556,22 @@
     ('endswith', lambda self, pfx: self.hasSuffix_(pfx)),
 )
 
+
+CONVENIENCE_METHODS['copyWithZone:'] = (
+    ('__copy__', lambda self: self.copyWithZone_(None)),
+)
+
+NSKeyedArchiver = lookUpClass('NSKeyedArchiver')
+NSKeyedUnarchiver = lookUpClass('NSKeyedUnarchiver')
+def coder_deepcopy(self):
+    buf = NSKeyedArchiver.archivedDataWithRootObject_(self)
+    result = NSKeyedUnarchiver.unarchiveObjectWithData_(buf)
+    return result
+
+CONVENIENCE_METHODS['encodeWithCoder:'] = (
+    ('__deepcopy__', coder_deepcopy ),
+)
+
 CLASS_METHODS['NSNull'] = (
     ('__nonzero__',  lambda self: False ),
 )

Modified: trunk/pyobjc/pyobjc-core/Lib/objc/test/test_exceptions.py
==============================================================================
--- trunk/pyobjc/pyobjc-core/Lib/objc/test/test_exceptions.py	(original)
+++ trunk/pyobjc/pyobjc-core/Lib/objc/test/test_exceptions.py	Thu May  1 03:34:04 2008
@@ -74,5 +74,15 @@
                 u'key2\u1234\u2049': u'value2\u1234\u2049',
             })
 
+    def testRaisingStringsInObjectiveC(self):
+        # Bug #1741095, @throw anNSString
+
+        o = PyObjCTestExceptions.alloc().init()
+        try:
+            o.raiseAString()
+
+        except objc.error, e:
+            self.assertEquals(e._pyobjc_exc_, u"thrown string")
+
 if __name__ == "__main__":
     unittest.main()

Modified: trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonArray.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonArray.m	(original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonArray.m	Thu May  1 03:34:04 2008
@@ -77,6 +77,13 @@
 	return value;
 }
 
+-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie
+{
+	*cookie = 0;
+	Py_INCREF(value);
+	return value;
+}
+
 -(void)release
 {
 	/* See comment in OC_PythonUnicode */
@@ -291,21 +298,201 @@
 	PyObjC_END_WITH_GIL;
 }
 
-- (void)encodeWithCoder:(NSCoder*)coder
+-(void)encodeWithCoder:(NSCoder*)coder
 {
-	/* 
-	 * Forcefully disable coding for now, to avoid generating invalid
-	 * encoded streams.
-	 */        
-	[NSException raise:NSInvalidArgumentException format:@"PyObjC: Encoding python objects of type %s is not supported", value->ob_type->tp_name, coder];
-	
+	/*
+	 * Instances of 'list' and 'tuple' are encoded directly,
+	 * for other sequences use the generic pickle support code.
+	 */
+	if (1 && PyTuple_CheckExact(value)) {
+		if ([coder allowsKeyedCoding]) {
+			[coder encodeInt32:1 forKey:@"pytype"];
+		} else {
+			int v = 1;
+			[coder encodeValueOfObjCType:@encode(int) at:&v];
+		}
+		[super encodeWithCoder:coder];
+	} else if (1 && PyList_CheckExact(value)) {
+		if ([coder allowsKeyedCoding]) {
+			[coder encodeInt32:2 forKey:@"pytype"];
+		} else {
+			int v = 2;
+			[coder encodeValueOfObjCType:@encode(int) at:&v];
+		}
+		[super encodeWithCoder:coder];
+	} else {
+		if ([coder allowsKeyedCoding]) {
+			[coder encodeInt32:3 forKey:@"pytype"];
+		} else {
+			int v = 3;
+			[coder encodeValueOfObjCType:@encode(int) at:&v];
+		}
+		PyObjC_encodeWithCoder(value, coder);
+
+	}
+}
+
+/*
+ * A basic implementation of -initWithObjects:count:. This method is needed
+ * to support NSCoding for Python sequences.
+ */
+-(id)initWithObjects:(NSObject**)objects count:(NSUInteger)count
+{
+	NSUInteger i;
+	PyObjC_BEGIN_WITH_GIL
+		for  (i = 0; i < count; i++) {
+			PyObject* v = PyObjC_IdToPython(objects[i]);
+			if (v == NULL) {
+				PyObjC_GIL_FORWARD_EXC();
+			}
+			int r = PyList_Append(value,  v);
+			if (r == -1) {
+				PyObjC_GIL_FORWARD_EXC();
+			}
+			Py_DECREF(v);
+		}
+
+	PyObjC_END_WITH_GIL
+	return self;
 }
 
-- initWithCoder:(NSCoder*)coder
+/* 
+ * Helper method for initWithCoder, needed to deal with
+ * recursive objects (e.g. o.value = o)
+ */
+-(void)pyobjcSetValue:(NSObject*)other
 {
-	[NSException raise:NSInvalidArgumentException format:@"PyObjC: Decoding python objects is not supported", coder];
+	PyObject* v = PyObjC_IdToPython(other);
+	Py_XDECREF(value);
+	value = v;
+}
+
+-(id)initWithCoder:(NSCoder*)coder
+{
+	PyObject* t;
+	int code;
+	if ([coder allowsKeyedCoding]) {
+		code = [coder decodeInt32ForKey:@"pytype"];
+	} else {
+		[coder decodeValueOfObjCType:@encode(int) at:&code];
+	}
+
+	PyObjC_BEGIN_WITH_GIL
+		value = PyList_New(0);
+		if (value == NULL) {
+			PyObjC_GIL_FORWARD_EXC();
+		}
+	PyObjC_END_WITH_GIL
+
+	switch (code) {
+	case 1:
+	      [super initWithCoder:coder];
+	      PyObjC_BEGIN_WITH_GIL
+		      t = value;
+		      value = PyList_AsTuple(t);
+		      Py_DECREF(t);
+		      if (value == NULL) {
+				PyObjC_GIL_FORWARD_EXC();
+		      }
+	      PyObjC_END_WITH_GIL
+	      return self;
+
+	case 2:
+	      [super initWithCoder:coder];
+	      return self;
+
+	case 3:
+
+		if (PyObjC_Decoder != NULL) {
+			PyObjC_BEGIN_WITH_GIL
+				PyObject* cdr = PyObjC_IdToPython(coder);
+				if (cdr == NULL) {
+					PyObjC_GIL_FORWARD_EXC();
+				}
+
+				PyObject* setValue;
+				PyObject* selfAsPython = PyObjCObject_New(self, 0, YES);
+				setValue = PyObject_GetAttrString(selfAsPython, "pyobjcSetValue_");
+
+				PyObject* v = PyObject_CallFunction(PyObjC_Decoder, "OO", cdr, setValue);
+				Py_DECREF(cdr);
+				Py_DECREF(setValue);
+				Py_DECREF(selfAsPython);
+
+				if (v == NULL) {
+					PyObjC_GIL_FORWARD_EXC();
+				}
+
+				Py_XDECREF(value);
+				value = v;
+
+				NSObject* proxy = PyObjC_FindObjCProxy(value);
+				if (proxy == NULL) {
+					PyObjC_RegisterObjCProxy(value, self);
+				} else {
+					[self release];
+					[proxy retain];
+					self = (OC_PythonArray*)proxy;
+				}
+
+
+			PyObjC_END_WITH_GIL
+
+			return self;
+		}
+	}
+
+	[NSException raise:NSInvalidArgumentException
+			format:@"decoding Python objects is not supported"];
+	[self release];
 	return nil;
 }
 
 
+#if 1
+-(NSObject*)replacementObjectForArchiver:(NSArchiver*)archiver 
+{
+	(void)(archiver);
+	return self;
+}
+
+-(NSObject*)replacementObjectForKeyedArchiver:(NSKeyedArchiver*)archiver
+{
+	(void)(archiver);
+	return self;
+}
+
+-(NSObject*)replacementObjectForCoder:(NSKeyedArchiver*)archiver
+{
+	(void)(archiver);
+	return self;
+}
+
+-(NSObject*)replacementObjectForPortCoder:(NSKeyedArchiver*)archiver
+{
+	(void)(archiver);
+	return self;
+}
+
+-(Class)classForArchiver
+{
+	return [OC_PythonArray class];
+}
+
+-(Class)classForKeyedArchiver
+{
+	return [OC_PythonArray class];
+}
+
+-(Class)classForCoder
+{
+	return [OC_PythonArray class];
+}
+
+-(Class)classForPortCoder
+{
+	return [OC_PythonArray class];
+}
+#endif
+
 @end /* implementation OC_PythonArray */

Modified: trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonData.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonData.m	(original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonData.m	Thu May  1 03:34:04 2008
@@ -33,6 +33,14 @@
 	return value;
 }
 
+-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie
+{
+	*cookie = 0;
+	Py_INCREF(value);
+	return value;
+}
+
+
 -(void)release
 {
 	/* See comment in OC_PythonUnicode */

Modified: trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonDate.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonDate.m	(original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonDate.m	Thu May  1 03:34:04 2008
@@ -75,6 +75,12 @@
 	Py_INCREF(value);
 	return value;
 }
+-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie
+{
+	*cookie = 0;
+	Py_INCREF(value);
+	return value;
+}
 
 -(void)release
 {
@@ -101,18 +107,68 @@
 
 - (void)encodeWithCoder:(NSCoder*)coder
 {
-	/* 
-	 * Forcefully disable coding for now, to avoid generating invalid
-	 * encoded streams.
-	 */        
-	[NSException raise:NSInvalidArgumentException format:@"PyObjC: Encoding python objects of type %s is not supported", value->ob_type->tp_name, coder];
-	
+	PyObjC_encodeWithCoder(value, coder);
+}
+
+
+/* 
+ * Helper method for initWithCoder, needed to deal with
+ * recursive objects (e.g. o.value = o)
+ */
+-(void)pyobjcSetValue:(NSObject*)other
+{
+	PyObject* v = PyObjC_IdToPython(other);
+	Py_XDECREF(value);
+	value = v;
 }
 
 - initWithCoder:(NSCoder*)coder
 {
-	[NSException raise:NSInvalidArgumentException format:@"PyObjC: Decoding python objects is not supported", coder];
-	return nil;
+	value = NULL;
+
+	if (PyObjC_Decoder != NULL) {
+		PyObjC_BEGIN_WITH_GIL
+			PyObject* cdr = PyObjC_IdToPython(coder);
+			if (cdr == NULL) {
+				PyObjC_GIL_FORWARD_EXC();
+			}
+
+			PyObject* setValue;
+			PyObject* selfAsPython = PyObjCObject_New(self, 0, YES);
+			setValue = PyObject_GetAttrString(selfAsPython, "pyobjcSetValue_");
+
+			PyObject* v = PyObject_CallFunction(PyObjC_Decoder, "OO", cdr, setValue);
+			Py_DECREF(cdr);
+			Py_DECREF(setValue);
+			Py_DECREF(selfAsPython);
+
+			if (v == NULL) {
+				PyObjC_GIL_FORWARD_EXC();
+			}
+
+			Py_XDECREF(value);
+			value = v;
+
+			NSObject* proxy = PyObjC_FindObjCProxy(value);
+			if (proxy == NULL) {
+				PyObjC_RegisterObjCProxy(value, self);
+			} else {
+				[self release];
+				[proxy retain];
+				self = (OC_PythonDate*)proxy;
+			}
+
+
+		PyObjC_END_WITH_GIL
+
+		return self;
+
+	} else {
+		[NSException raise:NSInvalidArgumentException
+				format:@"decoding Python objects is not supported"];
+		return nil;
+
+	}
 }
 
 -(NSDate*)_make_oc_value

Modified: trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonDictionary.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonDictionary.m	(original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonDictionary.m	Thu May  1 03:34:04 2008
@@ -159,6 +159,12 @@
 	Py_INCREF(value);
 	return value;
 }
+-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie
+{
+	*cookie = 0;
+	Py_INCREF(value);
+	return value;
+}
 
 -(NSUInteger)count
 {
@@ -366,19 +372,193 @@
 }
 
 
-- (void)encodeWithCoder:(NSCoder*)coder
+- initWithObjects:(NSObject**)objects 
+	  forKeys:(NSObject**)keys 
+	    count:(NSUInteger)count
+{
+	/* This implementation is needed for our support for the NSCoding
+	 * protocol, NSDictionary's initWithCoder: will call this method.
+	 */
+	NSUInteger i;
+
+	PyObjC_BEGIN_WITH_GIL
+		for  (i = 0; i < count; i++) {
+			PyObject* k;
+			PyObject* v;
+			int r;
+
+			if (objects[i] == [NSNull null]) {
+				v = Py_None;
+				Py_INCREF(Py_None);
+			} else {
+				v = PyObjC_IdToPython(objects[i]);
+				if (v == NULL) {
+					PyObjC_GIL_FORWARD_EXC();
+				}
+			}
+
+			if (keys[i] == [NSNull null]) {
+				k = Py_None;
+				Py_INCREF(Py_None);
+			} else {
+				k = PyObjC_IdToPython(keys[i]);
+				if (k == NULL) {
+					PyObjC_GIL_FORWARD_EXC();
+				}
+			}
+
+			r = PyDict_SetItem(value, k, v);
+			Py_DECREF(k); Py_DECREF(v);
+
+			if (r == -1) {
+				PyObjC_GIL_FORWARD_EXC();
+			}
+		}
+	PyObjC_END_WITH_GIL
+	return self;
+}
+
+/* 
+ * Helper method for initWithCoder, needed to deal with
+ * recursive objects (e.g. o.value = o)
+ */
+-(void)pyobjcSetValue:(NSObject*)other
 {
-	/* 
-	 * Forcefully disable coding for now, to avoid generating invalid
-	 * encoded streams.
-	 */        
-	[NSException raise:NSInvalidArgumentException format:@"PyObjC: Encoding python objects of type %s is not supported", value->ob_type->tp_name, coder];
+	PyObject* v = PyObjC_IdToPython(other);
+	Py_XDECREF(value);
+	value = v;
 }
 
 - initWithCoder:(NSCoder*)coder
 {
-	[NSException raise:NSInvalidArgumentException format:@"PyObjC: Decoding python objects is not supported", coder];
+	int code;
+	if ([coder allowsKeyedCoding]) {
+		code = [coder decodeInt32ForKey:@"pytype"];
+	} else {
+		[coder decodeValueOfObjCType:@encode(int) at:&code];
+	}
+	switch (code) {
+	case 1:
+		PyObjC_BEGIN_WITH_GIL
+			value = PyDict_New();
+			if (value == NULL) {
+				PyObjC_GIL_FORWARD_EXC();
+			}
+		PyObjC_END_WITH_GIL
+
+		self = [super initWithCoder:coder];
+		return self;
+	
+	case 2:
+		if (PyObjC_Decoder != NULL) {
+			PyObjC_BEGIN_WITH_GIL
+				PyObject* cdr = PyObjC_IdToPython(coder);
+				if (cdr == NULL) {
+					PyObjC_GIL_FORWARD_EXC();
+				}
+
+				PyObject* setValue;
+				PyObject* selfAsPython = PyObjCObject_New(self, 0, YES);
+				setValue = PyObject_GetAttrString(selfAsPython, "pyobjcSetValue_");
+
+				PyObject* v = PyObject_CallFunction(PyObjC_Decoder, "OO", cdr, setValue);
+				Py_DECREF(cdr);
+				Py_DECREF(setValue);
+				Py_DECREF(selfAsPython);
+
+				if (v == NULL) {
+					PyObjC_GIL_FORWARD_EXC();
+				}
+
+				Py_XDECREF(value);
+				value = v;
+
+				NSObject* proxy = PyObjC_FindObjCProxy(value);
+				if (proxy == NULL) {
+					PyObjC_RegisterObjCProxy(value, self);
+				} else {
+					[self release];
+					[proxy retain];
+					self = (OC_PythonDictionary*)proxy;
+				}
+
+
+			PyObjC_END_WITH_GIL
+
+			return self;
+
+		} else {
+			[NSException raise:NSInvalidArgumentException
+					format:@"decoding Python objects is not supported"];
+			return nil;
+
+		}
+	}
+	[NSException raise:NSInvalidArgumentException
+			format:@"decoding Python objects is not supported"];
+	[self release];
 	return nil;
 }
 
+- (void)encodeWithCoder:(NSCoder*)coder
+{
+	if (1 && PyDict_CheckExact(value)) {
+		if ([coder allowsKeyedCoding]) {
+			[coder encodeInt32:1 forKey:@"pytype"];
+		} else {
+			int v = 1;
+			[coder encodeValueOfObjCType:@encode(int) at:&v];
+		}
+		[super encodeWithCoder:coder];
+
+	} else {
+		if ([coder allowsKeyedCoding]) {
+			[coder encodeInt32:2 forKey:@"pytype"];
+		} else {
+			int v = 2;
+			[coder encodeValueOfObjCType:@encode(int) at:&v];
+		}
+		PyObjC_encodeWithCoder(value, coder);
+
+	}
+}
+
+
+#if 1
+
+-(NSObject*)replacementObjectForArchiver:(NSArchiver*)archiver
+{
+	(void)archiver;
+	return self;
+}
+
+-(NSObject*)replacementObjectForKeyedArchiver:(NSKeyedArchiver*)archiver
+{
+	(void)archiver;
+	return self;
+}
+
+
+-(Class)classForArchiver
+{
+	return [OC_PythonDictionary class];
+}
+
+-(Class)classForKeyedArchiver
+{
+	return [OC_PythonDictionary class];
+}
+
+-(Class)classForCoder
+{
+	return [OC_PythonDictionary class];
+}
+
+-(Class)classForPortCoder
+{
+	return [OC_PythonDictionary class];
+}
+
+#endif
+
 @end  // interface OC_PythonDictionary

Modified: trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonObject.h
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonObject.h	(original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonObject.h	Thu May  1 03:34:04 2008
@@ -28,8 +28,15 @@
 #import <Foundation/NSDictionary.h>
 #import <Foundation/NSMethodSignature.h>
 
+extern PyObject* PyObjC_Encoder;
+extern PyObject* PyObjC_Decoder;
 
-@interface OC_PythonObject : NSProxy 
+extern void PyObjC_encodeWithCoder(PyObject* pyObject, NSCoder* coder);
+
+
+
+
+@interface OC_PythonObject : NSProxy  <NSCopying>
 {
   PyObject *pyObject;
 }
@@ -89,6 +96,18 @@
 /* These two are only present to *disable* coding, not implement it */
 - (void)encodeWithCoder:(NSCoder*)coder;
 - initWithCoder:(NSCoder*)coder;
++classFallbacksForKeyedArchiver;
+-(NSObject*)replacementObjectForArchiver:(NSObject*)archiver;
+-(NSObject*)replacementObjectForKeyedArchiver:(NSObject*)archiver;
+-(NSObject*)replacementObjectForCoder:(NSObject*)archiver;
+-(NSObject*)replacementObjectForPortCoder:(NSObject*)archiver;
+-(Class)classForArchiver;
+-(Class)classForKeyedArchiver;
++(Class)classForUnarchiver;
++(Class)classForKeyedUnarchiver;
+-(Class)classForCoder;
+-(Class)classForPortCoder;
+-(id)awakeAfterUsingCoder:(NSCoder*)coder;
 
 @end /* OC_PythonObject class interface */
 

Modified: trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonObject.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonObject.m	(original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonObject.m	Thu May  1 03:34:04 2008
@@ -40,7 +40,26 @@
 PyObject *OC_PythonObject_DepythonifyTable = NULL;
 PyObject *OC_PythonObject_PythonifyStructTable = NULL;
 
+static int       py_version = 0;
+PyObject* PyObjC_Encoder = NULL;
+PyObject* PyObjC_Decoder = NULL;
+PyObject* PyObjC_CopyFunc = NULL;
+
 @implementation OC_PythonObject
++ (void)setVersion:(int) version coder:(NSObject*)coder decoder:(NSObject*)decoder copier:(NSObject*)copier
+{
+	py_version = version;
+
+	Py_XDECREF(PyObjC_Encoder);
+	PyObjC_Encoder = PyObjC_IdToPython(coder);
+
+	Py_XDECREF(PyObjC_Decoder);
+	PyObjC_Decoder = PyObjC_IdToPython(decoder);
+
+	Py_XDECREF(PyObjC_CopyFunc);
+	PyObjC_CopyFunc = PyObjC_IdToPython(copier);
+}
+
 + (int)wrapPyObject:(PyObject *)argument toId:(id *)datum
 {
 	int r;
@@ -92,27 +111,25 @@
 			r = -1;
 		}
 	} else if (PyBool_Check(argument)) {
-		rval = [NSNumber 
-			numberWithBool:PyInt_AS_LONG (argument)];
+		rval = [OC_PythonNumber newWithPythonObject:argument]; 
+		PyObjC_RegisterObjCProxy(argument, rval);
 		r = 0;
+
 	} else if (PyInt_Check (argument)) {
-		rval = [NSNumber 
-			numberWithLong:PyInt_AS_LONG (argument)];
+		rval = [OC_PythonNumber newWithPythonObject:argument]; 
+		PyObjC_RegisterObjCProxy(argument, rval);
 		r = 0;
+
 	} else if (PyFloat_Check (argument)) {
-		rval = [NSNumber 
-			numberWithDouble:PyFloat_AS_DOUBLE (argument)];
+		rval = [OC_PythonNumber newWithPythonObject:argument]; 
+		PyObjC_RegisterObjCProxy(argument, rval);
 		r = 0;
+
 	} else if (PyLong_Check(argument)) {
-		rval = [NSNumber 
-			numberWithLongLong:PyLong_AsLongLong(argument)];
-		if (PyErr_Occurred()) {
-			/* Probably overflow */
-			rval = nil;
-			r = -1;
-		} else {
-			r = 0;
-		}
+		rval = [OC_PythonNumber newWithPythonObject:argument]; 
+		PyObjC_RegisterObjCProxy(argument, rval);
+		r = 0;
+
 	} else if (PyList_Check(argument) || PyTuple_Check(argument)) {
 		rval = [OC_PythonArray 
 			newWithPythonObject:argument];
@@ -233,6 +250,7 @@
 		/* Check if the object is "sequence-like" */
 		instance = [OC_PythonArray depythonifyObject:obj];
 		if (instance != nil) {
+			PyObjC_RegisterObjCProxy(obj, instance);
 			PyObjC_GIL_RETURN(instance);
 		} 
 		if (PyErr_Occurred()) {
@@ -242,6 +260,7 @@
 		/* Check if the object is "mapping-like" */
 		instance = [OC_PythonDictionary depythonifyObject:obj];
 		if (instance != nil) {
+			PyObjC_RegisterObjCProxy(obj, instance);
 			PyObjC_GIL_RETURN(instance);
 		} 
 		if (PyErr_Occurred()) {
@@ -341,13 +360,47 @@
 {
 	PyObjC_BEGIN_WITH_GIL
 		PyObjC_UnregisterObjCProxy(pyObject, self);
-		Py_XDECREF(pyObject);
+		Py_XDECREF(pyObject); pyObject = NULL;
 
 	PyObjC_END_WITH_GIL
 
 	[super dealloc];
 }
 
+-copyWithZone:(NSZone*)zone
+{
+	(void)zone;
+	NSObject* result = nil;
+	PyObject* copy;
+
+	if (PyObjC_CopyFunc == NULL) {
+		[NSException raise:NSInvalidArgumentException
+					format:@"cannot copy Python objects"];
+
+	} else {
+		PyObjC_BEGIN_WITH_GIL
+			copy = PyObject_CallFunction(PyObjC_CopyFunc, "O", pyObject);
+			if (copy == NULL) {
+				PyObjC_GIL_FORWARD_EXC();
+			}
+
+			result = PyObjC_PythonToId(copy);
+			Py_DECREF(copy);
+
+		PyObjC_END_WITH_GIL
+	}
+
+	if (result) {
+		[result retain];
+	}
+	return result;
+}
+
+-copy
+{
+	return [self copyWithZone:NULL];
+}
+
 /* Undocumented method used by NSLog, this seems to work. */
 - (NSString*) _copyDescription
 {
@@ -509,6 +562,22 @@
 	PyObjC_END_WITH_GIL
 }
 
++ (NSMethodSignature *) methodSignatureForSelector:(SEL) sel
+{
+	Method		   m;
+
+	m = class_getInstanceMethod(self, sel);
+	if (m) {
+		/* A real Objective-C method */
+		return [NSMethodSignature 
+		    signatureWithObjCTypes:method_getTypeEncoding(m)];
+	}
+
+	[NSException raise:NSInvalidArgumentException 
+		format:@"Class %s: no such selector: %s", 
+		class_getName(self), sel_getName(sel)];
+	return nil;
+}
 
 - (NSMethodSignature *) methodSignatureForSelector:(SEL) sel
 {
@@ -595,7 +664,97 @@
 		[invocation setReturnValue:&b];
 
 		return YES;
-	}
+
+	} else if (sel_isEqual(aSelector, @selector(classForKeyedArchiver))){
+		Class	c;
+
+		c = [self classForKeyedArchiver];
+		[invocation setReturnValue:&c];
+
+		return YES;
+
+	} else if (sel_isEqual(aSelector, @selector(classForArchiver))){
+		Class	c;
+
+		c = [self classForArchiver];
+		[invocation setReturnValue:&c];
+
+		return YES;
+
+	} else if (sel_isEqual(aSelector, @selector(classForCoder))){
+		Class	c;
+
+		c = [self classForCoder];
+		[invocation setReturnValue:&c];
+
+		return YES;
+
+	} else if (sel_isEqual(aSelector, @selector(classForPortCoder))){
+		Class	c;
+
+		c = [self classForPortCoder];
+		[invocation setReturnValue:&c];
+
+		return YES;
+
+	} else if (sel_isEqual(aSelector, @selector(replacementObjectForKeyedArchiver:))){
+		NSObject*	c;
+		NSObject* archiver;
+
+		[invocation getArgument:&archiver atIndex:2];
+		c = [self replacementObjectForKeyedArchiver:archiver];
+		[invocation setReturnValue:&c];
+
+		return YES;
+
+	} else if (sel_isEqual(aSelector, @selector(replacementObjectForArchiver:))){
+		NSObject*	c;
+		NSObject* archiver;
+
+		[invocation getArgument:&archiver atIndex:2];
+		c = [self replacementObjectForArchiver:archiver];
+		[invocation setReturnValue:&c];
+
+		return YES;
+
+	} else if (sel_isEqual(aSelector, @selector(replacementObjectForCoder:))){
+		NSObject*	c;
+		NSObject* archiver;
+
+		[invocation getArgument:&archiver atIndex:2];
+		c = [self replacementObjectForCoder:archiver];
+		[invocation setReturnValue:&c];
+
+		return YES;
+
+	} else if (sel_isEqual(aSelector, @selector(replacementObjectForPortCoder:))){
+		NSObject*	c;
+		NSObject* archiver;
+
+		[invocation getArgument:&archiver atIndex:2];
+		c = [self replacementObjectForPortCoder:archiver];
+		[invocation setReturnValue:&c];
+
+		return YES;
+
+	} else if (sel_isEqual(aSelector, @selector(copy))) {
+		NSObject*	c;
+
+		c = [self copy];
+		[invocation setReturnValue:&c];
+
+		return YES;
+
+	} else if (sel_isEqual(aSelector, @selector(copyWithZone:))) {
+		NSObject*	c;
+		NSZone* zone;
+
+		[invocation getArgument:&zone atIndex:2];
+		c = [self copyWithZone:zone];
+		[invocation setReturnValue:&c];
+
+		return YES;
+	} 
 
 	return NO;
 }
@@ -713,11 +872,44 @@
 - (PyObject *)  __pyobjc_PythonObject__
 {
 	PyObjC_BEGIN_WITH_GIL
+#if 1
+		if (pyObject == NULL) {
+#if 1
+			PyObject* r = PyObjCObject_New(self, PyObjCObject_kDEFAULT, YES);
+			PyObjC_GIL_RETURN(r);
+#else
+			Py_INCREF(Py_None);
+			PyObjC_GIL_RETURN(Py_None);
+#endif
+		} else 
+#endif
+		{
+			Py_XINCREF(pyObject);
+			PyObjC_GIL_RETURN(pyObject);
+		}
+	PyObjC_END_WITH_GIL
+}
+-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie
+{
+	PyObjC_BEGIN_WITH_GIL
+	*cookie = 0;
 	Py_INCREF(pyObject);
-	PyObjC_GIL_RETURN(pyObject);
 	PyObjC_END_WITH_GIL
+	return pyObject;
 }
 
++(PyObject*)__pyobjc_PythonTransient__:(int*)cookie
+{
+	PyObject* rval;
+	
+	PyObjC_BEGIN_WITH_GIL
+	rval =  PyObjCClass_New([OC_PythonObject class]);
+	*cookie = 0;
+	PyObjC_END_WITH_GIL
+
+
+	return rval;
+}
 
 /*
  * Implementation for Key-Value Coding.
@@ -1065,21 +1257,135 @@
     PyObjC_END_WITH_GIL
 }
 
+
+/*
+ * Support of the NSCoding protocol
+ */
 - (void)encodeWithCoder:(NSCoder*)coder
 {
-	PyObjC_encode_object(coder, [self pyObject]);
+	PyObjC_encodeWithCoder(pyObject, coder);
+}
+
+/* 
+ * Helper method for initWithCoder, needed to deal with
+ * recursive objects (e.g. o.value = o)
+ */
+-(void)pyobjcSetValue:(NSObject*)other
+{
+	PyObject* value = PyObjC_IdToPython(other);
+	Py_XDECREF(pyObject);
+	pyObject = value;
 }
 
 - initWithCoder:(NSCoder*)coder
 {
-	pyObject = PyObjC_decode_object(coder);
-	if (pyObject == NULL) {
-		[self release];
+	pyObject = NULL;
+
+	if (PyObjC_Decoder != NULL) {
+		PyObjC_BEGIN_WITH_GIL
+			PyObject* cdr = PyObjC_IdToPython(coder);
+			if (cdr == NULL) {
+				PyObjC_GIL_FORWARD_EXC();
+			}
+
+			PyObject* setValue;
+			PyObject* selfAsPython = PyObjCObject_New(self, 0, YES);
+			setValue = PyObject_GetAttrString(selfAsPython, "pyobjcSetValue_");
+
+			PyObject* v = PyObject_CallFunction(PyObjC_Decoder, "OO", cdr, setValue);
+			Py_DECREF(cdr);
+			Py_DECREF(setValue);
+			Py_DECREF(selfAsPython);
+
+			if (v == NULL) {
+				PyObjC_GIL_FORWARD_EXC();
+			}
+
+			Py_XDECREF(pyObject);
+			pyObject = v;
+
+			NSObject* proxy = PyObjC_FindObjCProxy(pyObject);
+			if (proxy == NULL) {
+				PyObjC_RegisterObjCProxy(pyObject, self);
+			} else {
+				[self release];
+				[proxy retain];
+				self = (OC_PythonObject*)proxy;
+			}
+
+
+		PyObjC_END_WITH_GIL
+
+		return self;
+
+	} else {
+		[NSException raise:NSInvalidArgumentException
+				format:@"decoding Python objects is not supported"];
 		return nil;
+
 	}
+}
+
+-(id)awakeAfterUsingCoder:(NSCoder*)coder
+{
+	(void)coder;
 	return self;
 }
 
+-(NSObject*)replacementObjectForArchiver:(NSObject*)archiver
+{
+	(void)archiver;
+	return (NSObject*)self;
+}
+
+-(NSObject*)replacementObjectForKeyedArchiver:(NSObject*)archiver
+{
+	(void)archiver;
+	return (NSObject*)self;
+}
+
+-(NSObject*)replacementObjectForCoder:(NSObject*)archiver
+{
+	(void)archiver;
+	return (NSObject*)self;
+}
+
+-(NSObject*)replacementObjectForPortCoder:(NSObject*)archiver
+{
+	(void)archiver;
+	return (NSObject*)self;
+}
+
+-(Class)classForArchiver
+{
+	return [OC_PythonObject class];
+}
+
+-(Class)classForKeyedArchiver
+{
+	return [OC_PythonObject class];
+}
+
++(Class)classForUnarchiver
+{
+	return [OC_PythonObject class];
+}
+
++(Class)classForKeyedUnarchiver
+{
+	return [OC_PythonObject class];
+}
+
+-(Class)classForCoder
+{
+	return [OC_PythonObject class];
+}
+
+-(Class)classForPortCoder
+{
+	return [OC_PythonObject class];
+}
+
 /* NOTE: NSProxy does not implement isKindOfClass on Leopard, therefore we 
  * have to provide it ourself.
  *
@@ -1094,4 +1400,86 @@
 	return NO;
 }
 
+/* 
+ * This is needed to be able to add a python object to a
+ * NSArray and then use array.description()
+ */
+-(BOOL)isNSString__
+{
+	return NO;
+}
+
++classFallbacksForKeyedArchiver
+{
+	return nil;
+}
+
+
+
 @end /* OC_PythonObject class implementation */
+
+
+#if 0
+/*
+ * Generic implementation of the core of initWithCoder,
+ * returns a reference to a new proxy object.
+ *
+ * NOTE: an implementation of initWithCoder will have to
+ * release self and retain (and then return) the result of 
+ * this function.
+ */
+NSObject* PyObjC_decodeWithCoder(NSCoder* coder)
+{
+	PyObject* pyObject = NULL;
+	NSObject* result = nil;
+
+	if (PyObjC_Decoder != NULL) {
+		PyObjC_BEGIN_WITH_GIL
+			PyObject* cdr = PyObjC_IdToPython(coder);
+			if (cdr == NULL) {
+				PyObjC_GIL_FORWARD_EXC();
+			}
+
+			pyObject = PyObject_CallFunction(PyObjC_Decoder, "O", cdr);
+			Py_DECREF(cdr);
+			if (pyObject == NULL) {
+				PyObjC_GIL_FORWARD_EXC();
+			}
+
+			result = PyObjC_PythonToId(pyObject);
+			Py_DECREF(pyObject);
+
+		PyObjC_END_WITH_GIL
+		return result;
+	} else {
+		[NSException raise:NSInvalidArgumentException
+				format:@"decoding Python objects is not supported"];
+		return nil;
+
+	}
+}
+#endif
+
+void PyObjC_encodeWithCoder(PyObject* pyObject, NSCoder* coder)
+{
+	if (PyObjC_Encoder != NULL) {
+		PyObjC_BEGIN_WITH_GIL
+			PyObject* cdr = PyObjC_IdToPython(coder);
+			if (cdr == NULL) {
+            			PyObjC_GIL_FORWARD_EXC();
+			}
+
+			PyObject* r = PyObject_CallFunction(PyObjC_Encoder, "OO", pyObject, cdr);
+			Py_DECREF(cdr);
+			if (r == NULL) {
+            			PyObjC_GIL_FORWARD_EXC();
+			}
+			Py_DECREF(r);
+
+		PyObjC_END_WITH_GIL
+
+	} else {
+		[NSException raise:NSInvalidArgumentException
+				format:@"encoding Python objects is not supported"];
+	}
+}

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	Thu May  1 03:34:04 2008
@@ -26,6 +26,14 @@
 	return value;
 }
 
+-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie
+{
+	*cookie = 0;
+	Py_INCREF(value);
+	return value;
+}
+
+
 -(void)release
 {
 	/* See comment in OC_PythonUnicode */
@@ -55,10 +63,31 @@
 	}
 	if (!realObject) {
 #if defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3
+		/* This sucks big-time: +defaultCStringEncoding is not necessarily 
+		 * related to the system encoding. The code below tries to
+		 * compensate...
+		 */
+		NSStringEncoding encoding = [NSString defaultCStringEncoding];
+		const char* pycoding = PyUnicode_GetDefaultEncoding();
+		if (strcmp(pycoding, "ascii")) {
+			encoding = NSASCIIStringEncoding;
+		} else if (strcmp(pycoding, "utf-8")) {
+			encoding = NSUTF8StringEncoding;
+		} else if (strcmp(pycoding, "latin1")) {
+			encoding = NSISOLatin1StringEncoding;
+		} else if (strcmp(pycoding, "macroman")) {
+			encoding = NSMacOSRomanStringEncoding;
+		} else {
+			/* A very non-standard system encoding, use
+			 * whatever Cocoa believes to be the encoding.
+			 */
+		}
+
+
 		realObject = [[NSString alloc]
 			initWithBytesNoCopy:PyString_AS_STRING(value)
 			length:(NSUInteger)PyString_GET_SIZE(value)
-			encoding:[NSString defaultCStringEncoding]
+			encoding:encoding
 			freeWhenDone:NO];
 
 #else
@@ -96,4 +125,185 @@
 	[((NSString *)[self __realObject__]) getCharacters:buffer range:aRange];
 }
 
+
+- (id)initWithCharactersNoCopy:(unichar *)characters 
+			length:(NSUInteger)length 
+		  freeWhenDone:(BOOL)flag
+{
+#ifndef PyObjC_UNICODE_FAST_PATH
+# error "Wide UNICODE builds are not supported at the moment"
+#endif
+	PyObjC_BEGIN_WITH_GIL
+		PyObject* v;
+		v = PyUnicode_FromUnicode((Py_UNICODE*)characters, length);
+		if (v == NULL) {
+			PyObjC_GIL_FORWARD_EXC();
+		}
+
+		value = PyUnicode_AsEncodedString(v, NULL, NULL);
+		Py_DECREF(v);
+		if (value == NULL) {
+			PyObjC_GIL_FORWARD_EXC();
+		}
+
+	PyObjC_END_WITH_GIL;
+	if (flag) {
+		free(characters);
+	}
+	return self;
+}
+
+
+/* 
+ * Helper method for initWithCoder, needed to deal with
+ * recursive objects (e.g. o.value = o)
+ */
+-(void)pyobjcSetValue:(NSObject*)other
+{
+	PyObject* v = PyObjC_IdToPython(other);
+	Py_XDECREF(value);
+	value = v;
+}
+
+- initWithCoder:(NSCoder*)coder
+{
+	int v;
+	
+	if ([coder allowsKeyedCoding]) {
+		v = [coder decodeInt32ForKey:@"pytype"];
+	} else {
+		[coder decodeValueOfObjCType:@encode(int) at:&v];
+	}
+	if (v == 1) {
+		[super initWithCoder:coder];
+	} else if (v == 2) {
+
+		if (PyObjC_Decoder != NULL) {
+			PyObjC_BEGIN_WITH_GIL
+				PyObject* cdr = PyObjC_IdToPython(coder);
+				if (cdr == NULL) {
+					PyObjC_GIL_FORWARD_EXC();
+				}
+
+				PyObject* setValue;
+				PyObject* selfAsPython = PyObjCObject_New(self, 0, YES);
+				setValue = PyObject_GetAttrString(selfAsPython, "pyobjcSetValue_");
+
+				PyObject* v = PyObject_CallFunction(PyObjC_Decoder, "OO", cdr, setValue);
+				Py_DECREF(cdr);
+				Py_DECREF(setValue);
+				Py_DECREF(selfAsPython);
+
+				if (v == NULL) {
+					PyObjC_GIL_FORWARD_EXC();
+				}
+
+				Py_XDECREF(value);
+				value = v;
+
+				NSObject* proxy = PyObjC_FindObjCProxy(value);
+				if (proxy == NULL) {
+					PyObjC_RegisterObjCProxy(value, self);
+				} else {
+					[self release];
+					[proxy retain];
+					self = (OC_PythonObject*)proxy;
+				}
+
+
+			PyObjC_END_WITH_GIL
+
+			return self;
+
+		} else {
+			[NSException raise:NSInvalidArgumentException
+					format:@"decoding Python objects is not supported"];
+			return nil;
+
+		}
+
+	} else {
+		[NSException raise:NSInvalidArgumentException
+				format:@"encoding Python objects is not supported"];
+	}
+	return self;
+}
+
+-(void)encodeWithCoder:(NSCoder*)coder
+{
+	if (PyString_CheckExact(value)) {
+		if ([coder allowsKeyedCoding]) {
+			[coder encodeInt32:1 forKey:@"pytype"];
+		} else {
+			int v = 1;
+			[coder encodeValueOfObjCType:@encode(int) at:&v];
+		}
+		[super encodeWithCoder:coder];
+	} else {
+		if ([coder allowsKeyedCoding]) {
+			[coder encodeInt32:2 forKey:@"pytype"];
+		} else {
+			int v = 2;
+			[coder encodeValueOfObjCType:@encode(int) at:&v];
+		}
+
+		PyObjC_encodeWithCoder(value, coder);
+
+	}
+}
+
+#if 1
+-(NSObject*)replacementObjectForArchiver:(NSArchiver*)archiver 
+{
+	(void)(archiver);
+	return self;
+}
+
+-(NSObject*)replacementObjectForKeyedArchiver:(NSKeyedArchiver*)archiver
+{
+	(void)(archiver);
+	return self;
+}
+
+-(NSObject*)replacementObjectForCoder:(NSKeyedArchiver*)archiver
+{
+	(void)(archiver);
+	return self;
+}
+
+-(NSObject*)replacementObjectForPortCoder:(NSKeyedArchiver*)archiver
+{
+	(void)(archiver);
+	return self;
+}
+
+-(Class)classForArchiver
+{
+	return [OC_PythonString class];
+}
+
+-(Class)classForKeyedArchiver
+{
+	return [OC_PythonString class];
+}
+
+-(Class)classForCoder
+{
+	return [OC_PythonString class];
+}
+
+-(Class)classForPortCoder
+{
+	return [OC_PythonString class];
+}
+
+/* Ensure that we can be unarchived as a generic string by pure ObjC
+ * code.
+ */
++classFallbacksForKeyedArchiver
+{
+	return [NSArray arrayWithObject:@"NSString"];
+}
+#endif
+
 @end /* implementation OC_PythonString */

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	Thu May  1 03:34:04 2008
@@ -20,12 +20,22 @@
 	return self;
 }
 
+
 -(PyObject*)__pyobjc_PythonObject__
 {
 	Py_INCREF(value);
 	return value;
 }
 
+-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie
+{
+	*cookie = 0;
+	Py_INCREF(value);
+	return value;
+}
+
+
+
 -(void)release
 {
 	/* There is small race condition when an object is almost deallocated
@@ -134,6 +144,187 @@
 	[((NSString *)[self __realObject__]) getCharacters:buffer range:aRange];
 }
 
+
 #endif /* PyObjC_UNICODE_FAST_PATH */
 
+/*
+ * NSCoding support 
+ *
+ * We need explicit NSCoding support to get full fidelity, otherwise we'll
+ * get archived as generic NSStrings.
+ */
+- (id)initWithCharactersNoCopy:(unichar *)characters 
+			length:(NSUInteger)length 
+		  freeWhenDone:(BOOL)flag
+{
+#ifndef PyObjC_UNICODE_FAST_PATH
+# error "Wide UNICODE builds are not supported at the moment"
+#endif
+	PyObjC_BEGIN_WITH_GIL
+		value = PyUnicode_FromUnicode((Py_UNICODE*)characters, length);
+		if (value == NULL) {
+			PyObjC_GIL_FORWARD_EXC();
+		}
+
+	PyObjC_END_WITH_GIL;
+	if (flag) {
+		free(characters);
+	}
+	return self;
+}
+
+
+/* 
+ * Helper method for initWithCoder, needed to deal with
+ * recursive objects (e.g. o.value = o)
+ */
+-(void)pyobjcSetValue:(NSObject*)other
+{
+	PyObject* v = PyObjC_IdToPython(other);
+	Py_XDECREF(value);
+	value = v;
+}
+
+- initWithCoder:(NSCoder*)coder
+{
+	int ver;
+	if ([coder allowsKeyedCoding]) {
+		ver = [coder decodeInt32ForKey:@"pytype"];
+	} else {
+		[coder decodeValueOfObjCType:@encode(int) at:&ver];
+	}
+	if (ver == 1) {
+		self = [super initWithCoder:coder];
+		return self;
+	} else if (ver == 2) {
+
+		if (PyObjC_Decoder != NULL) {
+			PyObjC_BEGIN_WITH_GIL
+				PyObject* cdr = PyObjC_IdToPython(coder);
+				if (cdr == NULL) {
+					PyObjC_GIL_FORWARD_EXC();
+				}
+
+				PyObject* setValue;
+				PyObject* selfAsPython = PyObjCObject_New(self, 0, YES);
+				setValue = PyObject_GetAttrString(selfAsPython, "pyobjcSetValue_");
+
+				PyObject* v = PyObject_CallFunction(PyObjC_Decoder, "OO", cdr, setValue);
+				Py_DECREF(cdr);
+				Py_DECREF(setValue);
+				Py_DECREF(selfAsPython);
+
+				if (v == NULL) {
+					PyObjC_GIL_FORWARD_EXC();
+				}
+
+				Py_XDECREF(value);
+				value = v;
+
+				NSObject* proxy = PyObjC_FindObjCProxy(value);
+				if (proxy == NULL) {
+					PyObjC_RegisterObjCProxy(value, self);
+				} else {
+					[self release];
+					[proxy retain];
+					self = (OC_PythonUnicode*)proxy;
+				}
+
+
+			PyObjC_END_WITH_GIL
+
+			return self;
+
+		} else {
+			[NSException raise:NSInvalidArgumentException
+					format:@"decoding Python objects is not supported"];
+			return nil;
+
+		}
+	} else {
+		[NSException raise:NSInvalidArgumentException
+			format:@"encoding Python objects is not supported"];
+		return nil;
+	}
+}
+
+-(void)encodeWithCoder:(NSCoder*)coder
+{
+	if (PyUnicode_CheckExact(value)) {
+		if ([coder allowsKeyedCoding]) {
+			[coder encodeInt32:1 forKey:@"pytype"];
+		} else {
+			int v = 1;
+			[coder encodeValueOfObjCType:@encode(int) at:&v];
+		}
+		[super encodeWithCoder:coder];
+	} else {
+		if ([coder allowsKeyedCoding]) {
+			[coder encodeInt32:2 forKey:@"pytype"];
+		} else {
+			int v = 2;
+			[coder encodeValueOfObjCType:@encode(int) at:&v];
+		}
+
+		PyObjC_encodeWithCoder(value, coder);
+	}
+}
+
+#if 1
+
+
+-(NSObject*)replacementObjectForArchiver:(NSArchiver*)archiver 
+{
+	(void)(archiver);
+	return self;
+}
+
+-(NSObject*)replacementObjectForKeyedArchiver:(NSKeyedArchiver*)archiver
+{
+	(void)(archiver);
+	return self;
+}
+
+-(NSObject*)replacementObjectForCoder:(NSKeyedArchiver*)archiver
+{
+	(void)(archiver);
+	return self;
+}
+
+-(NSObject*)replacementObjectForPortCoder:(NSKeyedArchiver*)archiver
+{
+	(void)(archiver);
+	return self;
+}
+
+-(Class)classForArchiver
+{
+	return [OC_PythonUnicode class];
+}
+
+-(Class)classForKeyedArchiver
+{
+	return [OC_PythonUnicode class];
+}
+
+-(Class)classForCoder
+{
+	return [OC_PythonUnicode class];
+}
+
+-(Class)classForPortCoder
+{
+	return [OC_PythonUnicode class];
+}
+
+/* Ensure that we can be unarchived as a generic string by pure ObjC
+ * code.
+ */
++classFallbacksForKeyedArchiver
+{
+	return [NSArray arrayWithObject:@"NSString"];
+}
+
+#endif
+
 @end /* implementation OC_PythonUnicode */

Modified: trunk/pyobjc/pyobjc-core/Modules/objc/libffi_support.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/libffi_support.m	(original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/libffi_support.m	Thu May  1 03:34:04 2008
@@ -1765,7 +1765,7 @@
 
 		if (stubUserdata->argCount == methinfo->ob_size - 1 && !haveVarArgs && !haveVarKwds) {
 			/* OK */
-		} else if (stubUserdata->argCount <= 1 && haveVarArgs && haveVarKwds) {
+		} else if ((stubUserdata->argCount <= 1) && haveVarArgs && haveVarKwds) {
 			/* OK: 
 			 *    def m(self, *args, **kwds), or 
 			 *    def m(*args, **kwds)  
@@ -1847,7 +1847,7 @@
 
 		if (stubUserdata->argCount == methinfo->ob_size - 1&& !haveVarArgs && !haveVarKwds) {
 			/* OK */
-		} else if (stubUserdata->argCount == 0 && haveVarArgs && haveVarKwds) {
+		} else if ((stubUserdata->argCount <= 1) && haveVarArgs && haveVarKwds) {
 			/* OK */
 		} else {
 			/* Wrong number of arguments, raise an error */

Modified: trunk/pyobjc/pyobjc-core/Modules/objc/objc-object.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/objc-object.m	(original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/objc-object.m	Thu May  1 03:34:04 2008
@@ -876,29 +876,3 @@
 			((PyObjCObject*)object)->objc_object, object);
 	((PyObjCObject*)object)->objc_object = nil;
 }
-
-PyObject* PyObjCObject_NewTransient(id objc_object, int* cookie)
-{
-	PyObject* result;
-
-	result = PyObjC_FindPythonProxy(objc_object);
-	if (result) {
-		*cookie = 0;
-		return result;
-	}
-
-	*cookie = 1;
-	result = PyObjCObject_New(objc_object, 
-			PyObjCObject_kSHOULD_NOT_RELEASE, NO);
-	return result;
-}
-
-void PyObjCObject_ReleaseTransient(PyObject* proxy, int cookie)
-{
-	if (cookie && proxy->ob_refcnt != 1) {
-		CFRetain(PyObjCObject_GetObject(proxy));
-		((PyObjCObject*)proxy)-> flags &= ~PyObjCObject_kSHOULD_NOT_RELEASE;
-	} 
-	Py_DECREF(proxy);
-}
-

Modified: trunk/pyobjc/pyobjc-core/Modules/objc/objc-runtime-compat.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/objc-runtime-compat.m	(original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/objc-runtime-compat.m	Thu May  1 03:34:04 2008
@@ -8,6 +8,11 @@
 #define PYOBJC_COMPAT_IMPL
 #include "pyobjc.h"
 
+
+
+
+#if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) &&!defined(__OBJC2__)
+
 BOOL PyObjC_class_isSubclassOf(Class child, Class parent)
 {
 	if (parent == nil) return YES;
@@ -16,15 +21,11 @@
 		if (child == parent) {
 			return YES;
 		}
-		child = class_getSuperclass(child);
+		child = PyObjC_class_getSuperclass(child);
 	}
 	return NO;
 }
 
-
-
-#if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) &&!defined(__OBJC2__)
-
 #import <mach-o/dyld.h>
 #import <mach-o/getsect.h>
 #import <mach-o/loader.h>
@@ -909,6 +910,20 @@
 
 #else
 
+
+BOOL PyObjC_class_isSubclassOf(Class child, Class parent)
+{
+	if (parent == nil) return YES;
+
+	while (child != nil) {
+		if (child == parent) {
+			return YES;
+		}
+		child = class_getSuperclass(child);
+	}
+	return NO;
+}
+
 BOOL PyObjC_class_addMethodList(Class cls,
 		struct PyObjC_method* list, unsigned int count)
 {

Modified: trunk/pyobjc/pyobjc-core/Modules/objc/objc_support.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/objc_support.m	(original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/objc_support.m	Thu May  1 03:34:04 2008
@@ -37,6 +37,9 @@
 @interface NSObject (PyObjCSupport)
 -(PyObject*)__pyobjc_PythonObject__;
 +(PyObject*)__pyobjc_PythonObject__;
+
+-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie;
++(PyObject*)__pyobjc_PythonTransient__:(int*)cookie;
 @end /* PyObjCSupport */
 
 @implementation NSObject (PyObjCSupport)
@@ -69,11 +72,32 @@
 	return rval;
 }
 
+-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie
+{
+	PyObject* result = PyObjC_FindPythonProxy(self);
+	if (result) {
+		*cookie = 0;
+		return result;
+	}
+
+	*cookie = 1;
+	return PyObjCObject_New(self, PyObjCObject_kSHOULD_NOT_RELEASE, NO);
+}
+
++(PyObject*)__pyobjc_PythonTransient__:(int*)cookie
+{
+	*cookie = 0;
+	return (PyObject *)PyObjCClass_New(self);
+}
+
 @end /* PyObjCSupport */
 
 @interface NSProxy (PyObjCSupport)
 -(PyObject*)__pyobjc_PythonObject__;
 +(PyObject*)__pyobjc_PythonObject__;
+
+-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie;
++(PyObject*)__pyobjc_PythonTransient__:(int*)cookie;
 @end /* PyObjCSupport */
 
 @implementation NSProxy (PyObjCSupport)
@@ -102,10 +126,28 @@
 	return rval;
 }
 
+-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie
+{
+	PyObject* result = PyObjC_FindPythonProxy(self);
+	if (result) {
+		*cookie = 0;
+		return result;
+	}
+
+	*cookie = 1;
+	return PyObjCObject_New(self, PyObjCObject_kSHOULD_NOT_RELEASE, NO);
+}
+
++(PyObject*)__pyobjc_PythonTransient__:(int*)cookie
+{
+	*cookie = 0;
+	return (PyObject *)PyObjCClass_New(self);
+}
 @end /* PyObjCSupport */
 
 @interface Protocol (PyObjCSupport)
 -(PyObject*)__pyobjc_PythonObject__;
+-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie;
 @end /* PyObjCSupport */
 
 @implementation Protocol (PyObjCSupport)
@@ -121,10 +163,23 @@
 	return rval;
 }
 
+-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie
+{
+	PyObject *rval;
+
+	*cookie = 0;
+	rval = PyObjC_FindPythonProxy(self);
+	if (rval == NULL) {
+		rval = PyObjCFormalProtocol_ForProtocol(self);
+	}
+	return rval;
+}
+
 @end /* PyObjCSupport */
 
 @interface Object (PyObjCSupport)
 -(PyObject*)__pyobjc_PythonObject__;
+-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie;
 @end /* PyObjCSupport */
 
 @implementation Object (PyObjCSupport)
@@ -142,10 +197,25 @@
 	return rval;
 }
 
+-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie
+{
+	PyObject *rval;
+
+	*cookie = 0;
+	rval = PyObjC_FindPythonProxy(self);
+	if (rval == NULL) {
+		rval = (PyObject *)PyObjCObject_New(self,
+				PyObjCObject_kCLASSIC, NO);
+		PyObjC_RegisterPythonProxy(self, rval);
+	}
+	return rval;
+}
+
 @end /* PyObjCSupport */
 
 @interface NSString (PyObjCSupport)
 -(PyObject*)__pyobjc_PythonObject__;
+-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie;
 @end /* NSString (PyObjCSupport) */
 
 @implementation NSString (PyObjCSupport)
@@ -157,10 +227,17 @@
 	return rval;
 }
 
+-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie
+{
+	*cookie = 0;
+	return (PyObject *)PyObjCUnicode_New(self);
+}
+
 @end /* NSString (PyObjCSupport) */
 
 @interface NSNumber (PyObjCSupport)
 -(PyObject*)__pyobjc_PythonObject__;
+-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie;
 @end /* NSNumber (PyObjCSupport) */
 
 @implementation NSNumber (PyObjCSupport)
@@ -191,10 +268,17 @@
 	}
 	return rval;
 }
+
+-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie
+{
+	*cookie = 0;
+	return [self __pyobjc_PythonObject__];
+}
 @end
 
 @interface NSDecimalNumber (PyObjCSupport)
 -(PyObject*)__pyobjc_PythonObject__;
+-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie;
 @end /* NSDecimalNumber (PyObjCSupport) */
 
 @implementation NSDecimalNumber (PyObjCSupport)
@@ -211,6 +295,12 @@
 
 	return rval;
 }
+
+-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie
+{
+	*cookie = 0;
+	return [self __pyobjc_PythonObject__];
+}
 @end
 
 #ifndef MAX
@@ -2462,3 +2552,16 @@
 }
 
 
+PyObject* PyObjCObject_NewTransient(id objc_object, int* cookie)
+{
+	return [(NSObject*)objc_object __pyobjc_PythonTransient__:cookie];
+}
+
+void PyObjCObject_ReleaseTransient(PyObject* proxy, int cookie)
+{
+	if (cookie && proxy->ob_refcnt != 1) {
+		CFRetain(PyObjCObject_GetObject(proxy));
+		((PyObjCObject*)proxy)-> flags &= ~PyObjCObject_kSHOULD_NOT_RELEASE;
+	}
+	Py_DECREF(proxy);
+}

Modified: trunk/pyobjc/pyobjc-core/Modules/objc/objc_util.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/objc_util.m	(original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/objc_util.m	Thu May  1 03:34:04 2008
@@ -75,6 +75,28 @@
 
 	state = PyGILState_Ensure();
 
+	if (![localException isKindOfClass:[NSException class]]) {
+		/* We caught some random objects as the exception, so the minimal possible
+		 */
+		PyErr_SetString(PyObjCExc_Error, "non-NSException object caught");
+
+		PyErr_Fetch(&exc_type, &exc_value, &exc_traceback);
+		if (!exc_value || !PyObject_IsInstance(exc_value, exc_type)) {
+			PyErr_NormalizeException(&exc_type, &exc_value, &exc_traceback);
+		}
+
+		PyObject* exc = PyObjC_IdToPython(localException);
+		if (exc == NULL) {
+			PyErr_Clear();
+		} else {
+			PyObject_SetAttrString(exc_value, "_pyobjc_exc_", exc);
+		}
+		Py_DECREF(exc); exc = NULL;
+		PyErr_Restore(exc_type, exc_value, exc_traceback);
+		PyGILState_Release(state);
+		return;
+	}
+
 	exception = ObjCErr_PyExcForName([[localException name] UTF8String]);
 
 	userInfo = [localException userInfo];
@@ -201,6 +223,13 @@
 
 	PyErr_NormalizeException(&exc_type, &exc_value, &exc_traceback);
 
+	args = PyObject_GetAttrString(exc_value, "_pyobjc_exc_");
+	if (args == NULL) {
+		PyErr_Clear();
+	} else {
+		return PyObjC_PythonToId(args);
+	}
+
 	args = PyObject_GetAttrString(exc_value, "_pyobjc_info_");
 	if (args == NULL) {
 		PyErr_Clear();
@@ -290,7 +319,10 @@
 	if (state) {
 		PyGILState_Release(*state);
 	}
+	@throw exc;
+#if 0
 	[exc raise];
+#endif
 }
 
 

Modified: trunk/pyobjc/pyobjc-core/Modules/objc/proxy-registry.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/proxy-registry.m	(original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/proxy-registry.m	Thu May  1 03:34:04 2008
@@ -67,11 +67,11 @@
 {
 	PyObject* v;
 	
-    if (original == nil) {
-        v = Py_None;
-    } else {
-        v = NSMapGet(python_proxies, original);
-    }
+	if (original == nil) {
+		v = Py_None;
+	} else {
+		v = NSMapGet(python_proxies, original);
+	}
 	Py_XINCREF(v);
 	return v;
 }

Modified: trunk/pyobjc/pyobjc-core/Modules/objc/pyobjc-api.h
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/pyobjc-api.h	(original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/pyobjc-api.h	Thu May  1 03:34:04 2008
@@ -57,7 +57,8 @@
 		Py_BEGIN_ALLOW_THREADS \
 		@try {
 
-#define PyObjC_HANDLER } @catch(NSException* localException) {
+#define PyObjC_HANDLER } @catch(NSObject* _localException) { \
+		NSException* localException __attribute__((__unused__))= (NSException*)_localException;
 
 #define PyObjC_ENDHANDLER \
 		} \

Modified: trunk/pyobjc/pyobjc-core/Modules/objc/pyobjc.h
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/pyobjc.h	(original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/pyobjc.h	Thu May  1 03:34:04 2008
@@ -37,6 +37,7 @@
 #include "OC_PythonString.h"
 #include "OC_PythonEnumerator.h"
 #include "OC_PythonDate.h"
+#include "OC_PythonNumber.h"
 #include "method-signature.h"
 #include "objc_util.h"
 #include "objc-class.h"
@@ -61,7 +62,6 @@
 #include "parsexml.h"
 #include "objc_super.h"
 #include "picklecoder.h"
-#include "pycoder.h"
 
 
 /*

Modified: trunk/pyobjc/pyobjc-core/Modules/objc/test/exceptions.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/test/exceptions.m	(original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/test/exceptions.m	Thu May  1 03:34:04 2008
@@ -19,6 +19,7 @@
 -(void)raiseUnicodeName;
 -(void)raiseUnicodeReason;
 -(void)raiseUnicodeWithInfo;
+-(void)raiseAString;
 @end
 
 @implementation PyObjCTestExceptions
@@ -64,6 +65,11 @@
 				NULL]] raise];
 }
 
+-(void)raiseAString
+{
+	@throw @"thrown string";
+}
+
 @end
 
 

Modified: trunk/pyobjc/pyobjc-core/NEWS.txt
==============================================================================
--- trunk/pyobjc/pyobjc-core/NEWS.txt	(original)
+++ trunk/pyobjc/pyobjc-core/NEWS.txt	Thu May  1 03:34:04 2008
@@ -30,6 +30,17 @@
   instances before using them from Objective-C (such as using an 
   ``NSDateFormatter``)
 
+- There is experimental support for archiving Python objects 
+  using an ``NSKeyedArchiver``. 
+
+- Objective-C classes that support the ``NSCopying`` protocol can now be
+  copied using ``copy.copy`` as well.
+
+- Objective-C classes that support the ``NSCoding`` protocol can now be
+  copied using ``copy.deepcopy``.
+
+- Pure Python objects now support the ``NSCopying`` protocol.
+
 - A new decorator: ``objc.namedselector`` for overriding the Objective-C
   selector. Usage::
 
@@ -75,6 +86,27 @@
   functionality didn't work in PyObjC 2.0 and is now completely removed 
   because the functionality isn't supported by the Objective-C 2.0 runtime.
 
+- Adds custom wrappers for some more Python types:
+
+  * ``OC_PythonNumber``: wraps python numeric types
+
+    This is used instead of ``NSNumber`` because we might loose information
+    otherwise (such as when using custom subclasses of ``int``).
+
+  * ``OC_PythonSet``: wraps a python set
+
+- BUGFIX: using the ``@throw`` syntax one can raise arbitrary objects as
+  exceptions (not just instances of NSException) in Objective-C. All 
+  instances of NSObject are now converted to Python exceptions, throwing 
+  some other object (such as a C++ exception) will still case a fatal
+  error due to an uncaught exception. 
+
+  (SF Bug: 1741095)
+
+- BUGFIX: ``repr(CoreFoundation.kCFAllocatorUseContext)`` now works
+
+  (SF Bug: 1827746)
+
 - BUGFIX: The wrappers for CoreFoundation types no longer create a new type 
   in the Objective-C runtime, that type wasn't used anywhere and was an 
   unwanted side-effect of how CoreFoundation types are wrapped.

-------------------------------------------------------------------------
This SF.net email is sponsored by the 2008 JavaOne(SM) Conference 
Don't miss this year's exciting event. There's still time to save $100. 
Use priority code J8TL2D2. 
http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.