Commits

Ronald Oussoren  committed 0af4f90

- Add some tests for the custom wrappers of methods in the Foundation
frameworks. This is work in progress, more tests are needed (see next
item for an example of why tests are usefull).
- Fix the bugs found by these tests, including a cut&paste bug that
affects lots of calls to PyArg_ParseTuple. Previous version would crash
if you use the API incorrectly (wrong number of arguments, wrong values).
- Add a Cocoa-Python-ObjC Document-based Application template (patch
#755852, bug #755838)
- Add custom wrapper for the difficult method in NSQuickDrawView
- Add documentation to PyObjCTools.Signals
- Add __all__ to PyObjC.AppHelper. I hoped to teach pydoc what symbols
are part of the public API, but that module ignores the value of __all__ :-(
- Add 'sort()' method to NSMutableArray (though objc._convenience)
- Copy the code for updating the HTML version of the documentation to
a seperate script, make_distrib.py will be updated in the future.

  • Participants
  • Parent commits 1c5b54e

Comments (0)

Files changed (46)

File pyobjc/Doc/TODO

 This is post-1.0 work, in general this is a hard problem because it may 
 involve object cycles that cross the Python-ObjC boundary.
 
+NOTE: 1.0b1+ contains a patch that disables pickling even for pickle protocol 2,
+that's more usefull than writing incomplete objects to the pickle.
+
 NSCoder support
 ...............
 
 Luckily there are not many varargs methods and most (if no all) of them can
 be easily avoided.
 
+XXX: The paragraph above should be moved to the documentation, it is not a 
+todo item.
+
 All existing varargs methods should be located and documented. Where possible
 we should provide custom wrappers, otherwise we should document alternatives.
 
+
 Cleanup Examples
 ................
 
 final step of the tutorial. It isn't at the moment because additional cruft in
 the example.
 
-The TableModel and TableModel2 examples should be merged, the contain the same
-python code and only differ in the build method.
-
 * addressbook.py
   Cleanup, maybe transform this into a usefull utility (import/export from/to
   CSV springs to mind).
 ..........................
 
 Design and implement a set of performance tests for the bridge. Use this to 
-invistigate and fix any possible performance problems.
+investigate and fix any possible performance problems.
 
 Robustness
 ..........
 Add freelists
 .............
 
-PyObjCSelector objects and (especially) PyObjCObject objects are created on
+PyObjCSelector objects and PyObjCObject objects are created on
 a regular basis, we should check if using freelists would speed this up. See
 also `Performance tuning/testing`.
 
+
+Key-Value Encoding
+..................
+
+Implement the Key-Value encoding protocol for Py-ObjC hybrids, in a Pythonic
+way. Do the same in OC_PythonObject (e.g. for pure-python objects used from
+Objective-C)

File pyobjc/Doc/api-notes-macosx.txt

 .............................
 
 * ``getValues:forAttribute:forVirtualScreen:``
+
   This method is not yet supported
 
 * ``initWithAttributes:``
+
   This method is not yet supported
 
 Class ``NSQuickDrawView``
 .........................
 
 * ``qdPort``
-  This method is not yet supported and will return a MacPython wrapper for
-  a QuickDraw port in the future.
+
+  This method returns an instance from a type Carbon.QuickDraw. This 
+  requires MacPython.
 
 Class ``NSSimpleHorizontalTypesetter``
 ......................................
 The following methods are not supported in the current version of PyObjC.
 This limitation will be lifted in a future version of the bridge.
 
-* ``encodeBytes:length:``
+* ``decodeBytesWithReturnedLength:``
 
-* ``decodeBytesWithReturnedLength:``
+* ``decodeBytesForKey:returnedLength:``
 
 * ``encodeValuesOfObjCType:``
 
+  Use multiple calls to ``encodeValueOfObjCType:at:`` instead.
+
 * ``decodeValuesOfObjCType:``
 
-* ``decodeBytesForKey:returnedLength:``
+  Use multiple calls to ``decodeValueOfObjCType:at:`` instead. Note that
+  that won't work if your trying to read back data that was written using
+  ``encodeValuesOfObjCType:``.
 
-* ``decodeBytesWithoutReturnedLength:``
+The method ``decodeBytesWithoutReturnedLength:`` is not supported, use 
+``decodeBytesWithReturnedLength:`` instead. It is not possible to safely
+represent the return value of this method in Python.
 
 
 Class ``NSData``

File pyobjc/Doc/coding-style.html

 <li>Add appropriate ReST style fields to the top of the document as comments:<pre>
 # Author: David Goodger
 # Contact: goodger@users.sourceforge.net
-# Revision: $Revision: 1.16 $
-# Date: $Date: 2003/07/07 07:02:10 $
 # Copyright: This module has been placed in the public domain.
 </pre>
 </li>

File pyobjc/Doc/coding-style.txt

 
         # Author: David Goodger
         # Contact: goodger@users.sourceforge.net
-        # Revision: $Revision: 1.3 $
-        # Date: $Date: 2003/04/03 20:20:43 $
         # Copyright: This module has been placed in the public domain.
 
 (2) Add a module level variable that indicates that ReST is used to format

File pyobjc/Lib/Foundation/test/test_nsarray.py

         self.assertEquals(a, ('a', 'b', 'c'))
         self.assertEquals(b, ('c', 'b', 'a'))
 
+class TestNSMutableArrayInteraction(unittest.TestCase):
 
+    def testRemoveObjects(self):
+        a = NSMutableArray.arrayWithArray_(range(10))
 
+        self.assertEquals(len(a), 10)
+        self.assertEquals(a[0], 0)
+        self.assertEquals(a[1], 1)
+        self.assertEquals(a[2], 2)
+
+        a.removeObjectsFromIndices_numIndices_([2, 4, 6, 8], 3)
+
+        self.assertEquals(len(a), 7)
+        self.assertEquals(a, (0, 1, 3, 5, 7, 8, 9))
+
+
+    def testReplaceObjects(self):
+        a = NSMutableArray.arrayWithArray_(range(4))
+        self.assertEquals(a, (0, 1, 2, 3))
+
+        a.replaceObjectsInRange_withObjects_count_(
+            (1,2), ["a", "b", "c", "d"], 3)
+
+        self.assertEquals(a, (0, "a", "b", "c", 3))
+
+    def testSortInvalid(self):
+        """
+        Invalid calls to sortUsingFunction:context:
+        """
+
+        a = NSMutableArray.arrayWithArray_(range(4))
+        self.assertEquals(a, (0, 1, 2, 3))
+
+        self.assertRaises(TypeError, a.sortUsingFunction_context_, dir)
+        self.assertRaises(TypeError, a.sortUsingFunction_context_, dir, 1, 2)
+        self.assertRaises(TypeError, a.sortUsingFunction_context_, cmp, 'a')
+
+    def testSort2(self):
+        a = NSMutableArray.arrayWithArray_(range(10))
+        self.assertEquals(a, (0, 1, 2, 3, 4, 5, 6, 7, 8, 9))
+    
+        def cmpfunc(l, r, c):
+            return -cmp(l,r)
+
+        a.sortUsingFunction_context_range_(cmpfunc, "a", (4, 4))
+
+        self.assertEquals(a, (0, 1, 2, 3, 7, 6, 5, 4, 8, 9))
+
+    def testSort3(self):
+        """ check the sort method, list interface compatibility """
+
+        a = NSMutableArray.arrayWithArray_(range(4))
+        self.assertEquals(a, (0, 1, 2, 3))
+    
+        def cmpfunc(l, r):
+            return -cmp(l,r)
+
+        a.sort(cmpfunc)
+
+        self.assertEquals(a, (3, 2, 1, 0))
+        
+        a.sort()
+        self.assertEquals(a, (0, 1, 2, 3))
+
+    def testSort1(self):
+        a = NSMutableArray.arrayWithArray_(range(4))
+        self.assertEquals(a, (0, 1, 2, 3))
+    
+        def cmpfunc(l, r, c):
+            return -cmp(l,r)
+
+        a.sortUsingFunction_context_(cmpfunc, "a")
+
+        self.assertEquals(a, (3, 2, 1, 0))
+
+    def testSort2(self):
+        a = NSMutableArray.arrayWithArray_(range(10))
+        self.assertEquals(a, (0, 1, 2, 3, 4, 5, 6, 7, 8, 9))
+    
+        def cmpfunc(l, r, c):
+            return -cmp(l,r)
+
+        a.sortUsingFunction_context_range_(cmpfunc, "a", (4, 4))
+
+        self.assertEquals(a, (0, 1, 2, 3, 7, 6, 5, 4, 8, 9))
+
+    def testSort3(self):
+        """ check the sort method, list interface compatibility """
+
+        a = NSMutableArray.arrayWithArray_(range(4))
+        self.assertEquals(a, (0, 1, 2, 3))
+    
+        def cmpfunc(l, r):
+            return -cmp(l,r)
+
+        a.sort(cmpfunc)
+
+        self.assertEquals(a, (3, 2, 1, 0))
+        
+        a.sort()
+
+        self.assertEquals(a, (0, 1, 2, 3))
 
 if __name__ == '__main__':
-    unittest.main( )
+    unittest.main()

File pyobjc/Lib/PyObjCTools/AppHelper.py

 * sheetEndMethod - set correct signature for NSSheet callbacks
 """
 
+__all__ = ( 'runEventLoop', 'sheetEndMethod' )
+
 from AppKit import NSApplicationMain, NSApp, NSRunAlertPanel
 from Foundation import NSLog
 import sys

File pyobjc/Lib/PyObjCTools/Signals.py

-"""Signals.py -- Automatically dump a python stacktrace if something bad happens.
+"""Signals.py -- dump a python stacktrace if something bad happens.
 
-This module is not designed to provide fine grained control over signal handling.
-Nor is it intended to be terribly robust.
+          DO NOT USE THIS MODULE IN PRODUCTION CODE
+
+This module has two functions in its public API:
+
+- dumpStackOnFatalSignal()
+  This function will install signal handlers that print a stacktrace and
+  then reraise the signal.
+
+- resetFatalSignals()
+  Restores the signal handlers to the state they had before the call to
+  dumpStackOnFatalSignal.
+
+This module is not designed to provide fine grained control over signal 
+handling. Nor is it intended to be terribly robust. It may give usefull
+information when your program gets unexpected signals, but it might just
+as easily cause a crash when such a signal gets in. 
+
+          DO NOT USE THIS MODULE IN PRODUCTION CODE
 """
 
 import signal
-import traceback # go ahead an import now -- don't know what state we'll be in later
+import traceback
 import os
 
 __all__ = ["dumpStackOnFatalSignal", "resetFatalSignals"]
 originalHandlers = None
 
 def dumpHandler(signum, frame):
+    """
+    the signal handler used in this module: print a stacktrace and
+    then re-raise the signal
+    """
     resetFatalSignals()
     print "*** Handling fatal signal '%d'." % signum
     traceback.print_stack(frame)
     os.kill(os.getpid(), signum)
 
 def installHandler(sig):
+    """
+    Install our signal handler for a signal. The original handler
+    is saved in 'originalHandlers'.
+    """
     originalHandlers[sig] = signal.signal(sig, dumpHandler)
 
 def dumpStackOnFatalSignal():
+    """
+    Install signal handlers that might print a usefull stack trace when
+    this process receives a fatal signal. 
+
+    NOTE: See module docstring
+    """
+
     global originalHandlers
     if not originalHandlers:
         originalHandlers = {}
         installHandler(signal.SIGSYS)
 
 def resetFatalSignals():
+    """
+    Restore the original signal handlers
+    """
     global originalHandlers
     if originalHandlers:
         for sig in originalHandlers:

File pyobjc/Lib/objc/_convenience.py

 CONVENIENCE_METHODS['poseAsClass:'] = (
     ('poseAsClass_', (UnsupportedMethod)),
 )
+
+def sort(self, cmpfunc=cmp):
+    def doCmp(a, b, cmpfunc):
+        return cmpfunc(a, b)
+
+    self.sortUsingFunction_context_(doCmp, cmpfunc)
+
+CONVENIENCE_METHODS['sortUsingFunction:context:'] = (
+    ('sort', sort),
+)

File pyobjc/Modules/AppKit/_AppKit.m

   unsigned char *rectBytes;
   int rectByteLength;
   int rectCount = -1;
-  if  (PyArg_ParseTupleAndKeywords(args, kwds, "s#|i", keywords, &rectBytes, &rectByteLength, &rectCount) < 0) {
+  if  (!PyArg_ParseTupleAndKeywords(args, kwds, "s#|i", keywords, &rectBytes, &rectByteLength, &rectCount)) {
     return NULL;
   }
 

File pyobjc/Modules/AppKit/_AppKitMapping.m

   struct objc_super super;
 
   // check for five well defined read buffers in data planes argument
-  if (PyArg_ParseTuple(arguments, "(z#z#z#z#z#)iiiibbsii",
+  if (!PyArg_ParseTuple(arguments, "(z#z#z#z#z#)iiiibbsii",
 		       &dataPlanes[0], &garbage,
 		       &dataPlanes[1], &garbage,
 		       &dataPlanes[2], &garbage,
 		       &isPlanar,
 		       &colorSpaceName,
 		       &bpr,
-		       &bpp) == 0) {
+		       &bpp)) {
 
     if ( !PyErr_ExceptionMatches(PyExc_TypeError) )
       return NULL;
     PyErr_Clear();
     bzero(dataPlanes, sizeof(dataPlanes));
 
-    if (PyArg_ParseTuple(arguments, "Oiiiibbsii",
+    if (!PyArg_ParseTuple(arguments, "Oiiiibbsii",
 			 &maybeNone,
 			 &width,
 			 &height,
 			 &isPlanar,
 			 &colorSpaceName,
 			 &bpr,
-			 &bpp) == 0){
+			 &bpp)){
       return NULL; //! any other situations that we need to parse specific args go here
     } else {
       // first arg must be none as nothing else makes sense
   PyObject* result;
   struct objc_super super;
   
-  if (PyArg_ParseTuple(arguments, "") < 0) {
+  if (!PyArg_ParseTuple(arguments, "")) {
     return NULL;
   }
 
   PyObject* result;
   struct objc_super super;
   
-  if (PyArg_ParseTuple(arguments, "") < 0) {
+  if (!PyArg_ParseTuple(arguments, "")) {
     return NULL;
   }
 

File pyobjc/Modules/AppKit/_AppKitMapping_NSBezierPath.m

 	id fontObj;
 	int i;
 	
-	if  (PyArg_ParseTuple(arguments, "OiO&", &glyphList, &count, 
-			PyObjCObject_Convert, &fontObj) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "OiO&", &glyphList, &count, 
+			PyObjCObject_Convert, &fontObj)) {
 		return NULL;
 	}
 
 	int count;
 	int i;
 	
-	if  (PyArg_ParseTuple(arguments, "OiO&", &pointList, &count) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "OiO&", &pointList, &count)) {
 		return NULL;
 	}
 
 	NSBezierPathElement res;
 	int i;
 	
-	if  (PyArg_ParseTuple(arguments, "i", &idx) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "i", &idx)) {
 		return NULL;
 	}
 
 	PyObject* seq;
 	int i, len;
 	
-	if  (PyArg_ParseTuple(arguments, "Oi", &pointList, &idx) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "Oi", &pointList, &idx)) {
 		return NULL;
 	}
 
 	float phase;
 
 	
-	if  (PyArg_ParseTuple(arguments, "Oif", &patternList, &count, &phase) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "Oif", &patternList, &count, &phase)) {
 		return NULL;
 	}
 

File pyobjc/Modules/AppKit/_AppKitMapping_NSFont.m

 	NSPoint* points;
 	int i, len;
 
-	if (PyArg_ParseTuple(arguments, "Oi", &glyphList, &numGlyphs) < 0) {
+	if (!PyArg_ParseTuple(arguments, "Oi", &glyphList, &numGlyphs)) {
 		return 0;
 	}
 

File pyobjc/Modules/AppKit/_AppKitMapping_NSMatrix.m

 	PyObject* realContext;
 	id  res;
 
-	if  (PyArg_ParseTuple(arguments, "OO", &sortFunc, &context) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "OO", &sortFunc, &context)) {
 		return NULL;
 	}
 

File pyobjc/Modules/AppKit/_AppKitMapping_NSMovie.m

 	struct objc_super super;
 	void*     movie;
 
-	if  (PyArg_ParseTuple(arguments, "") < 0) {
+	if  (!PyArg_ParseTuple(arguments, "")) {
 		return NULL;
 	}
 
 	void*     movie;
 	id        objc_result;
 
-	if  (PyArg_ParseTuple(arguments, "O&", MovieObj_Convert, &movie) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "O&", MovieObj_Convert, &movie)) {
 		return NULL;
 	}
 

File pyobjc/Modules/AppKit/_AppKitMapping_NSQuickDrawView.m

 /*
  * Special wrappers for NSQuickDrawView methods with 'difficult' arguments.
  *
- * TODO:
- * -qdPort
+ * -qdPort		[call, imp]
+ *
+ * NOTE: Requires MacPython for complete functionality.
  */
 #include <Python.h>
 #include <AppKit/AppKit.h>
 #include "pyobjc-api.h"
 
 
+static PyObject* call_NSQuickDrawView_qdport(
+		PyObject* method __attribute__((__unused__)), 
+		PyObject* self, PyObject* arguments)
+{
+	PyObject* result;
+	struct objc_super super;
+	void*     port;
+
+	if  (!PyArg_ParseTuple(arguments, "")) {
+		return NULL;
+	}
+
+	NS_DURING
+		PyObjC_InitSuper(&super, 
+			PyObjCClass_GetClass((PyObject*)(self->ob_type)),
+			PyObjCObject_GetObject(self));
+
+
+		port = objc_msgSendSuper(&super,
+				@selector(qdport));
+		if (port == NULL) {
+			result = Py_None;
+			Py_INCREF(result);
+		} else {
+			result = GrafObj_New((GrafPtr)port);
+		}
+
+	NS_HANDLER
+		PyObjCErr_FromObjC(localException);
+		result = NULL;
+	NS_ENDHANDLER
+
+	return result;
+}
+
+static void* imp_NSQuickDrawView_qdport(id self, SEL sel)
+{
+	PyObject* result;
+	PyObject* arglist;
+	void*    objc_result;
+
+	arglist = PyTuple_New(0);
+	if (arglist == NULL) {
+		PyObjCErr_ToObjC();
+		return nil;
+	}
+
+	result = PyObjC_CallPython(self, sel, arglist);
+	Py_DECREF(arglist);
+	if (result == NULL) {
+		PyObjCErr_ToObjC();
+		return nil;
+	}
+
+	GrafObj_Convert(result, (GrafPtr*)&objc_result); 
+	Py_DECREF(result);
+
+	if (PyErr_Occurred()) {
+		PyObjCErr_ToObjC();
+		return nil;
+	}
+
+	return objc_result;
+}
+
+
 static int 
 _pyobjc_install_NSQuickDrawView(void)
 {
 
 	if (PyObjC_RegisterMethodMapping(
 		classNSQuickDrawView,
-		@selector(qdPort),
-		PyObjCUnsupportedMethod_Caller,
-		PyObjCUnsupportedMethod_IMP) < 0) {
+		@selector(initWithWindowRef:),
+		call_NSQuickDrawView_qdport,
+		(IMP)imp_NSQuickDrawView_qdport) < 0) {
 
 		return -1;
 	}
-
-	return 0;
 }

File pyobjc/Modules/AppKit/_AppKitMapping_NSView.m

 	PyObject* realContext;
 	id  res;
 
-	if  (PyArg_ParseTuple(arguments, "OO", &sortFunc, &context) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "OO", &sortFunc, &context)) {
 		return NULL;
 	}
 

File pyobjc/Modules/AppKit/_AppKitMapping_NSWindow.m

  *
  * -initWithWindowRef:
  * -windowRef
+ *
+ * NOTE: Requires MacPython for complete functionality.
  */
 #include <Python.h>
 #include <AppKit/AppKit.h>
 #include "pymactoolbox.h"
 
 static PyObject* call_NSWindow_windowRef(
-		PyObject* method __attribute__((__unused__)), PyObject* self, PyObject* arguments)
+		PyObject* method __attribute__((__unused__)), 
+		PyObject* self, PyObject* arguments)
 {
 	PyObject* result;
 	struct objc_super super;
 	void*     windowRef;
 
-	if  (PyArg_ParseTuple(arguments, "") < 0) {
+	if  (!PyArg_ParseTuple(arguments, "")) {
 		return NULL;
 	}
 
 		} else {
 			result = WinObj_New((WindowPtr)windowRef);
 		}
+
 	NS_HANDLER
 		PyObjCErr_FromObjC(localException);
 		result = NULL;
 	void*     windowRef;
 	id        objc_result;
 
-	if  (PyArg_ParseTuple(arguments, "O&", WinObj_Convert, &windowRef) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "O&", WinObj_Convert, &windowRef)) {
 		return NULL;
 	}
 
 		objc_result = objc_msgSendSuper(&super,
 				@selector(initWithWindowRef:), windowRef);
 		result = PyObjC_IdToPython(objc_result);
+
 	NS_HANDLER
 		PyObjCErr_FromObjC(localException);
 		result = NULL;

File pyobjc/Modules/Foundation/_Foundation.m

 /*
- * Mapping of static items in the Foundation kit:
- * - constants
- * - notification
- * - data types (TODO)
- * - enumerations (TODO)
- * - exceptions (TODO)
- * - global functions (TODO)
+ * Mapping of static items in the Foundation kit.
  */
 #include <Python.h>
 #import <Foundation/Foundation.h>

File pyobjc/Modules/Foundation/_FoundationMapping.m

 /*
  * This module contains custom mapping functions for problematic methods
+ *
+ * NOTE: all interesting code is in _FoundationMapping_*.m
  */
 
 #include <Python.h>
 	{ 0, 0, 0, 0 }
 };
 
-/* These are needed to silence GCC */
-void init_FoundationMapping(void);
 
 #include "_FoundationMapping_NSArray.m"
 #include "_FoundationMapping_NSCoder.m"
 #include "_FoundationMapping_NSSet.m"
 #include "_FoundationMapping_NSString.m"
 
+/* This prototype is needed to silence a GCC warning */
+void init_FoundationMapping(void);
 
 void init_FoundationMapping(void)
 {
 		return;
 	}
 
-	if (_pyobjc_install_NSArray()) return;
-	if (_pyobjc_install_NSCoder()) return;
-	if (_pyobjc_install_NSData()) return;
-	if (_pyobjc_install_NSDictionary()) return;
-	if (_pyobjc_install_NSMutableArray()) return;
-	if (_pyobjc_install_NSNetService()) return;
-	if (_pyobjc_install_NSScriptObjectSpecifier()) return;
-	if (_pyobjc_install_NSSet()) return;
-	if (_pyobjc_install_NSString()) return;
+	if (_pyobjc_install_NSArray() != 0) return;
+	if (_pyobjc_install_NSCoder() != 0) return;
+	if (_pyobjc_install_NSData() != 0) return;
+	if (_pyobjc_install_NSDictionary() != 0) return;
+	if (_pyobjc_install_NSMutableArray() != 0) return;
+	if (_pyobjc_install_NSNetService() != 0) return;
+	if (_pyobjc_install_NSScriptObjectSpecifier() != 0) return;
+	if (_pyobjc_install_NSSet() != 0) return;
+	if (_pyobjc_install_NSString() != 0) return;
 }

File pyobjc/Modules/Foundation/_FoundationMapping_NSArray.m

 	PyObject* realContext;
 	id  res;
 
-	if  (PyArg_ParseTuple(arguments, "OO", &sortFunc, &context) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "OO", &sortFunc, &context)) {
 		return NULL;
 	}
 
 	PyObject* realContext;
 	id  res;
 
-	if  (PyArg_ParseTuple(arguments, "OOO&", &sortFunc, &context,
-			PyObjCObject_Convert, &hint) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "OOO&", &sortFunc, &context,
+			PyObjCObject_Convert, &hint)) {
 		return NULL;
 	}
 
 	int i;
 	id  res;
 
-	if  (PyArg_ParseTuple(arguments, "Oi", &objectList, &count) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "Oi", &objectList, &count)) {
 		return NULL;
 	}
 
 	int i;
 	id  res;
 
-	if  (PyArg_ParseTuple(arguments, "Oi", &objectList, &count) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "Oi", &objectList, &count)) {
 		return NULL;
 	}
 
 	int i;
 	id  res;
 
-	if  (PyArg_ParseTuple(arguments, "Oi", &objectList, &count) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "Oi", &objectList, &count)) {
 		return NULL;
 	}
 

File pyobjc/Modules/Foundation/_FoundationMapping_NSCoder.m

 /*
  * NSCoder mappings for special methods:
- * - encodeValueOfObjCType:at: 
- * - decodeValueOfObjCType:at:
- * - encodeArrayOfObjCType:count:at:
- * - decodeArrayOfObjCType:count:at:
+ * - encodeValueOfObjCType:at: 			[call, imp]
+ * - decodeValueOfObjCType:at:			[call, imp]
+ * - encodeArrayOfObjCType:count:at:		[call, imp]
+ * - decodeArrayOfObjCType:count:at:		[call, imp]
+ * - encodeBytes:length:			[call, imp]
+ * - encodeBytes:length:forKey:			[call, imp]
  *
  * TODO:
- * - encodeBytes:length:
  * - decodeBytesWithReturnedLength:
+ * - decodeBytesForKey:returnedLength:
  * - encodeValuesOfObjCType: 
  * - decodeValuesOfObjCType:
- * - decodeBytesForKey:returnedLength:
+ *
+ * Unsupported method:
  * - decodeBytesWithoutReturnedLength:
+ *   Use ...WithReturnedLenght instead.
+ *
+ * XXX Check usage of self in upcalls, write unittests (including upcalls)
  */
 #include <Python.h>
 #include <Foundation/Foundation.h>
 	int err;
 	struct objc_super super;
 
-	if  (PyArg_ParseTuple(arguments, "sO", &signature, &value) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "sO", &signature, &value)) {
 		return NULL;
 	}
 
 	int err;
 	struct objc_super super;
 
-	if  (PyArg_ParseTuple(arguments, "siO", &signature, &count, &value) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "siO", &signature, &count, &value)) {
 		return NULL;
 	}
 
 	int    size;
 	struct objc_super super;
 
-	if  (PyArg_ParseTuple(arguments, "s", &signature) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "s", &signature)) {
 		return NULL;
 	}
 
 	int    size;
 	struct objc_super super;
 
-	if  (PyArg_ParseTuple(arguments, "si", &signature, &count) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "si", &signature, &count)) {
 		return NULL;
 	}
 
 			Py_DECREF(result);
 			return NULL;
 		}
-
-		/* XXX: Isn't this incorrect??, we get a crash without this */
-		//Py_INCREF(PyTuple_GET_ITEM(result, i)); 
 	}
 
 	return result;
 	Py_DECREF(values);
 }
 
+static PyObject* call_NSCoder_encodeBytes_length_(
+		PyObject* method __attribute__((__unused__)), 
+		PyObject* self, PyObject* arguments)
+{
+	char* bytes;
+	int    size;
+
+	PyObject* result;
+	struct objc_super super;
+
+	if  (!PyArg_ParseTuple(arguments, "t#", &bytes, &size)) {
+		return NULL;
+	}
+
+	NS_DURING
+		PyObjC_InitSuper(&super, 
+			PyObjCClass_GetClass((PyObject*)(self->ob_type)),
+			PyObjCObject_GetObject(self));
+
+		(void)objc_msgSendSuper(&super,
+				@selector(encodeBytes:length:),
+				bytes, size);
+		result = Py_None;
+		Py_INCREF(result);
+	NS_HANDLER
+		PyObjCErr_FromObjC(localException);
+		result = NULL;
+	NS_ENDHANDLER
+
+	return result;
+}
+
+static void imp_NSCoder_encodeBytes_length_(id self, SEL sel,
+		char* bytes, int length)	
+{
+	PyObject* result;
+	PyObject* arglist;
+
+	arglist = PyTuple_New(2);
+	if (arglist == NULL) {
+		PyObjCErr_ToObjC();
+		return;
+	}
+
+	PyTuple_SetItem(arglist, 0, PyString_FromStringAndSize(bytes, length));
+	PyTuple_SetItem(arglist, 1, PyInt_FromLong(length));
+
+	if (PyErr_Occurred()) {
+		Py_DECREF(arglist);
+		PyObjCErr_ToObjC();
+		return;
+	}
+
+	result = PyObjC_CallPython(self, sel, arglist);
+	Py_DECREF(arglist);
+	if (result == NULL) {
+		PyObjCErr_ToObjC();
+		return;
+	}
+
+	if (result != Py_None) {
+		PyErr_SetString(PyExc_TypeError, "Must return None");
+		Py_DECREF(result);
+		PyObjCErr_ToObjC();
+		return;
+	}
+	Py_DECREF(result);
+}
+
+static PyObject* call_NSCoder_encodeBytes_length_forKey_(
+		PyObject* method __attribute__((__unused__)), 
+		PyObject* self, PyObject* arguments)
+{
+	char* bytes;
+	int    size;
+	id     key;
+	PyObject* result;
+	struct objc_super super;
+
+	if  (!PyArg_ParseTuple(arguments, "t#O&", &bytes, &size, 
+			PyObjCObject_Convert, &key)) {
+		return NULL;
+	}
+
+	NS_DURING
+		PyObjC_InitSuper(&super, 
+			PyObjCClass_GetClass((PyObject*)(self->ob_type)),
+			PyObjCObject_GetObject(self));
+
+		(void)objc_msgSendSuper(&super,
+				@selector(encodeBytes:length:forKey:),
+				bytes, size, key);
+		result = Py_None;
+		Py_INCREF(result);
+	NS_HANDLER
+		PyObjCErr_FromObjC(localException);
+		result = NULL;
+	NS_ENDHANDLER
+
+	return result;
+}
+
+static void imp_NSCoder_encodeBytes_length_forKey_(id self, SEL sel,
+		char* bytes, int length, id key)	
+{
+	PyObject* result;
+	PyObject* arglist;
+
+	arglist = PyTuple_New(3);
+	if (arglist == NULL) {
+		PyObjCErr_ToObjC();
+		return;
+	}
+
+	PyTuple_SetItem(arglist, 0, PyString_FromStringAndSize(bytes, length));
+	PyTuple_SetItem(arglist, 1, PyInt_FromLong(length));
+	PyTuple_SetItem(arglist, 2, PyObjC_IdToPython(key));
+
+	if (PyErr_Occurred()) {
+		Py_DECREF(arglist);
+		PyObjCErr_ToObjC();
+		return;
+	}
+
+	result = PyObjC_CallPython(self, sel, arglist);
+	Py_DECREF(arglist);
+	if (result == NULL) {
+		PyObjCErr_ToObjC();
+		return;
+	}
+
+	if (result != Py_None) {
+		PyErr_SetString(PyExc_TypeError, "Must return None");
+		Py_DECREF(result);
+		PyObjCErr_ToObjC();
+		return;
+	}
+	Py_DECREF(result);
+}
+
 static int 
 _pyobjc_install_NSCoder(void)
 {
-  Class classNSCoder = objc_lookUpClass("NSCoder");
+	Class classNSCoder = objc_lookUpClass("NSCoder");
   
-  if (PyObjC_RegisterMethodMapping(
-	 classNSCoder,
-	 @selector(encodeArrayOfObjCType:count:at:),
-	 call_NSCoder_encodeArrayOfObjCType_count_at_,
-	 (IMP)imp_NSCoder_encodeArrayOfObjCType_count_at_) < 0) {
-    NSLog(
-    	@"Error occurred while installing NSCoder bridge method -encodeArrayOfObjCType:count:at:");
-    return -1;
-  }
-  if (PyObjC_RegisterMethodMapping(
-	 classNSCoder,
-	 @selector(encodeValueOfObjCType:at:),
-	 call_NSCoder_encodeValueOfObjCType_at_,
-	 (IMP)imp_NSCoder_encodeValueOfObjCType_at_) < 0) {
-    NSLog(@"Error occurred while installing NSCoder bridge method -encodeArrayOfObjCType:at:");
-    return -1;
-  }
+	if (PyObjC_RegisterMethodMapping(
+			classNSCoder,
+			@selector(encodeArrayOfObjCType:count:at:),
+			call_NSCoder_encodeArrayOfObjCType_count_at_,
+			(IMP)imp_NSCoder_encodeArrayOfObjCType_count_at_) < 0) {
+		return -1;
+	}
 
-  if (PyObjC_RegisterMethodMapping(
-	 classNSCoder,
-	 @selector(decodeArrayOfObjCType:count:at:),
-	 call_NSCoder_decodeArrayOfObjCType_count_at_,
-	 (IMP)imp_NSCoder_decodeArrayOfObjCType_count_at_) < 0) {
-    NSLog(
-    	@"Error occurred while installing NSCoder bridge method -encodeArrayOfObjCType:count:at:");
-    return -1;
-  }
+	if (PyObjC_RegisterMethodMapping(
+			classNSCoder,
+			@selector(encodeValueOfObjCType:at:),
+			call_NSCoder_encodeValueOfObjCType_at_,
+			(IMP)imp_NSCoder_encodeValueOfObjCType_at_) < 0) {
+		return -1;
+	}
 
-  if (PyObjC_RegisterMethodMapping(
-	 classNSCoder,
-	 @selector(decodeValueOfObjCType:at:),
-	 call_NSCoder_decodeValueOfObjCType_at_,
-	 (IMP)imp_NSCoder_decodeValueOfObjCType_at_) < 0) {
-    NSLog(@"Error occurred while installing NSCoder bridge method -decodeArrayOfObjCType:at:");
-    return -1;
-  }
+	if (PyObjC_RegisterMethodMapping(
+			classNSCoder,
+			@selector(decodeArrayOfObjCType:count:at:),
+			call_NSCoder_decodeArrayOfObjCType_count_at_,
+			(IMP)imp_NSCoder_decodeArrayOfObjCType_count_at_) < 0) {
+		return -1;
+	}
 
-  return 0;
+	if (PyObjC_RegisterMethodMapping(
+			classNSCoder,
+			@selector(decodeValueOfObjCType:at:),
+			call_NSCoder_decodeValueOfObjCType_at_,
+			(IMP)imp_NSCoder_decodeValueOfObjCType_at_) < 0) {
+		return -1;
+	}
+
+	if (PyObjC_RegisterMethodMapping(
+			classNSCoder,
+			@selector(encodeBytes:length:),
+			call_NSCoder_encodeBytes_length_,
+			(IMP)imp_NSCoder_encodeBytes_length_) < 0) {
+		return -1;
+	}
+
+	if (PyObjC_RegisterMethodMapping(
+			classNSCoder,
+			@selector(encodeBytes:length:forKey:),
+			call_NSCoder_encodeBytes_length_forKey_,
+			(IMP)imp_NSCoder_encodeBytes_length_forKey_) < 0) {
+		return -1;
+	}
+
+	return 0;
 }

File pyobjc/Modules/Foundation/_FoundationMapping_NSData.m

 	struct objc_super super;
 	id        objc_result;
 
-	if  (PyArg_ParseTuple(arguments, "t#i", &bytes, &bytes_len, &len) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "t#i", &bytes, &bytes_len, &len)) {
 		return NULL;
 	}
 
 	struct objc_super super;
 	id        objc_result;
 
-	if  (PyArg_ParseTuple(arguments, "t#i", &bytes, &bytes_len, &len) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "t#i", &bytes, &bytes_len, &len)) {
 		return NULL;
 	}
 
   PyObject* result;
   struct objc_super super;
 
-  if (PyArg_ParseTuple(arguments, "") < 0) {
+  if (!PyArg_ParseTuple(arguments, "")) {
     return NULL;
   }
 
   PyObject* result;
   struct objc_super super;
 
-  if (PyArg_ParseTuple(arguments, "") < 0) {
+  if (!PyArg_ParseTuple(arguments, "")) {
     return NULL;
   }
 

File pyobjc/Modules/Foundation/_FoundationMapping_NSDictionary.m

 	int i;
 	id  res;
 
-	if  (PyArg_ParseTuple(arguments, "OOi", &objectList, &keyList, &count) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "OOi", &objectList, &keyList, &count) ) {
 		return NULL;
 	}
 
 	int i;
 	id  res;
 
-	if  (PyArg_ParseTuple(arguments, "OOi", &objectList, &keyList, &count) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "OOi", &objectList, &keyList, &count)) {
 		return NULL;
 	}
 

File pyobjc/Modules/Foundation/_FoundationMapping_NSMutableArray.m

 	PyObject* realContext;
 	id  res;
 
-	if  (PyArg_ParseTuple(arguments, "OO", &sortFunc, &context) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "OO", &sortFunc, &context)) {
 		return NULL;
 	}
 
 			PyObjCObject_GetObject(self));
 
 			
-		res = objc_msgSendSuper(&super,
+		(void)objc_msgSendSuper(&super,
 				@selector(sortUsingFunction:context:),
 				 SortHelperFunc, realContext);
+		res = nil;
 	NS_HANDLER
 		PyObjCErr_FromObjC(localException);
 		res = nil;
 	PyObject* realContext;
 	id  res;
 
-	if  (PyArg_ParseTuple(arguments, "OOO&O", &sortFunc, &context,
-			 &rangeObj) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "OOO", &sortFunc, &context,
+			 &rangeObj)) {
 		return NULL;
 	}
 
 			PyObjCObject_GetObject(self));
 
 			
-		res = objc_msgSendSuper(&super,
+		(void)objc_msgSendSuper(&super,
 			@selector(sortUsingFunction:context:range:),
-			 sortFunc, realContext, range);
+			 SortHelperFunc, realContext, range);
+		res = nil;
 	NS_HANDLER
 		PyObjCErr_FromObjC(localException);
 		res = nil;
 	int count;
 	int i;
 
-	if  (PyArg_ParseTuple(arguments, "Oi", &indicesList, &count) < 0) {
+	if (!PyArg_ParseTuple(arguments, "Oi", &indicesList, &count)) {
 		return NULL;
 	}
 
 	}
 
 	NS_DURING
-		PyObjC_InitSuperCls(&super, 
+		PyObjC_InitSuper(&super, 
 			PyObjCSelector_GetClass(method),
-			PyObjCClass_GetClass(self));
-
+			PyObjCObject_GetObject(self));
 			
 		objc_msgSendSuper(&super,
 				@selector(removeObjectsFromIndices:numIndices:),
 	int count;
 	int i;
 
-	if  (PyArg_ParseTuple(arguments, "OOi", &rangeObj, &objectList, &count) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "OOi", &rangeObj, &objectList, &count)) {
 		return NULL;
 	}
 

File pyobjc/Modules/Foundation/_FoundationMapping_NSNetService.m

 	int len, i;
 	NSData* item;
 
-	if  (PyArg_ParseTuple(arguments, "") < 0) {
+	if  (!PyArg_ParseTuple(arguments, "")) {
 		return NULL;
 	}
 

File pyobjc/Modules/Foundation/_FoundationMapping_NSScriptObjectSpecifier.m

 	PyObject* v;
 	int i;
 
-	if  (PyArg_ParseTuple(arguments, "O&", 
-			PyObjCObject_Convert, &container) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "O&", 
+			PyObjCObject_Convert, &container)) {
 		return NULL;
 	}
 

File pyobjc/Modules/Foundation/_FoundationMapping_NSSet.m

 	int i;
 	id  res;
 
-	if  (PyArg_ParseTuple(arguments, "Oi", &objectList, &count) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "Oi", &objectList, &count)) {
 		return NULL;
 	}
 
 	int i;
 	id  res;
 
-	if  (PyArg_ParseTuple(arguments, "Oi", &objectList, &count) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "Oi", &objectList, &count)) {
 		return NULL;
 	}
 

File pyobjc/Modules/Foundation/_FoundationMapping_NSString.m

 	struct objc_super super;
 	PyObject* res;
 
-	if  (PyArg_ParseTuple(arguments, "iO", &maxLength, &rangeObj) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "iO", &maxLength, &rangeObj)) {
 		return NULL;
 	}
 
 	struct objc_super super;
 	PyObject* res;
 
-	if  (PyArg_ParseTuple(arguments, "i", &maxLength) < 0) {
+	if  (!PyArg_ParseTuple(arguments, "i", &maxLength)) {
 		return NULL;
 	}
 

File pyobjc/Modules/objc/objc-object.m

 object_repr(PyObjCObject* self)
 {
 	char buffer[256];
+	PyObject* res;
 
+	if (self->flags & PyObjCObject_kUNINITIALIZED) {
+		/* Try to call the method 'description', which is the ObjC
+		 * equivalent of __repr__. If that fails we'll fall back to
+		 * the default repr.
+		 * Don't call 'description' for uninitialized objects, that
+		 * crashes the interpreter for several classes.
+		 */
+		res = PyObject_CallMethod((PyObject*)self, "description", NULL);
+		if (res == NULL) {
+			PyErr_Clear();
+		} else {
+			return res;
+		}
+	}
 	snprintf(buffer, sizeof(buffer), "<%s objective-c instance %p>",
 		self->ob_type->tp_name, self->objc_object);
 
   if you try to pickle one: pickle protocol version 2 silently wrote the 
   incomplete state of objects to the pickle.
 
+- The default repr() of ObjC objects is now the result of a call to the
+  `description` method. This method is not called for unitialized objects,
+  because that might crash the interpreter; we use a default implementation
+  in that case.
+
+- A minor change to the conversion rule for methods with output arguments
+  (pointers to values in ObjC, where the method will write through the pointer).
+  If the method has 'void' as its return type, we used to return a tuple where
+  the first value is always None. This first element is no longer included,
+  furthermore if the method has only 1 output argument we no longer return
+  a tuple but return the output value directly (again only if the method has
+  'void' as its return type).
+  
+  This is a backward incompatible change, but there are not many of such
+  methods.
+
 Version 1.0b1 (2003-07-05):
 
 - More tutorials

File pyobjc/ProjectBuilder Extras/Project Templates/Cocoa-Python-ObjC Document-based Application/Cocoa Python ObjC Document-based Application.pbproj/TemplateInfo.plist

+{
+	FilesToMacroExpand = (
+		"English.lproj/InfoPlist.strings",
+		"bin-python-main.m",
+		"__main__.py",
+		"MyAppDelegate.py",
+                "MyDocument.py",
+                "HueView.m"
+	);
+
+	Description = "This project builds a Cocoa Document-based application written in both Python and Objective-C.  The Objective-C code can be loaded as a bundle, from Python, at runtime.";
+}

File pyobjc/ProjectBuilder Extras/Project Templates/Cocoa-Python-ObjC Document-based Application/Cocoa Python ObjC Document-based Application.pbproj/project.pbxproj

+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 38;
+	objects = {
+		080E96DCFE201CFB7F000001 = {
+			fileRef = 29B97318FDCFA39411CA2CEA;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+		080E96DDFE201D6D7F000001 = {
+			children = (
+				77E8D27903CF5E3A007B4ABE,
+				77E8D27A03CF5E45007B4ABE,
+			);
+			isa = PBXGroup;
+			name = "Cocoa Python ObjC Document-based Application Support Framework";
+			refType = 4;
+		};
+		089C165CFE840E0CC02AAC07 = {
+			children = (
+				089C165DFE840E0CC02AAC07,
+			);
+			isa = PBXVariantGroup;
+			name = InfoPlist.strings;
+			refType = 4;
+		};
+		089C165DFE840E0CC02AAC07 = {
+			fileEncoding = 10;
+			isa = PBXFileReference;
+			name = English;
+			path = English.lproj/InfoPlist.strings;
+			refType = 4;
+		};
+		089C165EFE840E0CC02AAC07 = {
+			fileRef = 089C165CFE840E0CC02AAC07;
+			isa = PBXBuildFile;
+			settings = {
+			};
+		};
+//080
+//081
+//082
+//083
+//084
+//100
+//101
+//102
+//103
+//104
+		1058C7A1FEA54F0111CA2CBB = {
+			isa = PBXFrameworkReference;
+			name = Cocoa.framework;
+			path = /System/Library/Frameworks/Cocoa.framework;
+			refType = 0;
+		};
+//100
+//101
+//102
+//103
+//104
+//170
+//171
+//172
+//173
+//174
+		17587328FF379C6511CA2CBB = {
+			isa = PBXApplicationReference;
+			path = "Cocoa Python ObjC Document-based Application.app";
+			refType = 3;
+		};
+//170
+//171
+//172
+//173
+//174
+//190
+//191
+//192
+//193
+//194
+		19C28FACFE9D520D11CA2CBB = {
+			children = (
+				77E8D25A03CF5BBD007B4ABE,
+				17587328FF379C6511CA2CBB,
+			);
+			isa = PBXGroup;
+			name = Products;
+			refType = 4;
+		};
+//190
+//191
+//192
+//193
+//194
+//290
+//291
+//292
+//293
+//294
+		29B97313FDCFA39411CA2CEA = {
+			buildStyles = (
+				4A9504CCFFE6A4B311CA0CBA,
+				4A9504CDFFE6A4B311CA0CBA,
+			);
+			hasScannedForEncodings = 1;
+			isa = PBXProject;
+			mainGroup = 29B97314FDCFA39411CA2CEA;
+			projectDirPath = "";
+			targets = (
+				29B97326FDCFA39411CA2CEA,
+				77E8D25903CF5BBD007B4ABE,
+			);
+		};
+		29B97314FDCFA39411CA2CEA = {
+			children = (
+				080E96DDFE201D6D7F000001,
+				77E8D27003CF5E08007B4ABE,
+				29B97323FDCFA39411CA2CEA,
+				19C28FACFE9D520D11CA2CBB,
+			);
+			isa = PBXGroup;
+			name = "Cocoa Python ObjC Document-based Application";
+			path = "";
+			refType = 4;
+		};
+		29B97315FDCFA39411CA2CEA = {
+			children = (
+				F60DD8BC0358A22201C8ED3C,
+				29B97316FDCFA39411CA2CEA,
+			);
+			isa = PBXGroup;
+			name = "Other Sources";
+			path = "";
+			refType = 4;
+		};
+		29B97316FDCFA39411CA2CEA = {
+			fileEncoding = 30;
+			isa = PBXFileReference;
+			path = "bin-python-main.m";
+			refType = 4;
+		};
+		29B97317FDCFA39411CA2CEA = {
+			children = (
+				29B97318FDCFA39411CA2CEA,
+				FD39B5B8048105FD00FE993C,
+				089C165CFE840E0CC02AAC07,
+			);
+			isa = PBXGroup;
+			name = Resources;
+			path = "";
+			refType = 4;
+		};
+		29B97318FDCFA39411CA2CEA = {
+			children = (
+				29B97319FDCFA39411CA2CEA,
+			);
+			isa = PBXVariantGroup;
+			name = MainMenu.nib;
+			path = "";
+			refType = 4;
+		};
+		29B97319FDCFA39411CA2CEA = {
+			isa = PBXFileReference;
+			name = English;
+			path = English.lproj/MainMenu.nib;
+			refType = 4;
+		};
+		29B97323FDCFA39411CA2CEA = {
+			children = (
+				29B97324FDCFA39411CA2CEA,
+				1058C7A1FEA54F0111CA2CBB,
+				29B97325FDCFA39411CA2CEA,
+				77AD447303ECA731004B557F,
+			);
+			isa = PBXGroup;
+			name = "Frameworks & Modules";
+			path = "";
+			refType = 4;
+		};
+		29B97324FDCFA39411CA2CEA = {
+			isa = PBXFrameworkReference;
+			name = AppKit.framework;
+			path = /System/Library/Frameworks/AppKit.framework;
+			refType = 0;
+		};
+		29B97325FDCFA39411CA2CEA = {
+			isa = PBXFrameworkReference;
+			name = Foundation.framework;
+			path = /System/Library/Frameworks/Foundation.framework;
+			refType = 0;
+		};
+		29B97326FDCFA39411CA2CEA = {
+			buildPhases = (
+				29B97327FDCFA39411CA2CEA,
+				29B97328FDCFA39411CA2CEA,
+				29B9732BFDCFA39411CA2CEA,
+				29B9732DFDCFA39411CA2CEA,
+				77AD48AF03ECA8D0004B557F,
+			);
+			buildSettings = {
+				FRAMEWORK_SEARCH_PATHS = "";
+				HEADER_SEARCH_PATHS = "";
+				INSTALL_PATH = "$(HOME)/Applications";
+				LIBRARY_SEARCH_PATHS = "";
+				OTHER_CFLAGS = "";
+				OTHER_LDFLAGS = "";
+				PRODUCT_NAME = "Cocoa Python ObjC Document-based Application";
+				SECTORDER_FLAGS = "";
+				WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
+				WRAPPER_EXTENSION = app;
+			};
+			dependencies = (
+				77E8D25B03CF5BC6007B4ABE,
+			);
+			isa = PBXApplicationTarget;
+			name = "Cocoa Python ObjC Document-based Application";
+			productInstallPath = "$(HOME)/Applications";
+			productName = "Cocoa Python ObjC Document-based Application";
+			productReference = 17587328FF379C6511CA2CBB;
+			productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleDocumentTypes</key>
+	<array>
+		<dict>
+			<key>CFBundleTypeExtensions</key>
+			<array>
+				<string>????</string>
+			</array>
+			<key>CFBundleTypeName</key>
+			<string>DocumentType</string>
+			<key>CFBundleTypeOSTypes</key>
+			<array>
+				<string>????</string>
+			</array>
+			<key>CFBundleTypeRole</key>
+			<string>Editor</string>
+			<key>NSDocumentClass</key>
+			<string>MyDocument</string>
+		</dict>
+	</array>
+	<key>CFBundleExecutable</key>
+	<string>Cocoa Python ObjC Document-based Application</string>
+	<key>CFBundleIconFile</key>
+	<string></string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>0.1</string>
+	<key>NSMainNibFile</key>
+	<string>MainMenu</string>
+	<key>NSPrincipalClass</key>
+	<string>NSApplication</string>
+</dict>
+</plist>
+";
+		};
+		29B97327FDCFA39411CA2CEA = {
+			buildActionMask = 2147483647;
+			files = (
+				522A55F104BC463900A801E3,
+			);
+			isa = PBXHeadersBuildPhase;
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		29B97328FDCFA39411CA2CEA = {
+			buildActionMask = 2147483647;
+			files = (
+				080E96DCFE201CFB7F000001,
+				089C165EFE840E0CC02AAC07,
+				77E8D26F03CF5BF4007B4ABE,
+				FD39B5BA048105FD00FE993C,
+				522A55ED04BC463600A801E3,
+				522A55EE04BC463700A801E3,
+			);
+			isa = PBXResourcesBuildPhase;
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		29B9732BFDCFA39411CA2CEA = {
+			buildActionMask = 2147483647;
+			files = (
+				29B9732CFDCFA39411CA2CEA,
+				522A55F004BC463900A801E3,
+			);
+			isa = PBXSourcesBuildPhase;
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		29B9732CFDCFA39411CA2CEA = {
+			fileRef = 29B97316FDCFA39411CA2CEA;
+			isa = PBXBuildFile;
+			settings = {
+				ATTRIBUTES = (
+				);
+			};
+		};
+		29B9732DFDCFA39411CA2CEA = {
+			buildActionMask = 2147483647;
+			files = (
+				F60DD8CF0358A5C101C8ED3C,