Commits

Ronald Oussoren committed b90dea6

- Try to clear up a number of exception messages
- OC_PythonObject methods -valueForKey and -takeValue:forKey: are now
implemented using getKey and setKey from PyObjCTools.KeyValueCoding.
- Remove the KeyValueCodingMixIn class from that module, it's not necessary.
- Make Doc/wrapping.txt slightly less confusing, based on input by
Pierce T. Wetter III <pierce (at) twinforces (dot) com>
- the getKey function now checks if object.key is a method, an if so calls
that instead of returning the method.
- the same is true for the KeyValueCoding implementation for hybrid objects
(in class-builder.m)
- Add testcases for the new behaviour
- Merge PyObjCTools.test.test_keyvalue2 into the other keyvalue tests.

Comments (0)

Files changed (20)

pyobjc/Doc/PyObjCTools.html

 <li>the return value of <code><span>object.getKey()</span></code></li>
 <li>the return value of <code><span>object._get_key()</span></code></li>
 <li>the return value of <code><span>object._getKey()</span></code></li>
-<li>the value of the attribute <code><span>key</span></code></li>
-<li>the value of the attribue <code><span>_key</span></code></li>
+<li>the value of the attribute <code><span>key</span></code>, or the value of <code><span>object.key()</span></code> if
+<code><span>object.key</span></code> is a method.</li>
+<li>the value of the attribue <code><span>_key</span></code>, or the vale of <code><span>object._key()</span></code> if
+<code><span>object._key</span></code> is a method.</li>
 </ul>
 </li>
 <li><code><span>getKeyPath(object,</span> <span>keypath)</span> <span>-&gt;</span> <span>value</span></code><p>Like <code><span>getKey</span></code> but using a key path. The <code><span>keypath</span></code> is a sequence of keys

pyobjc/Doc/PyObjCTools.txt

 
   - the return value of ``object._getKey()``
 
-  - the value of the attribute ``key``
+  - the value of the attribute ``key``, or the value of ``object.key()`` if
+    ``object.key`` is a method.
 
-  - the value of the attribue ``_key``
+  - the value of the attribue ``_key``, or the vale of ``object._key()`` if
+    ``object._key`` is a method.
 
 * ``getKeyPath(object, keypath) -> value``
 
 The first two bullets require at least some GUI tests.
 
 
+
 Less important items
 --------------------
 

pyobjc/Doc/index.html

 <li><a href="intro.html">An introduction to PyObjC</a><p>An overview of the PyObjC package and how to use it. Read this before
 you start using the package, it will help you to avoid some surprises.</p>
 </li>
-<li><a href="users.html">Userguide for PyObjC</a><p>An older overview of PyObjC.</p>
-</li>
 <li><a href="classes.html">Python classes and Objective-C code</a><p>Another older overview of PyObjC.</p>
 </li>
 <li><a href="api-notes-macosx.html">Notes on supported APIs and classes on MacOS X</a><p>This document lists the methods and classes that are not fully supported,

pyobjc/Doc/wrapping.html

    bundle_path='/path/to/MyFramework.framework')
 del objc
 </pre>
+<p>In general you should not load frameworks this way, but you should write a
+package or module to do this for you (e.g. place this code in <code><span>MyFramework.py</span></code>
+or <code><span>MyFramework/__init__.py</span></code>. This makes it possible to 
+<code><span>import</span> <span>MyFramework</span></code> which is much more convenient.</p>
 <p>If your class library does not require helper functions for some methods this
 is all that is needed.</p>
-<p>Don't forget to import the frameworks that are used by your framework before
-calling <code><span>objc.loadBundle</span></code>. This is necessary to arrange for the helper code
-for these modules (if there is any) to be loaded. Not importing the those
-wrappers can lead to subtle bugs in unrelated code!</p>
+<p>It is currently necessary to import the wrapper modules for all frameworks that
+are used by your framework. Not doing this may lead to subtle bugs in other
+parts of the code. This is a limitation of PyObjC that will be 
+lifted in a future version.</p>
 <h2><a name="wrapping-global-functions-and-constants">Wrapping global functions and constants</a></h2>
 <p>The code above only provides wrappers for Objective-C classes, if the library
 also defines global functions and/or constants you'll have to write an 

pyobjc/Doc/wrapping.txt

       bundle_path='/path/to/MyFramework.framework')
    del objc
 
+In general you should not load frameworks this way, but you should write a
+package or module to do this for you (e.g. place this code in ``MyFramework.py``
+or ``MyFramework/__init__.py``. This makes it possible to 
+``import MyFramework`` which is much more convenient.
+
 If your class library does not require helper functions for some methods this
 is all that is needed.
 
-Don't forget to import the frameworks that are used by your framework before
-calling ``objc.loadBundle``. This is necessary to arrange for the helper code
-for these modules (if there is any) to be loaded. Not importing the those
-wrappers can lead to subtle bugs in unrelated code!
+It is currently necessary to import the wrapper modules for all frameworks that
+are used by your framework. Not doing this may lead to subtle bugs in other
+parts of the code. This is a limitation of PyObjC that will be 
+lifted in a future version.
 
 Wrapping global functions and constants
 ---------------------------------------

pyobjc/Lib/PyObjCTools/KeyValueCoding.py

 __all__ = ("getKey", "setKey", "getKeyPath", "setKeyPath")
 
 import objc
+import types
 
 def getKey(obj, key):
     """
     The following attributes and accesors at tried (in this order):
     - Accessor 'getKey'
     - Accesoor 'get_key'
-    - Attribute 'key'
+    - Attribute or accessor 'key' 
     - Attribute '_key'
 
     If none of these exist, raise KeyError
         return m()
 
     try:
-        return getattr(obj, key)
+        m = getattr(obj, key)
+        if isinstance(m, (types.MethodType, types.BuiltinMethodType)):
+            return m()
+        else:
+            return m
     except AttributeError:
         pass
 
     try:
-        return getattr(obj, "_" + key)
+        m = getattr(obj, "_" + key)
+        if isinstance(m, types.MethodType):
+            return m()
+        else:
+            return m
     except AttributeError:
         pass
 
         cur = getKey(cur, e)
 
     return setKey(cur, elements[-1], value)
-
-class KeyValueCodingMixIn:
-    def valueForKey_(self, aKey):
-        return getKey(self, aKey)
-
-    def takeValue_forKey_(self, aValue, aKey):
-        return setKey(self, aKey, aValue)
-
-    def valueForKeyPath_(self, aKey):
-        return getKeyPath(self, aKey)
-                    
-    def takeValue_forKeyPath_(self, aValue, aKey):
-        return setKeyPath(self, aKey, aValue)
-

pyobjc/Lib/PyObjCTools/test/test_keyvalue.py

 """
 
 from PyObjCTools.KeyValueCoding import *
+from objc.test.keyvaluehelper import *
 import objc
 import unittest
 
         setKeyPath(o, "multiple.level2.level3.keyB", 9.999)
         self.assertEquals(o.multiple.level2.level3.keyB, 9.999)
 
+class MethodsAsKeys (unittest.TestCase):
+
+    def testStrCap (self):
+        s = "hello"
+
+        self.assertEquals(getKey(s, 'capitalize'), "Hello")
+
+
+class AbstractKVCodingTest:
+    def testBaseValueForKey(self):
+        self.assertEquals(DirectString, 
+            getKey( self.base, "directString"))
+        self.assertEquals(IndirectString, 
+            getKey( self.base, "indirectString"))
+        self.assertEquals(DirectNumber, 
+            getKey( self.base, "directNumber"))
+        self.assertEquals(IndirectNumber, 
+            getKey( self.base, "indirectNumber"))
+               
+    def testPathValueForKey(self):
+        self.assertEquals(DirectString, 
+            getKeyPath( self.path, "directHead.directString"))
+        self.assertEquals(DirectString, 
+            getKeyPath( self.path, "indirectHead.directString"))
+        self.assertEquals(IndirectString, 
+            getKeyPath( self.path, "directHead.indirectString"))
+        self.assertEquals(IndirectString, 
+            getKeyPath( self.path, "indirectHead.indirectString"))
+        self.assertEquals(DirectNumber, 
+            getKeyPath( self.path, "directHead.directNumber"))
+        self.assertEquals(DirectNumber, 
+            getKeyPath( self.path, "indirectHead.directNumber"))
+        self.assertEquals(IndirectNumber, 
+            getKeyPath( self.path, "directHead.indirectNumber"))
+        self.assertEquals(IndirectNumber, 
+            getKeyPath( self.path, "indirectHead.indirectNumber"))
+
+class TestObjCKVCoding(AbstractKVCodingTest, unittest.TestCase):
+    def setUp(self):
+        self.base = PyObjCTest_KVBaseClass.new()
+        self.path = PyObjCTest_KVPathClass.new()
+
+class TestPythonKVCoding(AbstractKVCodingTest, unittest.TestCase):
+    def setUp(self):
+        self.base = KVPyBase()
+        self.path = KVPyPath()
+
+class TestPythonSubObjCContainerCoding(AbstractKVCodingTest, unittest.TestCase):
+    def setUp(self):
+        self.base = KVPySubObjCBase.new()
+        self.path = KVPySubObjCPath.new()
+
+class TestPythonSubOverObjC(AbstractKVCodingTest, unittest.TestCase):
+    def setUp(self):
+        self.base = KVPySubOverObjCBase.new()
+        self.path = KVPySubOverObjCPath.new()
+
+    def testOverValueKey(self):
+        self.assertEquals(DirectString, 
+            getKey( self.base, "overDirectString"))
+        self.assertEquals(IndirectString, 
+            getKey( self.base, "overIndirectString"))
+
+    def testOverValueKeyPath(self):
+        self.assertEquals(DirectString, 
+            getKeyPath( self.path, "overDirectHead.directString"))
+        self.assertEquals(DirectString, 
+            getKeyPath( self.path, "overIndirectHead.directString"))
+        self.assertEquals(IndirectString, 
+            getKeyPath( self.path, "overDirectHead.indirectString"))
+        self.assertEquals(IndirectString, 
+            getKeyPath( self.path, "overIndirectHead.indirectString"))
+
 if __name__ == "__main__":
     unittest.main()

pyobjc/Lib/PyObjCTools/test/test_keyvalue2.py

-"""
-Tests for PyObjCTools.KeyValueCoding
-
-TODO: 
-    - Accessing properties in superclass of ObjC hybrids (see also Foundation.test.test_keyvalue)
-
-NOTE: Testcases here should be synchronized with the Key-Value Coding tests
-in objc.test.test_keyvalue and Foundation.test.test_keyvalue.
-"""
-
-from PyObjCTools import KeyValueCoding
-import objc
-import unittest
-
-from PyObjCTools.test.testkvcodingbndl import *
-
-DirectString = u'Direct String'
-IndirectString = u'Indirect String'
-DirectNumber = 42
-IndirectNumber = 84
-
-class KVPyBase(KeyValueCoding.KeyValueCodingMixIn):
-    def __init__(self):
-        self.directString = DirectString
-        self._indirectString = IndirectNumber
-        self.directNumber = DirectNumber
-        self._indirectNumber = IndirectNumber
-
-    def indirectString(self):
-        return self._indirectString
-    def setIndirectString_(self, aString):
-        self._indirectString = aString
-
-    def indirectNumber(self):
-        return self._indirectNumber
-    def setIndirectNumber_(self, aNumber):
-        self._indirectNumber = aNumber
-
-class KVPyPath(KeyValueCoding.KeyValueCodingMixIn):
-    def __init__(self):
-        self.directHead = KVPyBase()
-        self._indirectHead = KVPyBase()
-
-    def indirectHead(self):
-        return self._indirectHead
-    def setIndirectHead_(self, aHead):
-        self._indirectHead = aHead
-
-class KVPySubObjCBase(KVBaseClass):
-    pass
-
-class KVPySubObjCPath(KVPathClass):
-    pass
-
-class KVPySubOverObjCBase(KVBaseClass):
-    def init(self):
-        super(KVPySubOverObjCBase, self).init()
-        self.overDirect = DirectString
-        self._overIndirect = IndirectString
-
-    def overIndirectString(self):
-        return self._overIndirect
-    def setOverIndirectString_(self, aString):
-        self._overIndirect = aString
-
-class KVPySubOverObjCPath(KVPathClass):
-    def init(self):
-        super(KVPySubOverObjCPath, self).init()
-        self.overDirectHead = KVPySubOverObjCBase.new()
-        self._overIndirectHead = KVPySubOverObjCBase.new()
-
-    def overIndirectHead(self):
-        return self._overIndirectHead
-    def setOverIndirectHead_(self, aHead):
-        self._overIndirectHead = aHead
-
-class AbstractKVCodingTest:
-    def testBaseCValueForKey(self):
-        self.assertEquals(DirectString, self.base.valueForKey_("directString"))
-        self.assertEquals(IndirectString, self.base.valueForKey_("indirectString"))
-        self.assertEquals(DirectNumber, self.base.valueForKey_("directNumber"))
-        self.assertEquals(IndirectNumber, self.base.valueForKey_("indirectNumber"))
-
-    def testPathValueForKey(self):
-        self.assertEquals(DirectString, self.path.valueForKeyPath_("directHead.directString"))
-        self.assertEquals(IndirectString, self.path.valueForKeyPath_("indirectHead.indirectString"))
-        self.assertEquals(DirectNumber, self.path.valueForKeyPath_("directHead.directNumber"))
-        self.assertEquals(IndirectNumber, self.path.valueForKeyPath_("indirectHead.indirectNumber"))
-        
-class TestObjCKVCoding(AbstractKVCodingTest, unittest.TestCase):
-    def setUp(self):
-        self.base = KVBaseClass.new()
-        self.path = KVPathClass.new()
-
-class TestPythonKVCoding(AbstractKVCodingTest, unittest.TestCase):
-    def setUp(self):
-        self.base = KVPyBase()
-        self.path = KVPyPath()
-
-class TestPythonSubObjCContainerCoding(AbstractKVCodingTest, unittest.TestCase):
-    def setUp(self):
-        self.base = KVPySubObjCBase.new()
-        self.path = KVPySubObjCPath.new()
-
-class TestPythonSubOverObjC(AbstractKVCodingTest, unittest.TestCase):
-    def setUp(self):
-        self.base = KVPySubOverObjCBase.new()
-        self.path = KVPySubOverObjCPath.new()
-
-    def testOverValueForKey(self):
-        self.assertEquals(DirectString, self.base.valueForKey_("overDirectString"))
-        self.assertEquals(IndirectString, self.base.valueForKey_("overIndirectString"))
-
-    def testOverValueForKeyPath(self):
-        self.assertEquals(DirectString, self.path.valueForKeyPath_("overDirectHead.directString"))
-        self.assertEquals(IndirectString, self.path.valueForKeyPath_("overIndirectHead.indirectString"))
-
-if __name__ == "__main__":
-    unittest.main()

pyobjc/Lib/PyObjCTools/test/testkvcodingbndl.m

-/*
- * This file implements a (number of) class(es) that are used to test
- * the Key/Value coding support within PyObjC
- *
- * NOTES
- * - The implementation must be synchronized with test_keyvalue2.py, see that
- *   file for more details.
- */
-#import <Foundation/Foundation.h>
-
-#include <Python.h>
-#include <pyobjc-api.h>
-#include <objc/objc-runtime.h>
-
-
-@interface KVBaseClass : NSObject
-{
-    NSString *directString;
-    NSNumber *directNumber;
-    NSString *indirectString;
-    NSNumber *indirectNumber;
-}
-@end
-
-@implementation KVBaseClass
-- init
-{
-    self = [super init];
-    if (!self) return nil;
-
-    directString = [@"Direct String" retain];
-    directNumber = [[NSNumber numberWithInt: 42] retain];
-    indirectString = [@"Indirect String" retain];
-    indirectNumber = [[NSNumber numberWithInt: 84] retain];
-
-    return self;
-}
-
-- (NSString *) indirectString; { return indirectString; }
-- (void) setIndirectString: (NSString *) aString;
-{
-    [aString retain];
-    [indirectString release];
-    indirectString = aString;
-}
-
-- (NSNumber *) indirectNumber; { return indirectNumber; }
-- (void) setIndirectNumber: (NSNumber *) aNumber;
-{
-    [aNumber retain];
-    [indirectNumber release];
-    indirectNumber = aNumber;
-}
-@end
-
-@interface KVPathClass : NSObject
-{
-    KVBaseClass *directHead;
-    KVBaseClass *indirectHead;
-}
-@end
-
-@implementation KVPathClass
-- init
-{
-    self = [super init];
-    if (!self) return nil;
-
-    directHead = [[KVBaseClass alloc] init];
-    indirectHead = [[KVBaseClass alloc] init];
-
-    return self;
-}
-
-- (KVBaseClass *) indirectHead { return indirectHead; } 
-- (void) setInidrectHead: (KVBaseClass *) aHead;
-{
-    [aHead retain];
-    [indirectHead release];
-    indirectHead = aHead;
-}
-@end
-
-/* Python glue */
-
-static PyMethodDef no_methods[] = {
-	{ 0, 0, 0, 0 }
-};
-
-void inittestkvcodingbndl(void);
-void inittestkvcodingbndl(void)
-{
-    PyObject* m;
-
-    m = Py_InitModule4("testkvcodingbndl", no_methods, 
-		       NULL, NULL, PYTHON_API_VERSION);
-    if (!m) return;
-
-    if (PyObjC_ImportAPI(m) < 0) return;
-
-    PyModule_AddObject(m, "KVBaseClass", 
-		       PyObjCClass_New([KVBaseClass class]));
-    PyModule_AddObject(m, "KVPathClass", 
-		       PyObjCClass_New([KVPathClass class]));
-}

pyobjc/Lib/objc/test/keyvaluehelper.py

+"""
+Helper module for KeyValue tests
+"""
+from objc.test.testbndl import PyObjCTest_KVBaseClass, PyObjCTest_KVPathClass
+
+DirectString = u'Direct String'
+IndirectString = u'Indirect String'
+DirectNumber = 42
+IndirectNumber = 84
+
+class KVPyBase:
+    def __init__(self):
+        self.directString = DirectString
+        self._indirectString = IndirectString
+        self.directNumber = DirectNumber
+        self._indirectNumber = IndirectNumber
+
+    def get_indirectString(self):
+        return self._indirectString
+
+    def set_indirectString(self, aString):
+        self._indirectString = aString
+
+    def getIndirectNumber(self):
+        return self._indirectNumber
+
+    def setIndirectNumber(self, aNumber):
+        self._indirectNumber = aNumber
+
+class KVPyPath:
+    def __init__(self):
+        self.directHead = KVPyBase()
+        self._indirectHead = KVPyBase()
+
+    def indirectHead(self):
+        return self._indirectHead
+
+    def setIndirectHead(self, aHead):
+        self._indirectHead = aHead
+
+class KVPySubObjCBase (PyObjCTest_KVBaseClass):
+    pass
+
+class KVPySubObjCPath (PyObjCTest_KVPathClass):
+    pass
+
+class KVPySubOverObjCBase (PyObjCTest_KVBaseClass):
+    def init(self):
+        self = super(KVPySubOverObjCBase, self).init()
+        if not self:
+            return self
+
+        self.overDirectString = DirectString
+        self._overIndirectString = IndirectString
+        return self
+
+    def getOverIndirectString(self):
+        return self._overIndirectString
+
+    def setOverIndirectString(self, aString):
+        self._overIndirectString = aString
+
+class KVPySubOverObjCPath(PyObjCTest_KVPathClass):
+    def init(self):
+        self = super(KVPySubOverObjCPath, self).init()
+        self.overDirectHead = KVPySubOverObjCBase.new()
+        self._overIndirectHead = KVPySubOverObjCBase.new()
+        return self
+
+    def overIndirectHead(self):
+        return self._overIndirectHead
+
+    def setOverIndirectHead(self, aHead):
+        self._overIndirectHead = aHead

pyobjc/Lib/objc/test/test_keyvalue.py

 # Native code is needed to access the python class from Objective-C, otherwise
 # the Key-Value support cannot be tested.
 from objc.test.testbndl import PyObjC_TestClass3 as STUB
+from objc.test.testbndl import *
+from objc.test.keyvaluehelper import *
 
 class KeyValueClass2 (object):
     def __init__(self):
         # Private instance variables ('anObject.__value') are not accessible using
         # key-value coding.
         o = KeyValueClass2()
-        self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 0, o, "private")
+        self.assertRaises(KeyError, 
+                STUB.keyValue_forObject_key_, DO_VALUEFORKEY, o, "private")
 
     def testValueForKey(self):
         o = KeyValueClass2()
         o.addMultiple()
 
-        self.assertEquals(STUB.keyValue_forObject_key_(0, o, "key1"), 1)
-        self.assertEquals(STUB.keyValue_forObject_key_(0, o, "key2"), 2)
-        self.assertEquals(STUB.keyValue_forObject_key_(0, o, "key3"), 3)
-        self.assertEquals(STUB.keyValue_forObject_key_(0, o, "key4"), "4")
-        self.assertEquals(STUB.keyValue_forObject_key_(0, o, "multiple"), o.multiple)
+        self.assertEquals(STUB.keyValue_forObject_key_(DO_VALUEFORKEY, o, "key1"), 1)
+        self.assertEquals(STUB.keyValue_forObject_key_(DO_VALUEFORKEY, o, "key2"), 2)
+        self.assertEquals(STUB.keyValue_forObject_key_(DO_VALUEFORKEY, o, "key3"), 3)
+        self.assertEquals(STUB.keyValue_forObject_key_(DO_VALUEFORKEY, o, "key4"), "4")
+        self.assertEquals(STUB.keyValue_forObject_key_(DO_VALUEFORKEY, o, "multiple"), o.multiple)
        
-        self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 0, o, "nokey")
+        self.assertRaises(KeyError, STUB.keyValue_forObject_key_, DO_VALUEFORKEY, o, "nokey")
 
     def testValueForKey2(self):
         o = KeyValueClass3()
 
-        self.assertEquals(STUB.keyValue_forObject_key_(0, o, "foo"), "foobar")
-        self.assertEquals(STUB.keyValue_forObject_key_(0, o, "bar"), "foobarfoobar")
-        self.assertEquals(STUB.keyValue_forObject_key_(0, o, "roprop"), "read-only")
+        self.assertEquals(STUB.keyValue_forObject_key_(DO_VALUEFORKEY, o, "foo"), "foobar")
+        self.assertEquals(STUB.keyValue_forObject_key_(DO_VALUEFORKEY, o, "bar"), "foobarfoobar")
+        self.assertEquals(STUB.keyValue_forObject_key_(DO_VALUEFORKEY, o, "roprop"), "read-only")
 
     def testStoredValueForKey(self):
         o = KeyValueClass2()
         o.addMultiple()
 
-        self.assertEquals(STUB.keyValue_forObject_key_(2, o, "key1"), 1)
-        self.assertEquals(STUB.keyValue_forObject_key_(2, o, "key2"), 2)
-        self.assertEquals(STUB.keyValue_forObject_key_(2, o, "key3"), 3)
-        self.assertEquals(STUB.keyValue_forObject_key_(2, o, "key4"), "4")
-        self.assertEquals(STUB.keyValue_forObject_key_(2, o, "multiple"), o.multiple)
+        self.assertEquals(STUB.keyValue_forObject_key_(DO_STOREDVALUEFORKEY, o, "key1"), 1)
+        self.assertEquals(STUB.keyValue_forObject_key_(DO_STOREDVALUEFORKEY, o, "key2"), 2)
+        self.assertEquals(STUB.keyValue_forObject_key_(DO_STOREDVALUEFORKEY, o, "key3"), 3)
+        self.assertEquals(STUB.keyValue_forObject_key_(DO_STOREDVALUEFORKEY, o, "key4"), "4")
+        self.assertEquals(STUB.keyValue_forObject_key_(DO_STOREDVALUEFORKEY, o, "multiple"), o.multiple)
        
-        self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 2, o, "nokey")
+        self.assertRaises(KeyError, STUB.keyValue_forObject_key_, DO_STOREDVALUEFORKEY, o, "nokey")
 
     def testStoredValueForKey2(self):
         o = KeyValueClass3()
 
-        self.assertEquals(STUB.keyValue_forObject_key_(2, o, "foo"), "foobar")
-        self.assertEquals(STUB.keyValue_forObject_key_(2, o, "bar"), "foobarfoobar")
-        self.assertEquals(STUB.keyValue_forObject_key_(2, o, "roprop"), "read-only")
+        self.assertEquals(STUB.keyValue_forObject_key_(DO_STOREDVALUEFORKEY, o, "foo"), "foobar")
+        self.assertEquals(STUB.keyValue_forObject_key_(DO_STOREDVALUEFORKEY, o, "bar"), "foobarfoobar")
+        self.assertEquals(STUB.keyValue_forObject_key_(DO_STOREDVALUEFORKEY, o, "roprop"), "read-only")
 
     def testValueForKeyPath(self):
         o = KeyValueClass2()
         o.addMultiple()
 
-        self.assertEquals(STUB.keyValue_forObject_key_(1, o, "multiple"), o.multiple)
-        self.assertEquals(STUB.keyValue_forObject_key_(1, o, "multiple.level2"), o.multiple.level2)
-        self.assertEquals(STUB.keyValue_forObject_key_(1, o, "multiple.level2.level3.keyA"), o.multiple.level2.level3.keyA)
-        self.assertEquals(STUB.keyValue_forObject_key_(1, o, "multiple.level2.level3.keyB"), o.multiple.level2.level3.keyB)
+        self.assertEquals(STUB.keyValue_forObject_key_(DO_VALUEFORKEYPATH, o, "multiple"), o.multiple)
+        self.assertEquals(STUB.keyValue_forObject_key_(DO_VALUEFORKEYPATH, o, "multiple.level2"), o.multiple.level2)
+        self.assertEquals(STUB.keyValue_forObject_key_(DO_VALUEFORKEYPATH, o, "multiple.level2.level3.keyA"), o.multiple.level2.level3.keyA)
+        self.assertEquals(STUB.keyValue_forObject_key_(DO_VALUEFORKEYPATH, o, "multiple.level2.level3.keyB"), o.multiple.level2.level3.keyB)
 
-        self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 1, o, "multiple.level2.nokey")
+        self.assertRaises(KeyError, STUB.keyValue_forObject_key_, DO_VALUEFORKEYPATH, o, "multiple.level2.nokey")
 
     def testValuesForKeys(self):
         o = KeyValueClass2()
 
-        self.assertEquals(STUB.keyValue_forObject_key_(3, o, ["key1", "key2", "key3", "key4"]), { "key1":1, "key2": 2, "key3": 3, "key4": "4"} )
+        self.assertEquals(STUB.keyValue_forObject_key_(DO_VALUESFORKEYS, o, ["key1", "key2", "key3", "key4"]), { "key1":1, "key2": 2, "key3": 3, "key4": "4"} )
 
-        self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 3, o, [ "key1", "key2", "nokey", "key3" ])
+        self.assertRaises(KeyError, STUB.keyValue_forObject_key_, DO_VALUESFORKEYS, o, [ "key1", "key2", "nokey", "key3" ])
 
     def testTakeValueForKey(self):
         o = KeyValueClass2()
 
         self.assertEquals(o.key3, 3)
-        STUB.setKeyValue_forObject_key_value_(0, o, 'key3', 'drie')
+        STUB.setKeyValue_forObject_key_value_(DO_TAKEVALUE_FORKEY, o, 'key3', 'drie')
         self.assertEquals(o.key3, "drie")
         
         self.assertEquals(o._key4, "4")
-        STUB.setKeyValue_forObject_key_value_(0, o, 'key4', 'vier')
+        STUB.setKeyValue_forObject_key_value_(DO_TAKEVALUE_FORKEY, o, 'key4', 'vier')
         self.assertEquals(o._key4, "viervierviervier")
 
         o.key5 = 1
-        STUB.setKeyValue_forObject_key_value_(0, o, 'key5', 'V')
+        STUB.setKeyValue_forObject_key_value_(DO_TAKEVALUE_FORKEY, o, 'key5', 'V')
         self.assertEquals(o.key5, "VVVVV")
 
         self.assert_(not hasattr(o, 'key9'))
-        STUB.setKeyValue_forObject_key_value_(0, o, 'key9', 'IX')
+        STUB.setKeyValue_forObject_key_value_(DO_TAKEVALUE_FORKEY, o, 'key9', 'IX')
         self.assert_(hasattr(o, 'key9'))
         self.assertEquals(o.key9, 'IX')
 
         o = KeyValueClass3()
 
         self.assertEquals(o.foo, "foobar")
-        STUB.setKeyValue_forObject_key_value_(0, o, 'foo', 'FOO')
+        STUB.setKeyValue_forObject_key_value_(DO_TAKEVALUE_FORKEY, o, 'foo', 'FOO')
         self.assertEquals(o.foo, "FOO")
 
-        self.assertRaises(KeyError, STUB.setKeyValue_forObject_key_value_, 0, o, 'key9', 'IX')
+        self.assertRaises(KeyError, STUB.setKeyValue_forObject_key_value_, DO_TAKEVALUE_FORKEY, o, 'key9', 'IX')
 
     def testTakeStoredValueForKey(self):
         o = KeyValueClass2()
 
         self.assertEquals(o.key3, 3)
-        STUB.setKeyValue_forObject_key_value_(2, o, 'key3', 'drie')
+        STUB.setKeyValue_forObject_key_value_(DO_TAKESTOREDVALUE_FORKEY, o, 'key3', 'drie')
         self.assertEquals(o.key3, "drie")
         
         self.assertEquals(o._key4, "4")
-        STUB.setKeyValue_forObject_key_value_(2, o, 'key4', 'vier')
+        STUB.setKeyValue_forObject_key_value_(DO_TAKESTOREDVALUE_FORKEY, o, 'key4', 'vier')
         self.assertEquals(o._key4, "viervierviervier")
 
         o.key5 = 1
-        STUB.setKeyValue_forObject_key_value_(2, o, 'key5', 'V')
+        STUB.setKeyValue_forObject_key_value_(DO_TAKESTOREDVALUE_FORKEY, o, 'key5', 'V')
         self.assertEquals(o.key5, "VVVVV")
 
         self.assert_(not hasattr(o, 'key9'))
-        STUB.setKeyValue_forObject_key_value_(2, o, 'key9', 'IX')
+        STUB.setKeyValue_forObject_key_value_(DO_TAKESTOREDVALUE_FORKEY, o, 'key9', 'IX')
         self.assert_(hasattr(o, 'key9'))
         self.assertEquals(o.key9, 'IX')
 
         o = KeyValueClass3()
 
         self.assertEquals(o.foo, "foobar")
-        STUB.setKeyValue_forObject_key_value_(2, o, 'foo', 'FOO')
+        STUB.setKeyValue_forObject_key_value_(DO_TAKESTOREDVALUE_FORKEY, o, 'foo', 'FOO')
         self.assertEquals(o.foo, "FOO")
 
-        self.assertRaises(KeyError, STUB.setKeyValue_forObject_key_value_, 2, o, 'key9', 'IX')
-        self.assertRaises(KeyError, STUB.setKeyValue_forObject_key_value_, 2, o, 'roprop', 'IX')
+        self.assertRaises(KeyError, STUB.setKeyValue_forObject_key_value_, DO_TAKESTOREDVALUE_FORKEY, o, 'key9', 'IX')
+        self.assertRaises(KeyError, STUB.setKeyValue_forObject_key_value_, DO_TAKESTOREDVALUE_FORKEY, o, 'roprop', 'IX')
 
     def testTakeValuesFromDictionary(self):
         o = KeyValueClass2()
         o.key5 = 1
         self.assert_(not hasattr(o, 'key9'))
 
-        STUB.setKeyValue_forObject_key_value_(3, o, None,
+        STUB.setKeyValue_forObject_key_value_(DO_TAKEVALUESFROMDICT, o, None,
             {
                 'key3': 'drie',
                 'key4': 'vier',
         o = KeyValueClass3()
 
         self.assertEquals(o.foo, "foobar")
-        STUB.setKeyValue_forObject_key_value_(3, o, None, { 'foo': 'FOO' })
+        STUB.setKeyValue_forObject_key_value_(DO_TAKEVALUESFROMDICT, o, None, { 'foo': 'FOO' })
         self.assertEquals(o.foo, "FOO")
 
-        self.assertRaises(KeyError, STUB.setKeyValue_forObject_key_value_, 3, o, None, { 'key9':  'IX' })
-        self.assertRaises(KeyError, STUB.setKeyValue_forObject_key_value_, 3, o, None, { 'roprop':  'IX' })
+        self.assertRaises(KeyError, STUB.setKeyValue_forObject_key_value_, DO_TAKEVALUESFROMDICT, o, None, { 'key9':  'IX' })
+        self.assertRaises(KeyError, STUB.setKeyValue_forObject_key_value_, DO_TAKEVALUESFROMDICT, o, None, { 'roprop':  'IX' })
 
     def testTakeValueForKeyPath(self):
         o = KeyValueClass2()
         self.assertEquals(o.multiple.level2.level3.keyA, "hello")
         self.assertEquals(o.multiple.level2.level3.keyB, "world")
 
-        STUB.setKeyValue_forObject_key_value_(1, o, "multiple.level2.level3.keyA", "KeyAValue")
+        STUB.setKeyValue_forObject_key_value_(DO_TAKEVALUE_FORKEYPATH, o, "multiple.level2.level3.keyA", "KeyAValue")
         self.assertEquals(o.multiple.level2.level3.keyA, "KeyAValue")
 
-        STUB.setKeyValue_forObject_key_value_(1, o, "multiple.level2.level3.keyB", 9.999)
+        STUB.setKeyValue_forObject_key_value_(DO_TAKEVALUE_FORKEYPATH, o, "multiple.level2.level3.keyB", 9.999)
         self.assertEquals(o.multiple.level2.level3.keyB, 9.999)
 
+
+class TestAccMethod (unittest.TestCase):
+    def testStrCap(self):
+        class Foo:
+            def callme(self):
+                return "FOO"
+
+        # check the result for valueForKey:"callme" on a Foo instance 
+        self.assertEquals(STUB.keyValue_forObject_key_(DO_VALUEFORKEY, Foo(), "callme"), "FOO")
+
+    def testStr(self):
+        # Strings are automaticly converted to NSStrings, and those don't have
+        # a capitalize key.
+        self.assertRaises(KeyError, STUB.keyValue_forObject_key_, DO_VALUEFORKEY,
+            "hello", "capitalize")
+        self.assertRaises(KeyError, STUB.keyValue_forObject_key_, DO_VALUEFORKEY,
+            u"hello", "capitalize")
+
+
+class AbstractKVCodingTest:
+    def testBaseValueForKey(self):
+        self.assertEquals(DirectString, 
+            STUB.keyValue_forObject_key_(DO_VALUEFORKEY, self.base, "directString"))
+        self.assertEquals(IndirectString, 
+            STUB.keyValue_forObject_key_(DO_VALUEFORKEY, self.base, "indirectString"))
+        self.assertEquals(DirectNumber, 
+            STUB.keyValue_forObject_key_(DO_VALUEFORKEY, self.base, "directNumber"))
+        self.assertEquals(IndirectNumber, 
+            STUB.keyValue_forObject_key_(DO_VALUEFORKEY, self.base, "indirectNumber"))
+               
+    def testPathValueForKey(self):
+        self.assertEquals(DirectString, 
+            STUB.keyValue_forObject_key_(DO_VALUEFORKEYPATH, self.path, "directHead.directString"))
+        self.assertEquals(DirectString, 
+            STUB.keyValue_forObject_key_(DO_VALUEFORKEYPATH, self.path, "indirectHead.directString"))
+        self.assertEquals(IndirectString, 
+            STUB.keyValue_forObject_key_(DO_VALUEFORKEYPATH, self.path, "directHead.indirectString"))
+        self.assertEquals(IndirectString, 
+            STUB.keyValue_forObject_key_(DO_VALUEFORKEYPATH, self.path, "indirectHead.indirectString"))
+        self.assertEquals(DirectNumber, 
+            STUB.keyValue_forObject_key_(DO_VALUEFORKEYPATH, self.path, "directHead.directNumber"))
+        self.assertEquals(DirectNumber, 
+            STUB.keyValue_forObject_key_(DO_VALUEFORKEYPATH, self.path, "indirectHead.directNumber"))
+        self.assertEquals(IndirectNumber, 
+            STUB.keyValue_forObject_key_(DO_VALUEFORKEYPATH, self.path, "directHead.indirectNumber"))
+        self.assertEquals(IndirectNumber, 
+            STUB.keyValue_forObject_key_(DO_VALUEFORKEYPATH, self.path, "indirectHead.indirectNumber"))
+
+class TestObjCKVCoding(AbstractKVCodingTest, unittest.TestCase):
+    def setUp(self):
+        self.base = PyObjCTest_KVBaseClass.new()
+        self.path = PyObjCTest_KVPathClass.new()
+
+class TestPythonKVCoding(AbstractKVCodingTest, unittest.TestCase):
+    def setUp(self):
+        self.base = KVPyBase()
+        self.path = KVPyPath()
+
+class TestPythonSubObjCContainerCoding(AbstractKVCodingTest, unittest.TestCase):
+    def setUp(self):
+        self.base = KVPySubObjCBase.new()
+        self.path = KVPySubObjCPath.new()
+
+class TestPythonSubOverObjC(AbstractKVCodingTest, unittest.TestCase):
+    def setUp(self):
+        self.base = KVPySubOverObjCBase.new()
+        self.path = KVPySubOverObjCPath.new()
+
+    def testOverValueKey(self):
+        self.assertEquals(DirectString, 
+            STUB.keyValue_forObject_key_(DO_VALUEFORKEY, self.base, "overDirectString"))
+        self.assertEquals(IndirectString, 
+            STUB.keyValue_forObject_key_(DO_VALUEFORKEY, self.base, "overIndirectString"))
+
+    def testOverValueKeyPath(self):
+        self.assertEquals(DirectString, 
+            STUB.keyValue_forObject_key_(DO_VALUEFORKEYPATH, self.path, "overDirectHead.directString"))
+        self.assertEquals(DirectString, 
+            STUB.keyValue_forObject_key_(DO_VALUEFORKEYPATH, self.path, "overIndirectHead.directString"))
+        self.assertEquals(IndirectString, 
+            STUB.keyValue_forObject_key_(DO_VALUEFORKEYPATH, self.path, "overDirectHead.indirectString"))
+        self.assertEquals(IndirectString, 
+            STUB.keyValue_forObject_key_(DO_VALUEFORKEYPATH, self.path, "overIndirectHead.indirectString"))
+
+
 if __name__ == "__main__":
     unittest.main()

pyobjc/Lib/objc/test/testbndl.m

 @end
 
 
+@interface PyObjCTest_KVBaseClass : NSObject
+{
+    NSString *directString;
+    NSNumber *directNumber;
+    NSString *indirectString;
+    NSNumber *indirectNumber;
+}
+@end
+
+@implementation PyObjCTest_KVBaseClass
+- init
+{
+    self = [super init];
+    if (!self) return nil;
+
+    directString = [@"Direct String" retain];
+    directNumber = [[NSNumber numberWithInt: 42] retain];
+    indirectString = [@"Indirect String" retain];
+    indirectNumber = [[NSNumber numberWithInt: 84] retain];
+
+    return self;
+}
+
+- (NSString *) indirectString; { return indirectString; }
+- (void) setIndirectString: (NSString *) aString;
+{
+    [aString retain];
+    [indirectString release];
+    indirectString = aString;
+}
+
+- (NSNumber *) indirectNumber; { return indirectNumber; }
+- (void) setIndirectNumber: (NSNumber *) aNumber;
+{
+    [aNumber retain];
+    [indirectNumber release];
+    indirectNumber = aNumber;
+}
+@end
+
+@interface PyObjCTest_KVPathClass : NSObject
+{
+    PyObjCTest_KVBaseClass *directHead;
+    PyObjCTest_KVBaseClass *indirectHead;
+}
+@end
+
+@implementation PyObjCTest_KVPathClass
+- init
+{
+    self = [super init];
+    if (!self) return nil;
+
+    directHead = [[PyObjCTest_KVBaseClass alloc] init];
+    indirectHead = [[PyObjCTest_KVBaseClass alloc] init];
+
+    return self;
+}
+
+- (PyObjCTest_KVBaseClass *) indirectHead { return indirectHead; } 
+- (void) setInidrectHead: (PyObjCTest_KVBaseClass *) aHead;
+{
+    [aHead retain];
+    [indirectHead release];
+    indirectHead = aHead;
+}
+@end
+
 
 static PyMethodDef no_methods[] = {
 	{ 0, 0, 0, 0 }
 		PyObjCClass_New([OC_TestClass2 class]));
 	PyModule_AddObject(m, "PyObjC_TestClass3", 
 		PyObjCClass_New([PyObjC_TestClass3 class]));
-	
-	
+	PyModule_AddObject(m, "PyObjCTest_KVBaseClass", 
+		PyObjCClass_New([PyObjCTest_KVBaseClass class]));
+	PyModule_AddObject(m, "PyObjCTest_KVPathClass", 
+		PyObjCClass_New([PyObjCTest_KVPathClass class]));
+
+	PyModule_AddObject(m, "DO_VALUEFORKEY", PyInt_FromLong(0));
+	PyModule_AddObject(m, "DO_VALUEFORKEYPATH", PyInt_FromLong(1));
+	PyModule_AddObject(m, "DO_STOREDVALUEFORKEY", PyInt_FromLong(2));
+	PyModule_AddObject(m, "DO_VALUESFORKEYS", PyInt_FromLong(3));
+
+	PyModule_AddObject(m, "DO_TAKEVALUE_FORKEY", PyInt_FromLong(0));
+	PyModule_AddObject(m, "DO_TAKEVALUE_FORKEYPATH", PyInt_FromLong(1));
+	PyModule_AddObject(m, "DO_TAKESTOREDVALUE_FORKEY", PyInt_FromLong(2));
+	PyModule_AddObject(m, "DO_TAKEVALUESFROMDICT", PyInt_FromLong(3));
 }

pyobjc/Modules/objc/OC_PythonDictionary.m

 		}
 
 		if (result == nil) {
-			NSLog(@"OC_PythonDictionaryEnumerator: Python dict with None as key");
+			NSLog(@"OC_PythonDictionaryEnumerator: Python dict with None as key, skipping this key");
+			continue;
 		}
 
 	} while (result == nil);

pyobjc/Modules/objc/OC_PythonObject.m

 	if (!pymethod) {
 		PyErr_Clear();
 		[NSException raise:NSInvalidArgumentException 
-			format:@"No such selector: %s", SELNAME(sel)];
+			format:@"%s: no such selector: %s", GETISA(self)->name, SELNAME(sel)];
 	}
 
 
 
 
 
-/* First try the accessor functions 'getKey' and 'get_key', then
- * the attribute 'key' and finally instance variable '_key' (the last one
- * only if we're allowed to access instance variables directly).
+/*
+ *  Call PyObjCTools.KeyValueCoding.getKey to get the value for a key
  */
 - valueForKey:(NSString*) key;
 {
-	NSString* tmpName;
+static  PyObject* getKeyFunc = NULL;
+
+	PyObject* keyName;
 	PyObject* val;
 	id res;
-	
 
-	tmpName = [NSString stringWithFormat:@"get%@", [key capitalizedString]];
-	val = PyObject_CallMethod(pyObject, (char*)[tmpName cString], NULL);
-	if (val == NULL) {
-		PyErr_Clear();
-	} else {
-		if ( depythonify_c_value(@encode(id), val, &res) < 0) {
-			Py_DECREF(val);
+	if (getKeyFunc == NULL) {
+		PyObject* name;
+		PyObject* mod;
+		name = PyString_FromString( "PyObjCTools.KeyValueCoding");
+		if (name == NULL) {
 			PyObjCErr_ToObjC();
 			return nil;
-		} 
-		Py_DECREF(val);
-		return res;
+		}
+		mod = PyImport_Import(name);
+		if (mod == NULL) {
+			Py_DECREF(name);
+			PyObjCErr_ToObjC();
+			return nil;
+		}
+		getKeyFunc = PyObject_GetAttrString(mod, "getKey");
+		if (getKeyFunc == NULL) {
+			Py_DECREF(name);
+			Py_DECREF(mod);
+			PyObjCErr_ToObjC();
+			return nil;
+		}
+		Py_DECREF(name);
+		Py_DECREF(mod);
 	}
 
-	tmpName = [NSString stringWithFormat:@"get_%@", key];
-	val = PyObject_CallMethod(pyObject, (char*)[tmpName cString], NULL);
-	if (val == NULL) {
-		PyErr_Clear();
-	} else {
-		if ( depythonify_c_value(@encode(id), val, &res) < 0) {
-			Py_DECREF(val);
-			PyObjCErr_ToObjC();
-			return nil;
-		} 
-		Py_DECREF(val);
-		return res;
+	keyName = pythonify_c_value(@encode(id), &key);
+	if (keyName == NULL) {
+		PyObjCErr_ToObjC();
+		return nil;
 	}
 
-	val = PyObject_GetAttrString(pyObject, (char*)[key cString]);
+	val = PyObject_CallFunction(getKeyFunc, "OO", pyObject, keyName);
+	Py_DECREF(keyName);
 	if (val == NULL) {
-		PyErr_Clear();
-	} else {
-		if ( depythonify_c_value(@encode(id), val, &res) < 0) {
-			Py_DECREF(val);
-			PyObjCErr_ToObjC();
-			return nil;
-		} 
-		Py_DECREF(val);
-		return res;
+		PyObjCErr_ToObjC();
+		return nil;
 	}
 
-	if ([[self class] accessInstanceVariablesDirectly]) {
-		tmpName = [NSString stringWithFormat:@"_%@", key];
-		val = PyObject_GetAttrString(pyObject, (char*)[tmpName cString]);
-		if (val == NULL) {
-			PyErr_Clear();
-		} else {
-			if ( depythonify_c_value(@encode(id), val, &res) < 0) {
-				Py_DECREF(val);
-				PyObjCErr_ToObjC();
-				return nil;
-			}
-			Py_DECREF(val);
-			return res;
-		}
+	if (depythonify_c_value(@encode(id), val, &res) < 0) {
+		Py_DECREF(val);
+		PyObjCErr_ToObjC();
+		return nil;
 	}
-
-	[self handleQueryWithUnboundKey:key];
-	return nil;
+	Py_DECREF(val);
+	return res;
 }
 
 - storedValueForKey: (NSString*) key;
 	return [self valueForKey: key];
 }
 
-/* First check if there is a setter method (setKey or set_key), otherwise
- * check if '_key' exists as an attribute and try to replace that, otherwise
- * try set 'key' as an attribute.
- * 
- * NOTE: We never call setValue:forUnboundKey:
- */
+
+/* Calls PyObjCTools.KeyValueCoding.setKey to set the key */
 - (void)takeValue: value forKey: (NSString*) key;
 {
-	PyObject* meth;
+static  PyObject* setKeyFunc = NULL;
+
+	PyObject* keyName;
+	PyObject* pyValue;
 	PyObject* val;
-	NSString* tmpName;
+	id res;
 
-	val = pythonify_c_value(@encode(id), &value);
+	if (setKeyFunc == NULL) {
+		PyObject* name;
+		PyObject* mod;
+		name = PyString_FromString( "PyObjCTools.KeyValueCoding");
+		if (name == NULL) {
+			PyObjCErr_ToObjC();
+			return;
+		}
+		mod = PyImport_Import(name);
+		if (mod == NULL) {
+			Py_DECREF(name);
+			PyObjCErr_ToObjC();
+			return;
+		}
+		setKeyFunc = PyObject_GetAttrString(mod, "setKey");
+		if (setKeyFunc == NULL) {
+			Py_DECREF(name);
+			Py_DECREF(mod);
+			PyObjCErr_ToObjC();
+			return;
+		}
+		Py_DECREF(name);
+		Py_DECREF(mod);
+	}
+
+	keyName = pythonify_c_value(@encode(id), &key);
+	if (keyName == NULL) {
+		PyObjCErr_ToObjC();
+		return;
+	}
+
+	pyValue = pythonify_c_value(@encode(id), &value);
+	if (pyValue == NULL) {
+		Py_DECREF(keyName);
+		PyObjCErr_ToObjC();
+		return;
+	}
+
+	val = PyObject_CallFunction(setKeyFunc, "OOO", pyObject, keyName, pyValue);
+	Py_DECREF(keyName);
+	Py_DECREF(pyValue);
 	if (val == NULL) {
 		PyObjCErr_ToObjC();
 		return;
 	}
 
-	tmpName = [NSString stringWithFormat:@"set%@", [key capitalizedString]];
-	meth = PyObject_GetAttrString(pyObject, (char*)[tmpName cString]);
-	if (meth == NULL) {
-		PyErr_Clear();
-	} else if (PyFunction_Check(meth) || PyMethod_Check(meth) || PyObjCSelector_Check(meth)) {
-		PyObject* o = PyObject_CallFunction(meth, "O", val);
-		if (o == NULL) {
-			Py_DECREF(meth);
-			Py_DECREF(val);
-			PyObjCErr_ToObjC();
-			return;
-		}
-		Py_DECREF(o);
-		Py_DECREF(meth);
-		return;
-	} else {
-		Py_DECREF(meth);
-	}
-
-	tmpName = [NSString stringWithFormat:@"set_%@", key];
-	meth = PyObject_GetAttrString(pyObject, (char*)[tmpName cString]);
-	if (meth == NULL) {
-		PyErr_Clear();
-	} else if (PyMethod_Check(meth) || PyObjCSelector_Check(meth)) {
-		PyObject* o = PyObject_CallFunction(meth, "O", val);
-		if (o == NULL) {
-			Py_DECREF(meth);
-			Py_DECREF(val);
-			PyObjCErr_ToObjC();
-			return;
-		}
-		Py_DECREF(o);
-		Py_DECREF(meth);
-		return;
-	} else {
-		Py_DECREF(meth);
-	}
-
-	tmpName = [NSString stringWithFormat:@"_%@", key];
-	if (PyObject_HasAttrString(pyObject, (char*)[tmpName cString])) {
-		if (PyObject_SetAttrString(pyObject, 
-				(char*)[tmpName cString], val) < 0) {
-			Py_DECREF(val);
-			PyObjCErr_ToObjC();
-			return;
-		}
-		Py_DECREF(val);
-		return;
-	}
-
-	if (PyObject_SetAttrString(pyObject, (char*)[key cString], val) < 0) {
-		Py_DECREF(val);
-		if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
-			/* Unbound key */
-			PyErr_Clear();
-			[self handleTakeValue: value forUnboundKey: key];
-		}
-		PyObjCErr_ToObjC();
-		return;
-	}
 	Py_DECREF(val);
 }
 

pyobjc/Modules/objc/class-builder.m

  * one from 'self'.
  *
  * The 'right' way to do this is by building closures (if done correctly it
- * would at least be faster), but that requires an external library or low-level
- * (assembly) trickery.
+ * would at least be faster) using libffi.
  */
 static Class find_real_superclass(Class startAt, SEL selector, 
 		METHOD (*find_method)(Class, SEL), IMP currentImp)
 
 /*
  * Be smart about slots: Push them into Objective-C and leave an empty
- * __slots__ attribute.
+ * __slots__ attribute, that way we don't store object-state in the python
+ * proxy.
  */
 static int 
 do_slots(PyObject* super_class, PyObject* clsdict)
  *   might override methods. Need to check the MRO documentation to check
  *   if this is a problem. 
  * - It is a problem when the user tries to use mixins to define common
- *   methods (like a NSTableViewDataSource mixin).
+ *   methods (like a NSTableViewDataSource mixin), this works but slowly
+ *   because this calls will always be resolved through forwardInvocation:
+ * - Add an 'override' flag that makes it possible to replace an existing
+ *   PyObjC class, feature request for the Python-IDE  (write class, run,
+ *   oops this doesn't work, rewrite class, reload and continue testing in
+ *   the running app)
  */
 Class PyObjCClass_BuildClass(Class super_class,  PyObject* protocols,
 				char* name, PyObject* class_dict)
 
 	if (!PyList_Check(protocols)) {
 		ObjCErr_Set(ObjCExc_internal_error, "%s", 
-			"protocol list not a PyList");
+			"protocol list not a python 'list'");
 		goto error_cleanup;
 	}
 	if (!PyDict_Check(class_dict)) {
 		ObjCErr_Set(ObjCExc_internal_error, "%s", 
-			"class dict not a PyDict");
+			"class dict not a python 'dict'");
 		goto error_cleanup;
 	}
 	if (super_class == NULL) {
 	}
 
 	if (objc_lookUpClass(name) != NULL) {
-		ObjCErr_Set(ObjCExc_error, "class '%s' exists", name);
+		ObjCErr_Set(ObjCExc_error, "class already '%s' exists", name);
 		goto error_cleanup;
 	}
 	if (strspn(name, IDENT_CHARS) != strlen(name)) {
 		if (PyErr_Occurred()) {
 			PyErr_Clear();
 			ObjCErr_Set(ObjCExc_internal_error,
+				"PyObjCClass_BuildClass: "
 				"Cannot fetch key in keylist");
 			goto error_cleanup;
 		}
 		if (value == NULL) {
 			PyErr_Clear();
 			ObjCErr_Set(ObjCExc_internal_error,
+				"PyObjCClass_BuildClass: "
 				"Cannot fetch item in keylist");
 			goto error_cleanup;
 		}
 			if (class_getInstanceVariable(super_class, 
 			    ((PyObjCInstanceVariable*)value)->name) != NULL) {
 				ObjCErr_Set(ObjCExc_error,
-					"Cannot replace instance variable %s",
+					"a superclass already has an instance "
+					"variable with this name: %s",
 					((PyObjCInstanceVariable*)value)->name);
 				goto error_cleanup;
 			}
 		key = PyList_GetItem(key_list, i);
 		if (key == NULL) {
 			ObjCErr_Set(ObjCExc_internal_error,
+				"PyObjCClass_BuildClass: "
 				"Cannot fetch key in keylist");
 			goto error_cleanup;
 		}
 		value = PyDict_GetItem(class_dict, key);
 		if (value == NULL)  {
 			ObjCErr_Set(ObjCExc_internal_error,
+				"PyObjCClass_BuildClass: "
 				"Cannot fetch item in keylist");
 			goto error_cleanup;
 		}
 		return result;
 	}
 
+	r = getAccessor(self, [NSString stringWithFormat: @"%@", key], 
+		&result);
+	if (r == 0) {
+		return result;
+	}
+
+	r = getAccessor(self, [NSString stringWithFormat: @"_%@", key], 
+		&result);
+	if (r == 0) {
+		return result;
+	}
+
 	r = getAttribute(self, [NSString stringWithFormat: @"_%@", key], 
 		&result);
 	if (r == 0) {
 		class_getInstanceMethod,
 		(IMP)object_method_valueForKey_);
 	super.receiver = self;
-	return objc_msgSendSuper(&super, _meth, key);
+	result = objc_msgSendSuper(&super, _meth, key);
+	return result;
 }
 
 static void

pyobjc/Modules/objc/selector.m

 		return NULL;
 	}
 
-	sublist = PyDict_GetItemString(replacement_signatures, (char*)SELNAME(selector));
+	sublist = PyDict_GetItemString(replacement_signatures, 
+				(char*)SELNAME(selector));
 	if (sublist == NULL) return NULL;
 
 	len = PyList_Size(sublist);
 		argslen = PyTuple_Size(args);
 		if (argslen < 1) {
 			ObjCErr_Set(PyExc_TypeError,
-				"Missing self argument\n");
+				"Missing argument: self");
 			return NULL;
 		}
 		pyself = PyTuple_GetItem(args, 0);
 	    && !(self->sel_flags & PyObjCSelector_kINITIALIZER)) {
 
 		PySys_WriteStderr(
-			"Calling non-initializer (%s) on unitialized object %p of class %s\n",
+			"Calling method (%s) on unitialized object %p of class %s\n",
 			SELNAME(self->sel_selector),
 			(void*)PyObjCObject_GetObject(self->sel_self),
 			GETISA(PyObjCObject_GetObject(self->sel_self))->name);
 		if (strcmp(cls->name, "NSProxy") == 0) {
 			if (sel == @selector(methodSignatureForSelector:)) {
 				ObjCErr_Set(PyExc_AttributeError,
-					"Cannot access NSProxy.%s", name);
+					"Accessing NSProxy.%s is not supported",
+					name);
 				return NULL;
 			}
 		}
 		}
 	} else {
 		ObjCErr_Set(PyExc_RuntimeError,
-			"PyObjCSelector_FindNative called on bad object");
+			"PyObjCSelector_FindNative called on plain "
+			"python object");
 		return NULL;
 	}
 }
 	     ((PyObjCObject*)self->sel_self)->flags & PyObjCObject_kUNINITIALIZED) {
 
 		PySys_WriteStderr(
-		    "Calling non-initializer (%s) on unitialized object %p of class %s\n",
+		    "Calling method (%s) on unitialized object %p of class %s\n",
 		    SELNAME(self->sel_selector),
 		    (void*)PyObjCObject_GetObject(self->sel_self),
 		    GETISA(PyObjCObject_GetObject(self->sel_self))->name);
 		func_code = (PyCodeObject*)PyFunction_GetCode(PyMethod_Function(callable));
 	} else {
 		PyErr_SetString(PyExc_TypeError,
-			"Cannot calculate signature");
+			"Cannot calculate default method signature");
 		return NULL;
 	}
 

pyobjc/Modules/objc/super-call.m

 	PyObject*        pyclass;
 	PyObject* 	 entry;
 
-	//NSLog(@"Register mapping for %s in %s", SELNAME(sel), class->name);
-
 	if (signature_registry == NULL) {
 		if (init_registry() < 0) return -1;
 	}
 
 	if (special_registry == NULL) {
 		ObjCErr_Set(ObjCExc_error,
-			"No super-caller for %s\n", SELNAME(sel));
+			"PyObjC: don't know how to call method %s", 
+			SELNAME(sel));
 		return NULL;
 	}
 
 		return PyCObject_AsVoidPtr(result);
 	} else {
 		ObjCErr_Set(ObjCExc_error,
-			"No super-caller for %s\n", SELNAME(sel));
+			"PyObjC: don't know how to call method %s", 
+			SELNAME(sel));
 		return NULL;
 	}
 }
 
 	if (signature_registry == NULL) {
 		ObjCErr_Set(ObjCExc_error,
-			"[1]No forwarder for signature %s\n", signature);
+			"PyObjC: don't know how to call a method with "
+			"signature %s", signature);
 		return NULL;
 	}
 
 	o = PyDict_GetItemString(signature_registry, signature_buf);
 	if (o == NULL) {
 		ObjCErr_Set(ObjCExc_error,
-			"[2]No forwarder for signature %s\n", signature);
+			"PyObjC: don't know how to call a method with "
+			"signature %s", signature);
 		return NULL;
 	}
 
 <body>
 <h2>PyObjC NEWS</h2>
 <p>An overview of the relevant changes in new, and older, releases.</p>
-<h2><a name="version-1-0b1-cvs">Version 1.0b1+ (CVS)</a></h2>
+<h2><a name="version-1-0rc1-2003-08-10">Version 1.0rc1 (2003-08-10)</a></h2>
 <ul>
 <li>Better support for the NSKeyValueCoding protocol.  The module 
 <code><span>PyObjCTools.KeyValueCoding</span></code> provides a python interface that makes it
               ["Lib/objc/test/testbndl2.m"],
               extra_compile_args=["-IModules/objc" ] + CFLAGS,
               extra_link_args=OBJC_LDFLAGS),
-    Extension("PyObjCTools.test.testkvcodingbndl",
-              ["Lib/PyObjCTools/test/testkvcodingbndl.m"],
-              extra_compile_args=["-IModules/objc" ] + CFLAGS,
-              extra_link_args=OBJC_LDFLAGS),
     Extension("autoGIL", 
               ["Modules/autoGIL.c"],
               extra_compile_args = CFLAGS,