Commits

Ronald Oussoren committed 86504dc

- Move creation of CIFs and closures to seperate functions (libffi_support.m)
- Use those functions to remove the need for find_real_superclass in
class-builder.m
- Make sure users cannot delete selectors from classes, we cannot remove them
from the Objective-C runtime either.
- the IMPs for python-based methods in class-builder.m should contain a
hard binding to the python callable (needed for Key-Value Observing).
- Update the wrappers for Foundation and AppKit to use the new method of
overriding IMP's.
- Update error-handling in those wrappers.
- Started adding headerdoc markup to the header-files to improve the
source-code documentation.
See http://developer.apple.com/darwin/projects/headerdoc/ for more
information.
- Fix error-handling bug in objc_util.m
- Move ObjC_*ConvenienceMethods to objc-class.m, where the belong. The
primary reason for doing it is that update_convenience_methods breaks the
encapsulation of the class (it directly calls super.__setattr__).
- The __setattr__ of Objective-C classes no longer allows removal of
methods, and implicitly calls objc.classAddMethods when assigning a (new)
method to the class.
- Add script that generates the headerdoc documentation in the Doc tree.
- Added some unittests for most of the custom IMP-s for NSCoder
- Added some unittests for most of the custom IMP-s for NSData
- Add a custom build_ext class to setup.py, this way we don't start building
libffi and the static-wrappers when someone runs 'python setup.py --help'
(added after mis-typing build one time too many)
- bin-python-main.m in the project templates and examples now compiles with
gcc2. [bug #857048], the rest of PyObjC might not :-)
- Python keywords can be used as Objective-C methods names. To access or define
such a method append two underscores to its name [bug #836336].
- Selectors now check the type of 'self' (for calls to unbound selectors),
this solves the crash mentioned in bug #836247.
- Add some support for NSDecimal, including the methods of NSDecimalNumber that
deal with NSDecimal's. The NSDecimal type does not support mathematical
operators. By design, it does not do implicit conversion to/from Python
numbers, explict conversion is supported.
- Add wrappers for NSRectClipList, NSWindowList, NSWindowListForContext,
NSBestDepth, NSDrawTiledRects and NSDrawColorTiledRects.
NSDrawBitmap is now the only method in AppKit that we don't wrap (according
to the generator scripts.
Foundation contains more unwrapped functions, but most of those are
not very usefull in Python.
- Added a generic mechanism to create wrapper types for C structs, and used
that to create wrappers for NSRect, NSSize, NSPoint, NSRange and
NSAffineTransformStruct.
The types are mutable sequences of a fixed length and also allow access using
fieldnames. The mechanism is inspired by, but not based on, a simular
mechanism in core python (our system is much simpler, both interface and
implementation and is R/W).
Example: o = Foundation.NSRect(); o.size.width = 4

Comments (0)

Files changed (84)

 Multi-threading support
 .......................
 
-The code should be mostly thread-safe, but this should be checked. Furthermore
-we should add code that enables using python in multiple threads:
-
-* Give up the global interpreter lock (GIL) before calling into Objective-C
-
-* Make sure the current thread-state is stored in thread-local storage (TLS)
-  before calling into Objective-C 
-
-* Fetch the thread-state from a TLS during callbacks from Objective-C and
-  create one if it doesn't exist yet. The latter assumes 1 python interpreter
-  per process.
-
-* Acquire the GIL during callbacks from Objective-C (this includes python
-  methods called from Objective-C)
-
-* A number of functions use static buffers, all in pyobjc_support.m and
-  related to depythonify_c_value. Fixing this is relatively straightforward:
-  raise a python exception if the conversion fails, instead of returning an
-  error-string.
-
-This version has limited multithreading safety: it is possible to call from
-Objective-C to python from arbitrary threads. This only works when using 
-Python 2.3, because this uses the interfaces defined in PEP 311. This is only
-meant to make it safer to embed a PyObjC in existing applications, and not
-a solution for finegrained threading.
+Thanks to the autoGIL module the GIL is given up when the main runloop
+sleeps. We could give up the GIL before calling into Objective-C, but that
+requires a lot of work for minimal advantages.
 
 Test suite
 ..........
 
 The test suite needs to be enhanced.
 
+* Tests that exercise Key-Value Observing in a way that crashes older versions
+  of PyObjC.
+
 * tests for all functions in ``Modules/*/*Mapping*.m``
+  (inclusing IMPs)
 
 * tests for all non-generated function wrappers (and some for the generated
   functions as well, just in case the generator script is buggy)
 
 * Likewise for class-builder.m, this file is way to large.
 
-* Use libffi to do away with class-builder.m:find_real_superclass. And check
-  if we can use libffi to simplify code.
-
 Support for GNUstep
 ...................
 
 Design and implement a set of performance tests for the bridge. Use this to 
 investigate and fix any possible performance problems.
 
-Robustness
-..........
-
-Make core bridge more robust w.r.t. order of loading frameworks. You currently
-get incorrect wrappers if you manually load the AppKit.framework and then 
-import AppKit. I (Ronald) know how to do this, but this can wait until after 
-1.0.
-
 Add freelists
 .............
 
 Key-Value Encoding
 ..................
 
+XXX: Need to check if the current implementation is correct.
+
 The takeValue:forKey: implementation correctly emits notifications (on MacOS X
 10.3). MacOS X 10.3 is currently detected at compile-time, this should probably
 be done dynamicly.
 But: we should also provide links to locally installed documetation, especially
 in the documentation that will be installed on the users machine.
 
-Efficient conversion of arrays of C-types
-.........................................
-
-Make it possible to represent arrays for NSPoints/NSRects/... as (numeric) 
-arrays. This should be implemented as a genericly as possible, a possible
-interface in pyobjc-api.h::
-
-	void*	PyObjC_PythonArrayToObjC(
-			char* typestr, PyObject* array, PyObject* count);
-
-	PyObject* PyObjC_ObjCArrayToPython(
-		char* typestr, void* array, int count);
-
-If the ``count`` argument for PythonArrayToObjC is NULL or Py_None, all objects
-in the array are converted. This should accept:
-
-1) a python sequence (list, array, iterator, ...) containing Python objects
-   representing the elements of the array (e.g. [ (1,2), (3,4), (4,5) ] as a 
-   list of 3 points).
-2) an array.array of suitable dimensions/types
-3) a numeric array of suitable dimensions/types
-
-Items 2 and 3 must be checked for correctness (e.g. don't blindly convert a
-array.array containing bytes to an array of NSPoints).
-
 Installer support for OSX 10.3
 ..............................
 
+XXX: I have an osxpkg module, but that is completely untested.
+
 There should be at least two installers: one for Jaguar and one for Panther,
 they should share as much source-code as possible.
 

pyobjc/Doc/api-notes-macosx.txt

 AppKit framework
 ----------------
 
-``NSPoint`` is a tuple of 2 floats, or use ``AppKit.NSMakePoint(x, y)``.
-
-``NSSize`` is a tuple of 2 floats, or use ``AppKit.NSMakeSize(h, w)``.
-
-``NSRect`` is a tuple of an ``NSPoint`` and an ``NSSize``, or 
-use ``AppKit.NSMakeRect(x, y, h, w)``.
-
 The callback methods for the NSSheet API's have a non-default signature
 and no fixed name. You should therefore explicitly specify the signature. This
 is done by calling the ``endSheetMethod`` function after defining your
 using the python function ``apply``. The ``performv::`` method is also not
 supported, with a simular work-around.
 
+Structs are wrapped using a struct-like type. They can be accessed using the
+field-names from Objective-C, or you can access them as sequences. Accessing
+them as sequences is necessary for backward compatibility and is depericated.
+
 Class ``NSArray``
 .................
 
   Use ``bytes`` instead, and then use subscripting to get the
   desired range.
 
+Class ``NSDecimalNumber`` and the ``NSDecimal`` type
+....................................................
+
+NSDecimal is wrapped by a Python type. This type does not (yet) support
+mathematical operators, but does support explicit conversion to and from
+Python numbers. 
+
+Creating an ``NSDecimal`` instance: ``NSDecimal(value)`` or 
+``NSDecimal(mantisssa, exponent, isNegative)``.  ``Value`` can be a string,
+int or long (not a float because of the representation issues for floats).
+
+Converting an ``NSDecimal`` to a float or int: ``aDecimal.as_int()`` and
+``aDecimal.as_float``.
 
 Class ``NSDictionary``
 ......................

pyobjc/Doc/intro.txt

 
 * Then convert all colons to underscores: ``someMethod_withFoo_andBar_``
 
+It is possible to use Python keywords as method names in Objective-C. To access
+or define such methods append two underscores to its name (e.g. ``class__``). 
+This is currently only supported for ``raise`` and ``class`` because those are
+the only Python keywords that are actually used in Cocoa.
+
 Wrapped/bridged methods (and functions) have the same number of arguments
 as the corresponding Objective-C method or function, unless otherwise noted
 in the documentation (`Notes on supported APIs and classes on MacOS X`_ for

pyobjc/Examples/FieldGraph/bin-python-main.m

 //
 //  bin-python-main.m
-//  CurrencyConverter
+//  FieldGraph
 //
 //  Created by Dan Grassi on Mon Jun 16 2003.
-//  Copyright (c) 2003 __MyCompanyName__. All rights reserved.
 //
 
 /*
 
 int pyobjc_main(int argc, char * const *argv, char * const *envp)
 {
-    // The autorelease pool is not released on purpose.   The call to execve() destroys the
-    // calling process entirely and, as such, memory management in the traditional sense
-    // is not necessary (and not doing so avoids potential bugs associated with releasing
-    // the pool prior to the call to execve).
-    [[NSAutoreleasePool alloc] init];
-
-    const char **childArgv = alloca(sizeof(char *) * (argc + 5));
-    NSEnumerator *bundleEnumerator = [[NSBundle allFrameworks] reverseObjectEnumerator];
-    NSBundle *aBundle;
-    NSBundle *mainBundle = [NSBundle mainBundle];
-    NSMutableArray *bundlePaths = [NSMutableArray array];
+    // The autorelease pool is not released on purpose.   The call to execve() 
+    // destroys the calling process entirely and, as such, memory management 
+    // in the traditional sense is not necessary (and not doing so avoids 
+    // potential bugs associated with releasing the pool prior to the call to 
+    // execve).
+    const char** childArgv;
+    NSEnumerator* bundleEnumerator;
+    NSBundle* aBundle;
+    NSBundle* mainBundle;
+    NSMutableArray* bundlePaths;
     int i;
     int envc;
     char** childEnvp;
     char*  PYTHONPATH = NULL;
+    const char *pythonPathInWrapper;
+    NSString *pythonBinPath;
+    const char *pythonBinPathPtr; 
+    NSArray *possibleMains;
+    NSEnumerator * possibleMainsEnumerator;
+    NSString *mainPyPath;
+    NSString *nextFileName;
+    const char * mainPyPathPtr;
+
+    [[NSAutoreleasePool alloc] init];
+
+    childArgv = alloca(sizeof(char *) * (argc + 5));
+    bundleEnumerator = [[NSBundle allFrameworks] reverseObjectEnumerator];
+    mainBundle = [NSBundle mainBundle];
+    bundlePaths = [NSMutableArray array];
 
     // set up paths to be prepended to the PYTHONPATH
-    const char *pythonPathInWrapper = [[NSString stringWithFormat: @"%@:%@",
+    pythonPathInWrapper = [[NSString stringWithFormat: @"%@:%@",
         [[NSBundle mainBundle] resourcePath],
         [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent: @"PyObjC"]] UTF8String];
 
     childEnvp[envc++] = NULL;
 
     // figure out which python interpreter to use
-    NSString *pythonBinPath = [[NSUserDefaults standardUserDefaults] stringForKey: @"PythonBinPath"];
+    pythonBinPath = [[NSUserDefaults standardUserDefaults] stringForKey: @"PythonBinPath"];
     pythonBinPath = pythonBinPath ? pythonBinPath : @"/usr/bin/python";
 
-    const char *pythonBinPathPtr = [pythonBinPath UTF8String];
+    pythonBinPathPtr = [pythonBinPath UTF8String];
 
     // find main python file.  __main__.py seems to be a standard.
-    NSArray *possibleMains = [NSArray arrayWithObjects:
+    possibleMains = [NSArray arrayWithObjects:
         @"__main__.py",
         @"__main__.pyc",
         @"__main__.pyo",
         @"Main.pyc",
         @"Main.pyo",
         nil];
-    NSEnumerator *possibleMainsEnumerator = [possibleMains objectEnumerator];
-    NSString *mainPyPath;
-    NSString *nextFileName;
+    possibleMainsEnumerator = [possibleMains objectEnumerator];
 
     while (nextFileName = [possibleMainsEnumerator nextObject]) {
         mainPyPath = [mainBundle pathForResource: nextFileName ofType: nil];
     if ( !mainPyPath )
         [NSException raise: NSInternalInconsistencyException
                     format: @"%s:%d pyobjc_main() Failed to find one of %@ in app wrapper.  Exiting.", __FILE__, __LINE__, possibleMains];
-    const char *mainPyPathPtr = [mainPyPath UTF8String];
+    mainPyPathPtr = [mainPyPath UTF8String];
 
     // construct argv for the child
 

pyobjc/Examples/WebServicesTool/bin-python-main.m

 //
 //  bin-python-main.m
-//  Web Services Tool
-//
-//  Created by Bill Bumgarner on 10/10/2002.
-//  Copyright (c) 2002 The PyObjC Project. All rights reserved.
 //
 
 /*
  This main file uses execve() to transfer control of execution to the standard command line python interpreter.   As such, compiled classes in the project will not actually be linked into the runtime as execve() effectively overlays the existing process with the process being called -- in this case the python command line tool.
 
- To use compiled classes with this main, create a separate bundle target and load the bundle in the Main.py file.
+ To use compiled classes with this main, create a separate bundle target and load the bundle in the main python file.  The main python file should be in Resources and should be named "__main__.py", "__realmain__.py" or "Main.py".
 
  This style of execution works with the Apple provided version of Python.
  */
 
 int pyobjc_main(int argc, char * const *argv, char * const *envp)
 {
-    // The autorelease pool is not released on purpose.   The call to execve() destroys the
-    // calling process entirely and, as such, memory management in the traditional sense
-    // is not necessary (and not doing so avoids potential bugs associated with releasing
-    // the pool prior to the call to execve).
-    [[NSAutoreleasePool alloc] init];
-
-    const char **childArgv = alloca(sizeof(char *) * (argc + 5));
-    NSEnumerator *bundleEnumerator = [[NSBundle allFrameworks] reverseObjectEnumerator];
-    NSBundle *aBundle;
-    NSBundle *mainBundle = [NSBundle mainBundle];
-    NSMutableArray *bundlePaths = [NSMutableArray array];
+    // The autorelease pool is not released on purpose.   The call to execve() 
+    // destroys the calling process entirely and, as such, memory management 
+    // in the traditional sense is not necessary (and not doing so avoids 
+    // potential bugs associated with releasing the pool prior to the call to 
+    // execve).
+    const char** childArgv;
+    NSEnumerator* bundleEnumerator;
+    NSBundle* aBundle;
+    NSBundle* mainBundle;
+    NSMutableArray* bundlePaths;
     int i;
     int envc;
     char** childEnvp;
     char*  PYTHONPATH = NULL;
+    const char *pythonPathInWrapper;
+    NSString *pythonBinPath;
+    const char *pythonBinPathPtr; 
+    NSArray *possibleMains;
+    NSEnumerator * possibleMainsEnumerator;
+    NSString *mainPyPath;
+    NSString *nextFileName;
+    const char * mainPyPathPtr;
+
+    [[NSAutoreleasePool alloc] init];
+
+    childArgv = alloca(sizeof(char *) * (argc + 5));
+    bundleEnumerator = [[NSBundle allFrameworks] reverseObjectEnumerator];
+    mainBundle = [NSBundle mainBundle];
+    bundlePaths = [NSMutableArray array];
 
     // set up paths to be prepended to the PYTHONPATH
-    const char *pythonPathInWrapper = [[NSString stringWithFormat: @"%@:%@",
+    pythonPathInWrapper = [[NSString stringWithFormat: @"%@:%@",
         [[NSBundle mainBundle] resourcePath],
         [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent: @"PyObjC"]] UTF8String];
 
     childEnvp[envc++] = NULL;
 
     // figure out which python interpreter to use
-    NSString *pythonBinPath = [[NSUserDefaults standardUserDefaults] stringForKey: @"PythonBinPath"];
+    pythonBinPath = [[NSUserDefaults standardUserDefaults] stringForKey: @"PythonBinPath"];
     pythonBinPath = pythonBinPath ? pythonBinPath : @"/usr/bin/python";
 
-    const char *pythonBinPathPtr = [pythonBinPath UTF8String];
+    pythonBinPathPtr = [pythonBinPath UTF8String];
 
     // find main python file.  __main__.py seems to be a standard.
-    NSArray *possibleMains = [NSArray arrayWithObjects:
+    possibleMains = [NSArray arrayWithObjects:
         @"__main__.py",
         @"__main__.pyc",
         @"__main__.pyo",
         @"Main.pyc",
         @"Main.pyo",
         nil];
-    NSEnumerator *possibleMainsEnumerator = [possibleMains objectEnumerator];
-    NSString *mainPyPath;
-    NSString *nextFileName;
+    possibleMainsEnumerator = [possibleMains objectEnumerator];
 
     while (nextFileName = [possibleMainsEnumerator nextObject]) {
         mainPyPath = [mainBundle pathForResource: nextFileName ofType: nil];
     if ( !mainPyPath )
         [NSException raise: NSInternalInconsistencyException
                     format: @"%s:%d pyobjc_main() Failed to find one of %@ in app wrapper.  Exiting.", __FILE__, __LINE__, possibleMains];
-    const char *mainPyPathPtr = [mainPyPath UTF8String];
+    mainPyPathPtr = [mainPyPath UTF8String];
 
     // construct argv for the child
 

pyobjc/Lib/AddressBook/test/test_loaded.py

 """
 
 import unittest
-import AddressBook
 import objc
 
 class ABTest (unittest.TestCase):
 
     def testConstants(self):
+        import AddressBook
+
         # Test one string and one integer, to check if the constant-extraction
         # script worked.
         self.assert_(hasattr(AddressBook, 'kABMultiDictionaryProperty'))
         self.assertEquals(AddressBook.kABPhoneMainLabel, '_$!<Main>!$_')
 
     def testClasses(self):
+        import AddressBook
+
         # Check that we loaded the AddressBook framework by looking for a
         # class that should exist
         self.assert_(hasattr(AddressBook, 'ABPerson'))

pyobjc/Lib/AppKit/test/test_structs.py

+#
+# Tests for the struct-wrapper for NSAffineTransformStruct
+#
+from AppKit import *
+import unittest
+import operator
+
+class TestNSAffineTransformStruct (unittest.TestCase):
+    def testConstructor(self):
+        p = NSAffineTransformStruct()
+        self.assert_(isinstance(p, NSAffineTransformStruct))
+        self.assertEquals(p.m11, None)
+        self.assertEquals(p.m12, None)
+        self.assertEquals(p.m21, None)
+        self.assertEquals(p.m22, None)
+        self.assertEquals(p.tX, None)
+        self.assertEquals(p.tY, None)
+
+        p = NSAffineTransformStruct(1,2, 3, 4, 5, 6)
+        self.assert_(isinstance(p, NSAffineTransformStruct))
+        self.assertEquals(p.m11, 1)
+        self.assertEquals(p.m12, 2)
+        self.assertEquals(p.m21, 3)
+        self.assertEquals(p.m22, 4)
+        self.assertEquals(p.tX, 5)
+        self.assertEquals(p.tY, 6)
+        self.assertEquals(p[0], 1)
+        self.assertEquals(p[1], 2)
+        self.assertEquals(p[2], 3)
+        self.assertEquals(p[3], 4)
+        self.assertEquals(p[4], 5)
+        self.assertEquals(p[5], 6)
+
+        p = NSAffineTransformStruct(tY=1,tX=2, m22=3, m21=4, m12=5, m11=6)
+        self.assert_(isinstance(p, NSAffineTransformStruct))
+        self.assertEquals(p.m11, 6)
+        self.assertEquals(p.m12, 5)
+        self.assertEquals(p.m21, 4)
+        self.assertEquals(p.m22, 3)
+        self.assertEquals(p.tX, 2)
+        self.assertEquals(p.tY, 1)
+        self.assertEquals(p[0], 6)
+        self.assertEquals(p[1], 5)
+        self.assertEquals(p[2], 4)
+        self.assertEquals(p[3], 3)
+        self.assertEquals(p[4], 2)
+        self.assertEquals(p[5], 1)
+
+        self.assertRaises(TypeError, NSAffineTransformStruct, 1, 2, 3, 4, 5, 6, 7, 8)
+        self.assertRaises(TypeError, NSAffineTransformStruct, 1, 2, 3, 4, 5, 6, tY=3)
+        self.assertRaises(TypeError, NSAffineTransformStruct, 1, 2, 3, 4, 5, m11=3)
+        self.assertRaises(TypeError, NSAffineTransformStruct, m11=3, mXY=4)
+
+    def testHash(self):
+        p = NSAffineTransformStruct()
+        self.assertRaises(TypeError, hash, p)
+
+    def testCompare(self):
+        p = NSAffineTransformStruct(1, 2, 3, 4, 5, 6)
+        q = NSAffineTransformStruct(1, 2, 3, 4, 5, 7)
+        P = (1, 2, 3, 4, 5, 6)
+        Q = (1, 2, 3, 4, 5, 7)
+
+        self.assert_(not (p == P[:4]))
+        self.assert_((p != P[:4]))
+        self.assert_(not (p <= P[:4]))
+        self.assert_(not (p < P[:4]))
+        self.assert_((p > P[:4]))
+        self.assert_((p >= P[:4]))
+
+        self.assert_(not (p < p))
+        self.assert_(not (p < P))
+        self.assert_(p < q)
+        self.assert_(p < Q)
+
+        self.assert_(p <= p)
+        self.assert_(p <= P)
+        self.assert_(p <= q)
+        self.assert_(p <= Q)
+
+        self.assert_(p == p)
+        self.assert_(p == P)
+        self.assert_(not (p == q))
+        self.assert_(not (p == Q))
+
+        self.assert_(p != q)
+        self.assert_(p != Q)
+        self.assert_(not(p != p))
+        self.assert_(not(p != P))
+
+        self.assert_(q >= p)
+        self.assert_(q >= P)
+        self.assert_(q >= q)
+        self.assert_(q >= Q)
+
+        self.assert_(not (q > q))
+        self.assert_(not (q > Q))
+        self.assert_(q > p)
+        self.assert_(q > P)
+
+    def testRepr(self):
+        p = NSAffineTransformStruct()
+        self.assertEquals(repr(p), "<AppKit.NSAffineTransformStruct m11=None m12=None m21=None m22=None tX=None tY=None>")
+
+        p = NSAffineTransformStruct(1, 2, 3, 4, 5, 6)
+        self.assertEquals(repr(p), "<AppKit.NSAffineTransformStruct m11=1 m12=2 m21=3 m22=4 tX=5 tY=6>")
+
+        p.tX = p
+        self.assertEquals(repr(p), "<AppKit.NSAffineTransformStruct m11=1 m12=2 m21=3 m22=4 tX=<AppKit.NSAffineTransformStruct ...> tY=6>")
+
+    def testStr(self):
+        p = NSAffineTransformStruct()
+        self.assertEquals(str(p), "<AppKit.NSAffineTransformStruct m11=None m12=None m21=None m22=None tX=None tY=None>")
+
+        p = NSAffineTransformStruct(1, 2, 3, 4, 5, 6)
+        self.assertEquals(str(p), "<AppKit.NSAffineTransformStruct m11=1 m12=2 m21=3 m22=4 tX=5 tY=6>")
+
+        p.tX = p
+        self.assertEquals(str(p), "<AppKit.NSAffineTransformStruct m11=1 m12=2 m21=3 m22=4 tX=<AppKit.NSAffineTransformStruct ...> tY=6>")
+
+    def testSlice(self):
+        p = NSAffineTransformStruct(1,2,3,4,5,6)
+        q = p[:]
+
+        self.assert_(isinstance(q, tuple))
+        self.assertEquals(q, (1.0,2.0,3.0,4.0,5.0,6.0))
+
+    def testDeleteSlice(self):
+        p = NSAffineTransformStruct(1,2)
+        self.assertRaises(TypeError, operator.delitem, p, 0)
+        self.assertRaises(TypeError, operator.delslice, p, 0, 3)
+
+    def testAssignSlice(self):
+        p = NSAffineTransformStruct(1,2,3,4,5,6)
+        p[:] = (4,5,6,7,8,9)
+
+        self.assert_(isinstance(p, NSAffineTransformStruct))
+        self.assertEquals(p.m11, 4)
+        self.assertEquals(p.m12, 5)
+        self.assertEquals(p.m21, 6)
+        self.assertEquals(p.m22, 7)
+        self.assertEquals(p.tX, 8)
+        self.assertEquals(p.tY, 9)
+
+        p[:] = p
+        self.assert_(isinstance(p, NSAffineTransformStruct))
+        self.assertEquals(p.m11, 4)
+        self.assertEquals(p.m12, 5)
+        self.assertEquals(p.m21, 6)
+        self.assertEquals(p.m22, 7)
+        self.assertEquals(p.tX, 8)
+        self.assertEquals(p.tY, 9)
+
+        p[1:4] = range(3)
+        self.assertEquals(p.m11, 4)
+        self.assertEquals(p.m12, 0)
+        self.assertEquals(p.m21, 1)
+        self.assertEquals(p.m22, 2)
+        self.assertEquals(p.tX, 8)
+        self.assertEquals(p.tY, 9)
+
+        self.assertRaises(TypeError, operator.setslice, p, 0, 2, [1,2,3])
+        self.assertRaises(TypeError, operator.setslice, p, 0, 2, [3])
+
+        self.assertRaises(TypeError, operator.delslice, p, 0, 0)
+        self.assertRaises(TypeError, operator.delslice, p, 0, 1)
+        self.assertRaises(TypeError, operator.delslice, p, 0, 2)
+
+
+if __name__ == "__main__":
+    unittest.main()

pyobjc/Lib/Foundation/test/test_keyvalue.py

             o = KVOClass.alloc().init()
             o.addObserver_forKeyPath_options_context_(self, "test", 0, 0)
             o.removeObserver_forKeyPath_(self, "test")
-            o.retain()
 
         def testKVO2(self):
             """

pyobjc/Lib/Foundation/test/test_nscoder.py

 import objc
 
 from Foundation import *
+from objc.test.testbndl import PyObjC_TestClass4
 
 class TestNSCoderUsage(unittest.TestCase):
     if not hasattr(unittest.TestCase, 'assertAlmostEquals'):
         self.assertEquals(newObj.decodedBytes[0], "hello")
         self.assertEquals(newObj.decodedBytes[1], 5)
 
+
+class MyCoder (NSCoder):
+    def init(self):
+        self = super(MyCoder, self).init()
+        if self is None: return None
+        self.coded = []
+        return self
+
+    def encodeValueOfObjCType_at_(self, tp, value):
+        self.coded.append( ("value", tp, value) )
+
+    def encodeArrayOfObjCType_count_at_(self, tp, cnt, value):
+        self.coded.append( ("array", tp, cnt, value) )
+
+    def encodeBytes_length_(self, bytes, length):
+        self.coded.append( ("bytes", bytes, length) )
+
+    def decodeValueOfObjCType_at_(self, tp):
+        if tp == 'i':
+            return 42
+        elif tp == 'd':
+            return 1.5
+
+    def decodeArrayOfObjCType_count_at_(self, tp, cnt):
+        return range(cnt)
+
+    def decodeBytesWithReturnedLength_(self):
+        return ("ABCDEabcde", 10)
+
+class TestPythonCoder(unittest.TestCase):
+    #
+    # This test accesses a NSCoder implemented in Python from Objective-C
+    # 
+    # The tests only use those methods that require a custom IMP-stub.
+    #
+    def testEncoding(self):
+        coder = MyCoder.alloc().init()
+        o = PyObjC_TestClass4.alloc().init()
+        o.encodeWithCoder_(coder)
+        self.assertEquals(coder.coded,
+                [
+                    ("value", "d", 1.5),
+                    ("array", "i", 4, (3,4,5,6)),
+                    ("bytes", "hello world", 11),
+                ])
+
+    def testDecoding(self):
+        coder = MyCoder.alloc().init()
+        o = PyObjC_TestClass4
+
+        self.assertEquals(o.fetchInt_(coder), 42)
+        self.assertEquals(o.fetchDouble_(coder), 1.5)
+
+        d = o.fetchData_(coder)
+        self.assertEquals(d.length(), 10)
+        self.assertEquals(str(d.bytes()), "ABCDEabcde")
+
+        d = o.fetchArray_(coder)
+        self.assertEquals(tuple(range(10)), tuple(d))
+
 if __name__ == '__main__':
     unittest.main( )

pyobjc/Lib/Foundation/test/test_nsdata.py

 import array
 
 from Foundation import NSData, NSMutableData
+from objc.test.testbndl import PyObjC_TestClass3
 
 rawBytes = "a\x13b\x00cd\xFFef\xEFgh"
 otherBytes = array.array('c')
 
             mutableBytes[0:len(mutableBytes)] = bytes[0:len(bytes)]
 
+class MyData (NSData):
+    def dataWithBytes_length_(self, bytes, length):
+        return ("data", bytes, length)
+
+BYTES="dummy bytes"
+class MyData2 (NSData):
+    def initWithBytes_length_(self, bytes, length):
+        return ("init", bytes, length)
+
+    def length(self):
+        return 42
+
+    def bytes(self):
+        return BYTES
+
+
+class MyData3 (NSData):
+    def initWithBytes_length_(self, bytes, length):
+        self.bytes = bytes
+        self.length = length
+        return self
+
+    def bytes(self):
+        return self.bytes
+
+    def length(self):
+        if hasattr(self, 'length'):
+            return self.length
+        return -1
+
+class MyData4 (NSData):
+    def initWithBytes_length_(self, bytes, length):
+        return self
+
+    def bytes(self):
+        return None
+
+    def length(self):
+        return -1
+
+class MyData5(NSData):
+    def initWithBytes_length_(self, bytes, length):
+        return self
+
+    def bytes(self):
+        raise ValueError, "No bytes available"
+
+    def length(self):
+        return -1
+
+
+
+class TestMyData (unittest.TestCase):
+    # 'initWithBytes:lenght:' and 'dataWithBytes:lenght:' have custom IMP's
+    def testData(self):
+        r = PyObjC_TestClass3.makeDataWithBytes_method_(MyData, 0)
+        self.assertEquals(r, ('data', 'hello world', 11))
+
+    def testInit(self):
+        r = PyObjC_TestClass3.makeDataWithBytes_method_(MyData2, 1)
+        self.assertEquals(r, ('init', 'hello world', 11))
+
+    def testBytes(self):
+        r = PyObjC_TestClass3.makeDataWithBytes_method_(MyData3, 1)
+        b = PyObjC_TestClass3.getBytes_(r)
+        self.assertEquals(str(b.bytes()), 'hello world')
+
+    def testBytesNone(self):
+        b = PyObjC_TestClass3.makeDataWithBytes_method_(MyData4, 1)
+        self.assertEquals(b.bytes(), None)
+
+    def testBytesRaises(self):
+        b = PyObjC_TestClass3.makeDataWithBytes_method_(MyData5, 1)
+        self.assertRaises(ValueError, b.bytes)
+
 if __name__ == '__main__':
     unittest.main( )

pyobjc/Lib/Foundation/test/test_nsobject.py

 from Foundation import *
 
 class TestNSObjectInteraction(unittest.TestCase):
+    def testCallingInstanceMethodWithClassSelf(self):
+        self.assertRaises(TypeError, NSObject.description, NSObject)
+        self.assertRaises(TypeError, NSObject.description, "hello")
+
+    def testNSObjectClassMethod(self):
+        # Check that -class is accesible as 'class__' and 'class' (the latter
+        # only through getattr because it is a Python keyword)
+        self.assert_(hasattr(NSObject, 'class__'))
+        self.assert_(isinstance(NSObject.class__, objc.selector))
+        o = NSObject.alloc().init()
+        self.assert_(o.class__() is o.__class__)
+
+        self.assert_(hasattr(NSObject, 'class'))
+        self.assert_(isinstance(getattr(NSObject, 'class'), objc.selector))
+        self.assert_(getattr(o, 'class')() is o.__class__)
+
     def testNSObjectClass(self):
         self.assert_( NSObject.instancesRespondToSelector_( "description" ), "NSObject class claims it doesn't respond to a selector that it does." )
         self.assert_( hasattr(NSObject, "description"), "NSObject class claims it doesn't respond to a selector that it does." )

pyobjc/Lib/Foundation/test/test_structs.py

+#
+# Tests for the struct-wrappers for NSPoint, NSSize, NSRange and NSRect.
+#
+from Foundation import *
+import unittest
+import operator
+
+class TestNSPoint (unittest.TestCase):
+    def testConstructor(self):
+        p = NSPoint()
+        self.assert_(isinstance(p, NSPoint))
+        self.assertEquals(p.x, None)
+        self.assertEquals(p.y, None)
+
+        p = NSPoint(1,2)
+        self.assert_(isinstance(p, NSPoint))
+        self.assertEquals(p.x, 1)
+        self.assertEquals(p.y, 2)
+        self.assertEquals(p[0], 1)
+        self.assertEquals(p[1], 2)
+
+        p = NSPoint(y=1,x=2)
+        self.assert_(isinstance(p, NSPoint))
+        self.assertEquals(p.x, 2)
+        self.assertEquals(p.y, 1)
+        self.assertEquals(p[1], 1)
+        self.assertEquals(p[0], 2)
+
+        self.assertRaises(TypeError, NSPoint, 1, 2, 3)
+        self.assertRaises(TypeError, NSPoint, 1, 2, y=3)
+        self.assertRaises(TypeError, NSPoint, 1, x=3)
+        self.assertRaises(TypeError, NSPoint, x=3, z=4)
+
+    def testMakePoint(self):
+        p = NSMakePoint(1, 2)
+        self.assert_(isinstance(p, NSPoint))
+        self.assertEquals(p.x, 1)
+        self.assertEquals(p.y, 2)
+
+    def testHash(self):
+        p = NSMakePoint(1, 2)
+        self.assertRaises(TypeError, hash, p)
+
+    def testCompare(self):
+        p = NSMakePoint(1, 2)
+        q = NSMakePoint(2, 3)
+        P = (1, 2)
+        Q = (2, 3)
+
+        self.assert_(not (p < p))
+        self.assert_(not (p < P))
+        self.assert_(p < q)
+        self.assert_(p < Q)
+
+        self.assert_(p <= p)
+        self.assert_(p <= P)
+        self.assert_(p <= q)
+        self.assert_(p <= Q)
+
+        self.assert_(p == p)
+        self.assert_(p == P)
+        self.assert_(not (p == q))
+        self.assert_(not (p == Q))
+
+        self.assert_(p != q)
+        self.assert_(p != Q)
+        self.assert_(not(p != p))
+        self.assert_(not(p != P))
+
+        self.assert_(q >= p)
+        self.assert_(q >= P)
+        self.assert_(q >= q)
+        self.assert_(q >= Q)
+
+        self.assert_(not (q > q))
+        self.assert_(not (q > Q))
+        self.assert_(q > p)
+        self.assert_(q > P)
+
+    def testRepr(self):
+        p = NSPoint()
+        self.assertEquals(repr(p), "<Foundation.NSPoint x=None y=None>")
+
+        p = NSPoint(42, 98)
+        self.assertEquals(repr(p), "<Foundation.NSPoint x=42 y=98>")
+
+        p.x = p
+        self.assertEquals(repr(p), "<Foundation.NSPoint x=<Foundation.NSPoint ...> y=98>")
+
+    def testStr(self):
+        p = NSPoint()
+        self.assertEquals(str(p), "<Foundation.NSPoint x=None y=None>")
+
+        p = NSPoint(42, 98)
+        self.assertEquals(str(p), "<Foundation.NSPoint x=42 y=98>")
+
+        p.x = p
+        self.assertEquals(repr(p), "<Foundation.NSPoint x=<Foundation.NSPoint ...> y=98>")
+
+    def testSlice(self):
+        p = NSPoint(1,2)
+        q = p[:]
+
+        self.assert_(isinstance(q, tuple))
+        self.assertEquals(q, (1.0,2.0))
+
+    def testDeleteAttr(self):
+        p = NSPoint(1,2)
+        self.assertRaises(TypeError, delattr, p, 'x')
+
+    def testDeleteSlice(self):
+        p = NSPoint(1,2)
+        self.assertRaises(TypeError, operator.delitem, p, 0)
+
+    def testAssignSlice(self):
+        p = NSPoint(1,2)
+        p[:] = (4,5)
+
+        self.assert_(isinstance(p, NSPoint))
+        self.assertEquals(p.x, 4)
+        self.assertEquals(p.y, 5)
+
+        p[:] = p
+        self.assert_(isinstance(p, NSPoint))
+        self.assertEquals(p.x, 4)
+        self.assertEquals(p.y, 5)
+
+        self.assertRaises(TypeError, operator.setslice, p, 0, 2, [1,2,3])
+        self.assertRaises(TypeError, operator.setslice, p, 0, 2, [3])
+        self.assertRaises(TypeError, operator.setslice, p, 0, 3, [1,2,3])
+
+        self.assertRaises(TypeError, operator.delslice, p, 0, 0)
+        self.assertRaises(TypeError, operator.delslice, p, 0, 1)
+        self.assertRaises(TypeError, operator.delslice, p, 0, 2)
+
+class TestNSSize (unittest.TestCase):
+    def testConstructor(self):
+        p = NSSize()
+        self.assert_(isinstance(p, NSSize))
+        self.assertEquals(p.width, None)
+        self.assertEquals(p.height, None)
+
+        p = NSSize(1,2)
+        self.assert_(isinstance(p, NSSize))
+        self.assertEquals(p.width, 1)
+        self.assertEquals(p.height, 2)
+        self.assertEquals(p[0], 1)
+        self.assertEquals(p[1], 2)
+
+        p = NSSize(height=1,width=2)
+        self.assert_(isinstance(p, NSSize))
+        self.assertEquals(p.width, 2)
+        self.assertEquals(p.height, 1)
+        self.assertEquals(p[1], 1)
+        self.assertEquals(p[0], 2)
+
+        self.assertRaises(TypeError, NSSize, 1, 2, 3)
+        self.assertRaises(TypeError, NSSize, 1, 2, height=3)
+        self.assertRaises(TypeError, NSSize, 1, width=3)
+        self.assertRaises(TypeError, NSSize, width=3, z=4)
+
+    def testMakeSize(self):
+        p = NSMakeSize(1, 2)
+        self.assert_(isinstance(p, NSSize))
+        self.assertEquals(p.width, 1)
+        self.assertEquals(p.height, 2)
+
+class TestNSRange (unittest.TestCase):
+    def testConstructor(self):
+        p = NSRange()
+        self.assert_(isinstance(p, NSRange))
+        self.assertEquals(p.location, None)
+        self.assertEquals(p.length, None)
+
+        p = NSRange(1,2)
+        self.assert_(isinstance(p, NSRange))
+        self.assertEquals(p.location, 1)
+        self.assertEquals(p.length, 2)
+        self.assertEquals(p[0], 1)
+        self.assertEquals(p[1], 2)
+
+        p = NSRange(length=1,location=2)
+        self.assert_(isinstance(p, NSRange))
+        self.assertEquals(p.location, 2)
+        self.assertEquals(p.length, 1)
+        self.assertEquals(p[1], 1)
+        self.assertEquals(p[0], 2)
+
+        self.assertRaises(TypeError, NSRange, 1, 2, 3)
+        self.assertRaises(TypeError, NSRange, 1, 2, length=3)
+        self.assertRaises(TypeError, NSRange, 1, location=3)
+        self.assertRaises(TypeError, NSRange, location=3, z=4)
+
+    def testMakeSize(self):
+        p = NSMakeSize(1, 2)
+        self.assert_(isinstance(p, NSSize))
+        self.assertEquals(p.width, 1)
+        self.assertEquals(p.height, 2)
+
+class TestNSRect (unittest.TestCase):
+    def testConstructor(self):
+        p = NSRect()
+        self.assert_(isinstance(p, NSRect))
+        self.assert_(p.origin is not None)
+        self.assert_(p.size is not None)
+        self.assertEquals(p.origin, NSPoint(0, 0))
+        self.assertEquals(p.size, NSSize(0, 0))
+
+        p = NSRect(1,2)
+        self.assert_(isinstance(p, NSRect))
+        self.assertEquals(p.origin, 1)
+        self.assertEquals(p.size, 2)
+        self.assertEquals(p[0], 1)
+        self.assertEquals(p[1], 2)
+
+        p = NSRect(size=1,origin=2)
+        self.assert_(isinstance(p, NSRect))
+        self.assertEquals(p.origin, 2)
+        self.assertEquals(p.size, 1)
+        self.assertEquals(p[1], 1)
+        self.assertEquals(p[0], 2)
+
+        self.assertRaises(TypeError, NSRect, 1, 2, 3)
+        self.assertRaises(TypeError, NSRect, 1, 2, origin=3)
+        self.assertRaises(TypeError, NSRect, 1, origin=3)
+        self.assertRaises(TypeError, NSRect, origin=3, z=4)
+
+    def testMakeRect(self):
+        p = NSMakeRect(1, 2, 3, 4)
+        self.assert_(isinstance(p, NSRect))
+        self.assertEquals(p.origin, (1, 2))
+        self.assertEquals(p.size, (3,4))
+        self.assertEquals(p.origin.x, 1)
+        self.assertEquals(p.origin.y, 2)
+        self.assertEquals(p.size.width, 3)
+        self.assertEquals(p.size.height, 4)
+
+if __name__ == "__main__":
+    unittest.main()

pyobjc/Lib/InterfaceBuilder/test/test_loaded.py

 """
 
 import unittest
-import InterfaceBuilder
 import objc
 
 class IBTest (unittest.TestCase):
 
     def testConstants(self):
+        import InterfaceBuilder
+
         self.assert_(hasattr(InterfaceBuilder, 'kPaletteResource'))
 
         self.assertEquals(InterfaceBuilder.kPaletteResource, 2)
 
     def testClasses(self):
+        import InterfaceBuilder
+
         # Check that we loaded the InterfaceBuilder framework by looking for a
         # class that should exist
         self.assert_(hasattr(InterfaceBuilder, 'IBContainerView'))

pyobjc/Lib/PreferencePanes/test/test_loaded.py

 """
 
 import unittest
-import PreferencePanes
 import objc
 
 class PPTest (unittest.TestCase):
 
 
     def testClasses(self):
+        import PreferencePanes
+
         # Check that we loaded the PreferencePanes framework by looking for a
         # class that should exist
         self.assert_(hasattr(PreferencePanes, 'NSPreferencePane'))

pyobjc/Lib/ScreenSaver/test/test_loaded.py

 """
 
 import unittest
-import ScreenSaver
 import objc
 
 class SSTest (unittest.TestCase):
 
     def testClasses(self):
+        import ScreenSaver
+
         # Check that we loaded the ScreenSaver framework by looking for a
         # class that should exist
         self.assert_(hasattr(ScreenSaver, 'ScreenSaverView'))

pyobjc/Lib/WebKit/test/test_loaded.py

 import unittest
 
 import os
+import objc
 
 if os.path.exists('/System/Library/Frameworks/WebKit.framework'):
-    import WebKit
-    import objc
-
-
     class WKTest (unittest.TestCase):
 
         def testConstants(self):
-            # Test one string and one integer, to check if the constant-extraction
-            # script worked.
+            # Test one string and one integer, to check if the 
+            # constant-extraction script worked.
+            import WebKit
+
             self.assert_(hasattr(WebKit, 'WebMenuItemTagOpenLinkInNewWindow'))
             self.assert_(hasattr(WebKit, 'WebHistoryItemsKey'))
 
         def testClasses(self):
             # Check that we loaded the WebKit framework by looking for a
             # class that should exist
+            import WebKit
+
             self.assert_(hasattr(WebKit, 'WebFrame'))
             self.assert_(isinstance(WebKit.WebFrame, objc.objc_class))
 
 
         def testProtocols(self):
+            import WebKit
+
             self.assert_(hasattr(WebKit.protocols, 'WebPolicyDelegate'))
 
 if __name__ == "__main__":

pyobjc/Lib/objc/test/test_classandinst.py

     """Simple subclass, just make sure it still works"""
     pass
 
+
+# XXX: Huh? The next two classes have the same definition?
 class PyObjC_TestClassAndInstanceClassOverride(PyObjC_TestClassAndInstance):
     """return YES for both"""
     def isInstance(klass):
 
     def testClassAndInstanceClassOverrideWorkaround(self):
         self.assertEquals(PyObjC_TestClassAndInstanceClassOverride.pyobjc_classMethods.isInstance(), objc.YES)
-        self.assertEquals(PyObjC_TestClassAndInstanceClassOverride.alloc().init().pyobjc_instanceMethods.isInstance(), objc.YES)
+
+        # XXX: Class methods are no longer accessible through instances.
+        #self.assertEquals(PyObjC_TestClassAndInstanceClassOverride.alloc().init().pyobjc_instanceMethods.isInstance(), objc.YES)
 
     def testClassAndInstanceSubclassWorkaround(self):
         self.assertEquals(PyObjC_TestClassAndInstanceSubclass.pyobjc_classMethods.isInstance(), objc.NO)
     
     def testClassAndInstanceClassOverride(self):
         self.assertEquals(PyObjC_TestClassAndInstanceClassOverride.isInstance(), objc.YES)
-        self.assertEquals(PyObjC_TestClassAndInstanceClassOverride.alloc().init().isInstance(), objc.YES)
+        #self.assertEquals(PyObjC_TestClassAndInstanceClassOverride.alloc().init().isInstance(), objc.YES)
 
     def testClassAndInstanceInstanceOverride(self):
         # Having the next line true would be nice:

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 PyObjCTest_KeyValueObserver
 from objc.test.testbndl import *
 from objc.test.keyvaluehelper import *
 
             self.assertEquals(o.multiple.level2.level3.keyB, 9.999)
 
 
+class PyObjC_TestKeyValueSource (objc.runtime.NSObject):
+    def getFoobar(self):
+        return "Hello world"
+
+class TestKeyValueObservingFromNative (unittest.TestCase):
+    # This test makes uses of Key-Value Coding/Observing from Objective-C.
+    # Versions of PyObjC upto 2003-12-29 crashed on this test due to the way
+    # key-value observing is implemented in Cocoa.
+
+    def testOne(self):
+        o = PyObjCTest_KeyValueObserver.alloc().initWithInstanceOfClass_withKey_(PyObjC_TestKeyValueSource, "foobar")
+        self.assertEquals(o.getValue(), "Hello world")
+
 if __name__ == "__main__":
     unittest.main()

pyobjc/Lib/objc/test/test_methodedits.py

 class TestFromPythonClassToObjCClass(unittest.TestCase):
 
     def testPythonSourcedMethods(self):
+        # 20031227, Ronald: Assigning the methods works alright, but actually 
+        # using them won't because the new methods are actually still methods 
+        # of a different class and will therefore complain about the type
+        # of 'self'.
         objc.classAddMethods(MEClass, [PurePython.description,
                                                   PurePython.newMethod,
                                                   PurePython.purePythonMethod])
 
         newInstance = MEClass.new()
 
-        self.assertEquals(newInstance.description(), "<pure>")
-        self.assertEquals(newInstance.newMethod(), "<pure-new>")
-        self.assertEquals(newInstance.purePythonMethod(), "<pure-py>")
+        # This is bogus, see above:
+        #self.assertEquals(newInstance.description(), "<pure>")
+        #self.assertEquals(newInstance.newMethod(), "<pure-new>")
+        #self.assertEquals(newInstance.purePythonMethod(), "<pure-py>")
 
-        self.assertEquals(preEverythingInstance.description(), "<pure>")
-        self.assertEquals(preEverythingInstance.newMethod(), "<pure-new>")
-        self.assertEquals(preEverythingInstance.purePythonMethod(), "<pure-py>")
+        #self.assertEquals(preEverythingInstance.description(), "<pure>")
+        #self.assertEquals(preEverythingInstance.newMethod(), "<pure-new>")
+        #self.assertEquals(preEverythingInstance.purePythonMethod(), "<pure-py>")
+
+        self.assertRaises(TypeError, newInstance.description)
+        self.assertRaises(TypeError, newInstance.newMethod)
+        self.assertRaises(TypeError, newInstance.purePythonMethod)
+        self.assertRaises(TypeError, preEverythingInstance.description)
+        self.assertRaises(TypeError, preEverythingInstance.newMethod)
+        self.assertRaises(TypeError, preEverythingInstance.purePythonMethod)
 
     def testPythonSourcedFunctions(self):
         # Same as testPythonSourcedMethods, but using function objects instead
         # of method objects.
+
+
         objc.classAddMethods(MEClass, [
             PurePython.description.im_func,
             PurePython.newMethod.im_func,
         self.assertEquals(preEverythingInstance.newMethod(), "<pure-new>")
         self.assertEquals(preEverythingInstance.purePythonMethod(), "<pure-py>")
 
+
+
+class TestClassAsignments (unittest.TestCase):
+    def testAssignAMethod(self):
+        MEClass.doSomethingElse = lambda self: 2*2
+        MEClass.doDuplicate_ = lambda self, x: 2*x
+        
+        self.assert_(MEClass.instancesRespondToSelector_("doSomethingElse"))
+        self.assert_(MEClass.instancesRespondToSelector_("doDuplicate:"))
+
+        o = MEClass.alloc().init()
+
+        self.assertEquals(4, o.doSomethingElse())
+        self.assertEquals(8, o.doDuplicate_(4))
+
+    def testAssignAClassMethod(self):
+        MEClass.classSomethingElse = classmethod(lambda self: 2*2)
+        MEClass.classDuplicate_ = classmethod(lambda self, x: 2*x)
+
+        self.assert_(MEClass.pyobjc_classMethods.respondsToSelector_("classSomethingElse"))
+        self.assert_(MEClass.pyobjc_classMethods.respondsToSelector_("classDuplicate:"))
+
+        self.assertEquals(4, MEClass.classSomethingElse())
+        self.assertEquals(8, MEClass.classDuplicate_(4))
+
+    def testAssignFuzzyMethod(self):
+        self.assertRaises(ValueError, setattr, MEClass, 'fuzzyMethod', objc.selector(None, selector='fuzzy', signature='@@:'))
+
+    def testRemovingMethods(self):
+        theClass = objc.runtime.NSObject
+
+        self.assertRaises(AttributeError, delattr, theClass, 'alloc')
+        self.assertRaises(AttributeError, delattr, theClass, 'init')
+
+
 if __name__ == '__main__':
     unittest.main()

pyobjc/Lib/objc/test/test_regr.py

 import objc
 
 class TestRegressions(unittest.TestCase):
+    def testNSObjectRespondsToCommonMethods(self):
+        NSObject=objc.runtime.NSObject
+        self.assert_(NSObject.pyobjc_classMethods.respondsToSelector_('alloc'))
+        self.assert_(NSObject.instancesRespondToSelector_('init'))
+        self.assert_(not NSObject.instancesRespondToSelector_('frodel'))
+
     def testQualifiersInSignature(self):
         import Foundation
         import AppKit

pyobjc/Lib/objc/test/test_subclass.py

 NSObject = objc.lookUpClass('NSObject')
 
 class TestSubclassing(unittest.TestCase):
+    def testMethodRaise(self):
+        # Defining a method whose name is a keyword followed by two underscores
+        # should define the method name without underscores in the runtime,
+        # and this method should be accesible both with and without the
+        # underscores.
+
+        class RaiseClass (NSObject):
+            def raise__(self):
+                pass
+
+        self.assert_(not hasattr(NSObject, 'raise__'))
+        self.assert_(not hasattr(NSObject, 'raise'))
+
+        self.assert_(hasattr(RaiseClass, 'raise__'))
+        self.assert_(hasattr(RaiseClass, 'raise'))
+        self.assertEquals(RaiseClass.raise__.selector, 'raise')
+        self.assertEquals(getattr(RaiseClass, 'raise').selector, 'raise')
+
     def testMIObjC(self):
         try:
             class MIClass1(NSObject, objc.runtime.NSArray):

pyobjc/Lib/objc/test/testbndl.m

 {
 }
 +makeACopy:source;
++makeDataWithBytes:(Class)cls method:(int)i;
++getBytes:(NSData*)data;
 +keyValue:(int)idx forObject: value key: id;
 +(void)setKeyValue:(int)idx forObject: object key: key value: value;
 @end
 
 @implementation PyObjC_TestClass3
 
++getBytes:(NSData*)data
+{
+	const void* bytes = [data bytes];
+
+	if (bytes == NULL) {
+		return nil;
+	} else {
+		return [NSData dataWithBytes:bytes length:[data length]];
+	}
+}
+
+
++makeDataWithBytes:(Class)cls method:(int)i
+{
+	if (i == 0) {
+		return [cls dataWithBytes:"hello world" length:sizeof("hello world")-1];
+	} else {
+		id o = [cls alloc];
+		return [o initWithBytes:"hello world" length:sizeof("hello world")-1];
+	}
+}
+
+
 +makeACopy:source
 {
 	id theCopy;
 
 @end
 
+@interface PyObjC_TestClass4 : NSObject
+{
+}
+- (void)encodeWithCoder:(NSCoder*)coder;
+
++ (int)fetchInt:(NSCoder*)coder;
++ (double)fetchDouble:(NSCoder*)coder;
++ (NSData*)fetchData:(NSCoder*)coder;
++ (NSArray*)fetchArray:(NSCoder*)coder;
+@end
+
+@implementation PyObjC_TestClass4
+- (void)encodeWithCoder:(NSCoder*)coder
+{
+	double d = 1.5;
+	int iArray[] = { 3,4,5,6};
+	[coder encodeValueOfObjCType:@encode(double) at:&d];
+	[coder encodeArrayOfObjCType:@encode(int) count:4 at:iArray];
+	[coder encodeBytes:"hello world" length:11];
+}
+
++ (int)fetchInt:(NSCoder*)coder
+{
+	int i;
+	[coder decodeValueOfObjCType:@encode(int) at:&i];
+	return i;
+}
+
++ (double)fetchDouble:(NSCoder*)coder
+{
+	double i;
+	[coder decodeValueOfObjCType:@encode(double) at:&i];
+	return i;
+}
+
++ (NSData*)fetchData:(NSCoder*)coder
+{
+	void* data;
+	int length;
+
+	data = [coder decodeBytesWithReturnedLength:&length];
+	return [NSData dataWithBytes:data length:length];
+}
+
++ (NSArray*)fetchArray:(NSCoder*)coder
+{
+	int data[10];
+
+	[coder decodeArrayOfObjCType:@encode(int) count:10 at:data];
+	return [NSArray arrayWithObjects:
+			[NSNumber numberWithInt:data[0]],
+			[NSNumber numberWithInt:data[1]],
+			[NSNumber numberWithInt:data[2]],
+			[NSNumber numberWithInt:data[3]],
+			[NSNumber numberWithInt:data[4]],
+			[NSNumber numberWithInt:data[5]],
+			[NSNumber numberWithInt:data[6]],
+			[NSNumber numberWithInt:data[7]],
+			[NSNumber numberWithInt:data[8]],
+			[NSNumber numberWithInt:data[9]],
+			nil];
+}
+
+@end
+
 
 @interface PyObjCTest_KVBaseClass : NSObject
 {
 }
 @end
 
+@interface PyObjCTest_KeyValueObserver : NSObject
+{
+	id observed;
+	NSString* key;
+	id value;
+}
+-initWithInstanceOfClass:(Class)cls withKey:(NSString*)key;
+-getValue;
+-(void)dealloc;
+-(void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context;
+@end
+
+@implementation PyObjCTest_KeyValueObserver
+
+-initWithInstanceOfClass:(Class)cls withKey:(NSString*)aKey
+{
+	self = [super init];
+	if (self == nil) return nil;
+	value = nil;
+	observed = nil;
+
+	observed = [[cls alloc] init];
+	if (observed == nil) {
+		[self release];
+		return nil;
+	}
+
+	key = aKey;
+	[aKey retain];
+
+	[observed addObserver:self 
+		  forKeyPath:key 
+		  options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld 
+		  context:0];
+	value = [observed valueForKey:key];
+	return self;
+}
+
+-(void)dealloc
+{
+	[observed removeObserver:self forKeyPath:key];
+	[key release];
+	[observed release];
+	[value release];
+}
+
+-getValue
+{
+	return value;
+}
+
+-(void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context
+{
+	id newValue = [change objectForKey:NSKeyValueChangeNewKey];
+	[newValue retain];
+	[value release];
+	value = newValue;
+
+	// use all arguments to avoid warnings...
+	(void)&keyPath;
+	(void)&context;
+	(void)&object;
+}
+
+
+@end
+
 
 static PyObject* pyobjcpy(PyObject* self __attribute__((__unused__)), PyObject* args)
 {
 		PyObjCClass_New([OC_TestClass2 class]));
 	PyModule_AddObject(m, "PyObjC_TestClass3", 
 		PyObjCClass_New([PyObjC_TestClass3 class]));
+	PyModule_AddObject(m, "PyObjC_TestClass4", 
+		PyObjCClass_New([PyObjC_TestClass4 class]));
 	PyModule_AddObject(m, "PyObjCTest_KVBaseClass", 
 		PyObjCClass_New([PyObjCTest_KVBaseClass class]));
 	PyModule_AddObject(m, "PyObjCTest_KVPathClass", 
 		PyObjCClass_New([PyObjCTest_KVPathClass class]));
+	PyModule_AddObject(m, "PyObjCTest_KeyValueObserver", 
+		PyObjCClass_New([PyObjCTest_KeyValueObserver class]));
 
 	PyModule_AddObject(m, "DO_VALUEFORKEY", PyInt_FromLong(0));
 	PyModule_AddObject(m, "DO_VALUEFORKEYPATH", PyInt_FromLong(1));

pyobjc/Modules/AppKit/_AppKit.m

 /* 'Applications' */
 
 static PyObject* 
-objc_NSApplicationMain(PyObject* self __attribute__((__unused__)), PyObject* args, PyObject* kwds)
+objc_NSApplicationMain(
+	PyObject* self __attribute__((__unused__)), 
+	PyObject* args, 
+	PyObject* kwds)
 {
 static	char* keywords[] = { "argv", NULL };
 	char** argv = NULL;
 
 
 static PyObject*
-objc_NSApp(PyObject* self __attribute__((__unused__)), PyObject* args, PyObject* kwds)
+objc_NSApp(
+	PyObject* self __attribute__((__unused__)), 
+	PyObject* args, 
+	PyObject* kwds)
 {
 static  char* keywords[] = { NULL };
         PyObject* result;
 }
 
 static PyObject*
-objc_NSCountWindows(PyObject* self __attribute__((__unused__)), PyObject* args, PyObject* kwds)
+objc_NSCountWindows(
+	PyObject* self __attribute__((__unused__)), 
+	PyObject* args, 
+	PyObject* kwds)
 {
 static  char* keywords[] = { NULL };
 	int       count;
 }
 
 static PyObject*
-objc_NSCountWindowsForContext(PyObject* self __attribute__((__unused__)), PyObject* args, PyObject* kwds)
+objc_NSCountWindowsForContext(
+	PyObject* self __attribute__((__unused__)), 
+	PyObject* args, 
+	PyObject* kwds)
 {
 static  char* keywords[] = { "context", NULL };
 	int       count;
 }
 
 static PyObject*
-objc_NSAvailableWindowDepths(PyObject* self __attribute__((__unused__)), PyObject* args, PyObject* kwds)
-{
-static  char* keywords[] = { NULL };
-	const NSWindowDepth*	  depths;
-	PyObject *result, *tmp;
-
-	if (!PyArg_ParseTupleAndKeywords(args, kwds, ":NSAvailableWindowDepts", keywords)) {
-		return NULL;
-	}
-
-	NS_DURING
-		depths = NSAvailableWindowDepths();
-	NS_HANDLER
-		depths = NULL;
-		PyObjCErr_FromObjC(localException);
-	NS_ENDHANDLER
-	if (PyErr_Occurred()) return NULL;
-
-	result = PyList_New(0);
-	if (result == NULL) return NULL;
-
-	while (*depths != 0) {
-		PyObject* v = PyInt_FromLong(*depths);
-		if (v == NULL) {
-			Py_DECREF(result);
-			return NULL;
-		}
-
-		if (PyList_Append(result, v) == -1) {
-			Py_DECREF(result);
-			return NULL;
-		}
-
-		depths++;
-	}
-
-	tmp = PyList_AsTuple(result);
-	Py_XDECREF(result);
-	return tmp;
-}
-
-
-static PyObject*
-objc_NSRectFillList(PyObject* self __attribute__((__unused__)), PyObject* args, PyObject* kwds)
+objc_NSRectFillList(
+	PyObject* self __attribute__((__unused__)), 
+	PyObject* args, 
+	PyObject* kwds)
 {
 static char* keywords[] = { "rects", "count", 0 };
 	PyObject* pyList;
 }
 
 static PyObject*
-objc_NSRectFillListUsingOperation(PyObject* self __attribute__((__unused__)), PyObject* args, PyObject* kwds)
+objc_NSRectFillListUsingOperation(
+	PyObject* self __attribute__((__unused__)), 
+	PyObject* args, 
+	PyObject* kwds)
 {
 static char* keywords[] = { "rects", "count", "operation", 0 };
 	PyObject* pyList;
 }
 
 static PyObject*
-objc_NSRectFillListWithColors(PyObject* self __attribute__((__unused__)), PyObject* args, PyObject* kwds)
+objc_NSRectFillListWithColors(
+	PyObject* self __attribute__((__unused__)), 
+	PyObject* args, 
+	PyObject* kwds)
 {
 static char* keywords[] = { "rects", "colors", "count", 0 };
 	PyObject* pyList;
 }
 
 static PyObject*
-objc_NSRectFillListWithColorsUsingOperation(PyObject* self __attribute__((__unused__)), PyObject* args, PyObject* kwds)
+objc_NSRectFillListWithColorsUsingOperation(
+	PyObject* self __attribute__((__unused__)), 
+	PyObject* args, 
+	PyObject* kwds)
 {
 static char* keywords[] = { "rects", "colors", "count", "operation", 0 };
 	PyObject* pyList;
 }
 
 static PyObject*
-objc_NSRectFillListWithGrays(PyObject* self __attribute__((__unused__)), PyObject* args, PyObject* kwds)
+objc_NSRectFillListWithGrays(
+	PyObject* self __attribute__((__unused__)), 
+	PyObject* args, 
+	PyObject* kwds)
 {
 static char* keywords[] = { "rects", "grays", "count", 0 };
 	PyObject* pyList;
 }
 
 static PyObject*
+objc_NSDrawTiledRects(
+	PyObject* self __attribute__((__unused__)), 
+	PyObject* args, 
+	PyObject* kwds)
+{
+static char* keywords[] = { "boundsRect", "clipRect", "sides", "grays", "count", 0 };
+	PyObject* pyBounds;
+	PyObject* pyClip;
+	PyObject* pySides;
+	PyObject* pyGrays;
+	PyObject* pyCount = NULL;
+	NSRect boundsRect;
+	NSRect clipRect;
+	NSRectEdge* sides;
+	float* grays;
+	int sidesCount;
+	int graysCount;
+	int sidesToken;
+	int graysToken;
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOOO|O", keywords, &pyBounds, &pyClip, &pySides, &pyGrays, &pyCount)) {
+		return NULL;
+	}
+
+	if (PyObjC_PythonToObjC(@encode(NSRect), pyBounds, &boundsRect) == -1) {
+		return NULL;
+	}
+	if (PyObjC_PythonToObjC(@encode(NSRect), pyClip, &clipRect) == -1) {
+		return NULL;
+	}
+
+	sidesToken = PyObjC_PythonToCArray(
+		@encode(NSRectEdge), pySides, pyCount, (void**)&sides, &sidesCount);
+
+	if (sidesToken == -1) return NULL;
+
+	graysToken = PyObjC_PythonToCArray(
+		@encode(id), pyGrays, pyCount, (void**)&grays, &graysCount);
+
+	if (graysToken == -1)  {
+		PyObjC_FreeCArray(sidesToken, sides);
+		return NULL;
+	}
+
+	if (graysCount != sidesCount) {
+		PyErr_Format(PyExc_ValueError,
+				"Passing %d sides and %d grays",
+				sidesCount, graysCount);
+		PyObjC_FreeCArray(sidesToken, sides);
+		PyObjC_FreeCArray(graysToken, grays);
+		return NULL;
+	}
+		
+
+	NS_DURING
+		NSDrawTiledRects(boundsRect, clipRect, sides, grays, sidesCount);
+	NS_HANDLER
+		PyObjCErr_FromObjC(localException);
+	NS_ENDHANDLER
+
+	PyObjC_FreeCArray(sidesToken, sides);
+	PyObjC_FreeCArray(graysToken, grays);
+
+	if (PyErr_Occurred()) {
+		return NULL;
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None; 
+}
+
+static PyObject*
+objc_NSDrawColorTiledRects(
+	PyObject* self __attribute__((__unused__)), 
+	PyObject* args, 
+	PyObject* kwds)
+{
+static char* keywords[] = { "boundsRect", "clipRect", "sides", "grays", "count", 0 };
+	PyObject* pyBounds;
+	PyObject* pyClip;
+	PyObject* pySides;
+	PyObject* pyColors;
+	PyObject* pyCount = NULL;
+	NSRect boundsRect;
+	NSRect clipRect;
+	NSRectEdge* sides;
+	id* colors;
+	int sidesCount;
+	int colorsCount;
+	int sidesToken;
+	int colorsToken;
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOOO|O", keywords, &pyBounds, &pyClip, &pySides, &pyColors, &pyCount)) {
+		return NULL;
+	}
+
+	if (PyObjC_PythonToObjC(@encode(NSRect), pyBounds, &boundsRect) == -1) {
+		return NULL;
+	}
+	if (PyObjC_PythonToObjC(@encode(NSRect), pyClip, &clipRect) == -1) {
+		return NULL;
+	}
+
+	sidesToken = PyObjC_PythonToCArray(
+		@encode(NSRectEdge), pySides, pyCount, (void**)&sides, &sidesCount);
+
+	if (sidesToken == -1) return NULL;
+
+	colorsToken = PyObjC_PythonToCArray(
+		@encode(id), pyColors, pyCount, (void**)&colors, &colorsCount);
+
+	if (colorsToken == -1)  {
+		PyObjC_FreeCArray(sidesToken, sides);
+		return NULL;
+	}
+
+	if (colorsCount != sidesCount) {
+		PyErr_Format(PyExc_ValueError,
+				"Passing %d sides and %d colors",
+				sidesCount, colorsCount);
+		PyObjC_FreeCArray(sidesToken, sides);
+		PyObjC_FreeCArray(colorsToken, colors);
+		return NULL;
+	}
+		
+
+	NS_DURING
+		NSDrawColorTiledRects(boundsRect, clipRect, sides, colors, sidesCount);
+	NS_HANDLER
+		PyObjCErr_FromObjC(localException);
+	NS_ENDHANDLER
+
+	PyObjC_FreeCArray(sidesToken, sides);
+	PyObjC_FreeCArray(colorsToken, colors);
+
+	if (PyErr_Occurred()) {
+		return NULL;
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None; 
+}
+
+static PyObject* 
+objc_NSWindowListForContext(
+	PyObject* self __attribute__((__unused__)),
+	PyObject* args,
+	PyObject* kwds)
+{
+	static char* keywords[] = { "context", "count", NULL };
+	int context;
+	int size;
+	int* list;
+	PyObject* result;
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwds, "ii", keywords, &context, &size)) {
+		return NULL;
+	}
+
+	list = malloc(sizeof(int)*size);
+	if (list == NULL) {
+		PyErr_NoMemory();
+		return 0;
+	}
+	memset(list, 0, sizeof(int)*size);
+
+	NS_DURING
+		NSWindowListForContext(context, size, list);
+	NS_HANDLER
+		PyObjCErr_FromObjC(localException);
+	NS_ENDHANDLER
+
+	if (PyErr_Occurred()) {
+		free(list);
+		return NULL;
+	}
+
+	result = PyObjC_CArrayToPython(@encode(int), list, size);
+	free(list);
+	return result;
+}
+
+static PyObject* 
+objc_NSWindowList(
+	PyObject* self __attribute__((__unused__)),
+	PyObject* args,
+	PyObject* kwds)
+{
+	static char* keywords[] = { "count", NULL };
+	int size;
+	int* list;
+	PyObject* result;
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", keywords, &size)) {
+		return NULL;
+	}
+
+	list = malloc(sizeof(int)*size);
+	if (list == NULL) {
+		PyErr_NoMemory();
+		return 0;
+	}
+	memset(list, 0, sizeof(int)*size);
+
+	NS_DURING
+		NSWindowList(size, list);
+	NS_HANDLER
+		PyObjCErr_FromObjC(localException);
+	NS_ENDHANDLER
+
+	if (PyErr_Occurred()) {
+		free(list);
+		return NULL;
+	}
+
+	result = PyObjC_CArrayToPython(@encode(int), list, size);
+	free(list);
+	return result;
+}
+
+static PyObject* 
+objc_NSAvailableWindowDepths(
+	PyObject* self __attribute__((__unused__)),
+	PyObject* args,
+	PyObject* kwds)
+{
+	static char* keywords[] = { NULL };
+	int size;
+	const int* list;
+	PyObject* result;
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwds, "", keywords)) {
+		return NULL;
+	}
+
+	NS_DURING
+		list = NSAvailableWindowDepths();
+	NS_HANDLER
+		PyObjCErr_FromObjC(localException);
+		list = NULL;
+	NS_ENDHANDLER
+
+	if (list == NULL && PyErr_Occurred()) {
+		return NULL;
+	}
+	size = 0;
+	if (list != NULL) {
+		for (size=0; list[size] != 0; size++) ;
+		size ++;
+	}
+
+	result = PyObjC_CArrayToPython(@encode(int), (int*)list, size);
+	return result;
+}
+
+static PyObject* 
+objc_NSBestDepth(
+	PyObject* self __attribute__((__unused__)),
+	PyObject* args,
+	PyObject* kwds)
+{
+	static char* keywords[] = { "colorSpace", "bps", "bpp", "planar" };