Commits

Ronald Oussoren committed fc8686f

Futher improvements in testsuite, with cleanups

Comments (0)

Files changed (20)

pyobjc-core/Doc/lib/module-PyObjCTools.KeyValueCoding.rst

 
    .. method __setattr__(key, value)
 
-      Returns ``setKey(self, key, value)``.
+      Returns ``setKey(self, key, value)`` if the key
+      does not start with an underscore. 
+      
+      Sets an attribute of the wrapper
+      when the key does start with an undercore.
 
    .. method __getitem_(self, keypath)
 

pyobjc-core/Doc/lib/module-objc.rst

 .. function:: callbackFor(callable[, argIndex=])
 
    Use this decorator to tell that this function is the callback for
-   an (Objective-C) API.
+   an (Objective-C) API that stores a reference to the callback
+   function.
+
+   You only *have* to use this API when the Objective-C API can store
+   the callback function for later usage. For other functions the
+   bridge can create a temporary callback stub.
+
+   Using this decorator for methods is not supported
 
    Usage:
 
    for NSArray, and ensures that the function will get the correct
    Objective-C signature.
 
+   .. note::
+
+      The example will also work without the decorator because 
+      NSArray won't store a reference to the compare function that
+      is used after 'sortedArrayUsingFunction_context_' returns.
+
 .. function:: selectorFor(callable[, argIndex])
 
    Decorator to tell that this is the "callback" selector for another 
       def sheetDidEnd_returnCode_contextInfo_(self, sheet, returnCode, info): 
           pass 
       
-  This will tell the bridge that this method is used as the end method
-  for a sheet API, and will ensure that the method is registered with
-  the correct Objective-C signature.
+   This will tell the bridge that this method is used as the end method
+   for a sheet API, and will ensure that the method is registered with
+   the correct Objective-C signature.
 
-  You only *have* to use this API when the Objective-C API can store
-  the callback function for later usage. For other functions the
-  bridge can create a temporary callback stub.
 
 .. function:: synthesize(name[, copy[, readwrite[, type[, ivarName]]]])
 

pyobjc-core/Lib/PyObjCTools/KeyValueCoding.py

     def __setattr__(self, attr, value):
         if not attr.startswith('_'):
             setKey(self.__pyobjc_object__, attr, value)
-        object.__setattr__(self, attr, value)
+
+        else:
+            object.__setattr__(self, attr, value)
 
     def __getitem__(self, item):
         if not isinstance(item, basestring):

pyobjc-core/Lib/PyObjCTools/TestSupport.py

     This also adds a number of useful assertion methods
     """
 
-    if not hasattr(_unittest.TestCase, 'assertItemsEqual'):
-        def assertItemsEqual(self, seq1, seq2, message=None):
-            self.assertEqual(set(seq1), set(seq2), message)
-
-    def assertGreaterThan(self, value, test, message = None):
-        if not (value > test):
-            self.fail(message or "not: %s > %s"%(value, test))
-
-    def assertGreaterThanOrEquals(self, value, test, message = None):
-        if not (value >= test):
-            self.fail(message or "not: %s >= %s"%(value, test))
-
-    def assertLessThan(self, value, test, message = None):
-        if not (value < test):
-            self.fail(message or "not: %s < %s"%(value, test))
-
-    def assertLessThanOrEquals(self, value, test, message = None):
-        if not (value <= test):
-            self.fail(message or "not: %s <= %s"%(value, test))
 
     def assertIsCFType(self, tp, message = None):
         if not isinstance(tp, objc.objc_class):
         if not hasattr(tp, "__typestr__"):
             self.fail(message or "%r is not an opaque-pointer"%(tp,))
 
-    def assertIs(self, value, test, message = None):
-        if value is not test:
-            self.fail(message or  "%r (id=%r) is not %r (id=%r) "%(value, id(value), test, id(test)))
-
-    def assertIsNot(self, value, test, message = None):
-        if value is test:
-            self.fail(message or  "%r is %r"%(value, test))
-
-    def assertIsNone(self, value, message = None):
-        self.assertIs(value, None)
-
-    def assertIsNotNone(self, value, message = None):
-        if value is None:
-            sel.fail(message, "%r is not %r"%(value, test))
 
     def assertResultIsNullTerminated(self, method, message = None):
         info = method.__metadata__()
         if not info['retval'].get('c_array_delimited_by_null'):
-            self.fail(message or "result of %r is not a nul-terminated array"%(method,))
+            self.fail(message or "result of %r is not a null-terminated array"%(method,))
 
     def assertIsNullTerminated(self, method, message = None):
         info = method.__metadata__()
             self.fail(message or "arg %d of %s is not an 'in' argument"%(
                 argno, method))
 
+    
+    #
+    # Addition assert methods, all of them should only be necessary for
+    # python 2.7 or later
+    #
 
-    def assertStartswith(self, value, check, message=None):
-        if not value.startswith(check):
-            self.fail(message or "not %r.startswith(%r)"%(value, check))
+    if not hasattr(_unittest.TestCase, 'assertItemsEqual'): # pragma: no cover
+        def assertItemsEqual(self, seq1, seq2, message=None):
+            self.assertEqual(set(seq1), set(seq2), message)
 
-    def assertHasAttr(self, value, key, message=None):
-        if not hasattr(value, key):
-            self.fail(message or "%s is not an attribute of %r"%(key, value))
+    if not hasattr(_unittest.TestCase, 'assertIs'): # pragma: no cover
+        def assertIs(self, value, test, message = None):
+            if value is not test:
+                self.fail(message or  "%r (id=%r) is not %r (id=%r) "%(value, id(value), test, id(test)))
 
-    def assertNotHasAttr(self, value, key, message=None):
-        if hasattr(value, key):
-            self.fail(message or "%s is an attribute of %r"%(key, value))
+    if not hasattr(_unittest.TestCase, 'assertIsNot'): # pragma: no cover
+        def assertIsNot(self, value, test, message = None):
+            if value is test:
+                self.fail(message or  "%r is %r"%(value, test))
 
-    def assertIsInstance(self, value, types, message=None):
-        if not isinstance(value, types):
-            self.fail(message or "%s is not an instance of %r but %s"%(value, types, type(value)))
+    if not hasattr(_unittest.TestCase, 'assertIsNone'): # pragma: no cover
+        def assertIsNone(self, value, message = None):
+            self.assertIs(value, None)
 
-    def assertIsNotInstance(self, value, types, message=None):
-        if isinstance(value, types):
-            self.fail(message or "%s is an instance of %r"%(value, types))
+    if not hasattr(_unittest.TestCase, 'assertIsNotNone'): # pragma: no cover
+        def assertIsNotNone(self, value, message = None):
+            if value is None:
+                sel.fail(message, "%r is not %r"%(value, test))
 
-    def assertIn(self, value, seq, message=None):
-        if value not in seq:
-            self.fail(message or "%r is not in %r"%(value, seq))
+    if not hasattr(_unittest.TestCase, 'assertStartsWith'): # pragma: no cover
+        def assertStartswith(self, value, check, message=None):
+            if not value.startswith(check):
+                self.fail(message or "not %r.startswith(%r)"%(value, check))
 
-    def assertNotIn(self, value, seq, message=None):
-        if value in seq:
-            self.fail(message or "%r is in %r"%(value, seq))
+    if not hasattr(_unittest.TestCase, 'assertHasAttr'): # pragma: no cover
+        def assertHasAttr(self, value, key, message=None):
+            if not hasattr(value, key):
+                self.fail(message or "%s is not an attribute of %r"%(key, value))
 
+    if not hasattr(_unittest.TestCase, 'assertNotHasAttr'): # pragma: no cover
+        def assertNotHasAttr(self, value, key, message=None):
+            if hasattr(value, key):
+                self.fail(message or "%s is an attribute of %r"%(key, value))
 
-    if not hasattr(_unittest.TestCase, 'assertGreaterThan'):
+    if not hasattr(_unittest.TestCase, 'assertIsInstance'): # pragma: no cover
+        def assertIsInstance(self, value, types, message=None):
+            if not isinstance(value, types):
+                self.fail(message or "%s is not an instance of %r but %s"%(value, types, type(value)))
+
+    if not hasattr(_unittest.TestCase, 'assertIsNotInstance'): # pragma: no cover
+        def assertIsNotInstance(self, value, types, message=None):
+            if isinstance(value, types):
+                self.fail(message or "%s is an instance of %r"%(value, types))
+
+    if not hasattr(_unittest.TestCase, 'assertIn'): # pragma: no cover
+        def assertIn(self, value, seq, message=None):
+            if value not in seq:
+                self.fail(message or "%r is not in %r"%(value, seq))
+
+    if not hasattr(_unittest.TestCase, 'assertNotIn'): # pragma: no cover
+        def assertNotIn(self, value, seq, message=None):
+            if value in seq:
+                self.fail(message or "%r is in %r"%(value, seq))
+
+
+    if not hasattr(_unittest.TestCase, 'assertGreaterThan'): # pragma: no cover
         def assertGreaterThan(self, val, test, message=None):
             if not (val > test):
                 self.fail(message or '%r <= %r'%(val, test))
 
-    if not hasattr(_unittest.TestCase, 'assertGreaterEqual'):
+    if not hasattr(_unittest.TestCase, 'assertGreaterEqual'): # pragma: no cover
         def assertGreaterEqual(self, val, test, message=None):
             if not (val >= test):
                 self.fail(message or '%r < %r'%(val, test))
 
-    if not hasattr(_unittest.TestCase, 'assertLessThan'):
+    if not hasattr(_unittest.TestCase, 'assertLessThan'): # pragma: no cover
         def assertLessThan(self, val, test, message=None):
             if not (val < test):
                 self.fail(message or '%r >= %r'%(val, test))
 
-    if not hasattr(_unittest.TestCase, 'assertLessEqual'):
+    if not hasattr(_unittest.TestCase, 'assertLessEqual'): # pragma: no cover
         def assertLessEqual(self, val, test, message=None):
             if not (val <= test):
                 self.fail(message or '%r > %r'%(val, test))
 
-
-    if not hasattr(_unittest.TestCase, "assertAlmostEquals"):
+    if not hasattr(_unittest.TestCase, "assertAlmostEquals"): # pragma: no cover
         def assertAlmostEquals(self, val1, val2, message=None):
             self.failUnless(abs (val1 - val2) < 0.00001, 
                     message or 'abs(%r - %r) >= 0.00001'%(val1, val2))
 
 
     def run(self, *args):
+        """
+        Run the test, same as unittest.TestCase.run, but every test is
+        run with a fresh autorelease pool.
+        """
         if _useleaks:
             leaksBefore = _leaks()
         if _usepool:
                         for ln in leaksAfter:
                             print(ln)
 
-    def _deprecate(original_func):
-        def deprecated_func(*args, **kwds):
-            warnings.warn("Please use %s instead."%(original_func.__name__,),
-                    DeprecationWarning, 2)
-            return original_func(*args, **kwds)
-        return deprecated_func
-
-    failUnlessIsIn = _deprecate(assertIn)
-    failUnlessIsNotIn = _deprecate(assertNotIn)
-    assertIsIn = _deprecate(assertIn)
-    assertIsNotIn = _deprecate(assertNotIn)
-    failUnlessIsCFType = _deprecate(assertIsCFType)
-    failUnlessIsOpaquePointer = _deprecate(assertIsOpaquePointer)
-    failUnlessIsNone = _deprecate(assertIsNone)
-    failIfIsNone = _deprecate(assertIsNotNone)
-    failUnlessResultIsNullTerminated = _deprecate(assertResultIsNullTerminated)
-    failUnlessIsNullTerminated = _deprecate(assertIsNullTerminated)
-    failUnlessArgIsNullTerminated = _deprecate(assertArgIsNullTerminated)
-    failUnlessArgIsVariableSize = _deprecate(assertArgIsVariableSize)
-    failUnlessResultIsVariableSize = _deprecate(assertResultIsVariableSize)
-    failUnlessArgSizeInResult = _deprecate(assertArgSizeInResult)
-    failUnlessArgIsPrintf = _deprecate(assertArgIsPrintf)
-    failUnlessArgIsCFRetained = _deprecate(assertArgIsCFRetained)
-    failIfArgIsCFRetained = _deprecate(assertArgIsCFRetained)
-    failUnlessResultIsCFRetained = _deprecate(assertResultIsCFRetained)
-    failIfResultIsCFRetained = _deprecate(assertResultIsNotCFRetained)
-    failUnlessResultIsRetained = _deprecate(assertResultIsRetained)
-    failIfResultIsRetained = _deprecate(assertResultIsNotRetained)
-    failUnlessResultHasType = _deprecate(assertResultHasType)
-    failUnlessArgHasType = _deprecate(assertArgHasType)
-    failUnlessArgIsFunction = _deprecate(assertArgIsFunction)
-    failUnlessArgIsBlock = _deprecate(assertArgIsBlock)
-    failUnlessResultIsBlock = _deprecate(assertResultIsBlock)
-    failUnlessArgIsSEL = _deprecate(assertArgIsSEL)
-    failUnlessResultIsBOOL = _deprecate(assertResultIsBOOL)
-    failUnlessArgIsBOOL = _deprecate(assertArgIsBOOL)
-    failUnlessArgIsFixedSize = _deprecate(assertArgIsFixedSize)
-    failUnlessArgSizeInArg = _deprecate(assertArgSizeInArg)
-    failUnlessResultSizeInArg = _deprecate(assertResultSizeInArg)
-    failUnlessArgIsOut = _deprecate(assertArgIsOut)
-    failUnlessArgIsInOut = _deprecate(assertArgIsInOut)
-    failUnlessArgIsIn = _deprecate(assertArgIsIn)
-    failUnlessStartswith = _deprecate(assertStartswith)
-    failUnlessHasAttr = _deprecate(assertHasAttr)
-    failIfHasAttr = _deprecate(assertNotHasAttr)
-    failUnlessIsInstance = _deprecate(assertIsInstance)
-    failIfIsInstance = _deprecate(assertIsNotInstance)
-    failUnlessIsIn = _deprecate(assertIsIn)
-    failIfIsNotIn = _deprecate(assertIsIn)
-    failUnlessIsNotIn = _deprecate(assertIsNotIn)
-    failIfIsIn = _deprecate(assertIsNotIn)
-    assertNotIsInstance = _deprecate(assertIsNotInstance)
-    assertIsObject = _deprecate(assertIs)
-    assertIsNotObject = _deprecate(assertIsNot)
-
-    del _deprecate
 
 main = _unittest.main
 
 if hasattr(_unittest, 'expectedFailure'):
     expectedFailure = _unittest.expectedFailure
-else:
+
+else: # pragma: no cover (py2.6)
+
     def expectedFailure(func):
         def test(self):
             try:
 
         return test
 
+# XXX: filterwarnings relies on implementation details of
+#      the warnings module
 class filterWarnings (object):
     def __init__(self, kind, category):
         self._kind = kind

pyobjc-core/Lib/objc/_bridges.py

 from objc import _objc
 import struct
 import sys
+import collections
 
 __all__ = [ 'registerListType', 'registerMappingType' ]
 
-BRIDGED_STRUCTURES = {}
-BRIDGED_STRUCTURES2 = {}
-BRIDGED_TYPES = []
-
 def registerListType(type):
     """
     Register 'type' as a list-like type that will be proxied
     OC_PythonDictionary.depythonifyTable().append(type)
 
 
-def _bridgePythonTypes():
-    # Python to Obj-C
-    OC_PythonObject = lookUpClass('OC_PythonObject')
-    try:
-        if BRIDGED_TYPES:
-            OC_PythonObject.depythonifyTable().extend(BRIDGED_TYPES)
-        if BRIDGED_STRUCTURES:
-            OC_PythonObject.pythonifyStructTable().update(BRIDGED_STRUCTURES)
-    except AttributeError:
-        pass
-
-if sys.version_info[0] > 2:
+if sys.version_info[0] > 2: # pragma: no cover (py3k)
     registerListType(type(range(1)))
 
 else:
     registerListType(xrange)
 
-
-_bridgePythonTypes()
+registerListType(collections.Sequence)
+registerMappingType(collections.Mapping)

pyobjc-core/Lib/objc/_bridgesupport.py

     def _as_bytes(value):
         return value
 
-    def _as_string(value):
-        return value
+else: # pragma: no cover (py3k)
 
-else:
     _unicode = str
 
     def _as_bytes(value):
             return value
         return value.encode('ascii')
 
-    def _as_string(value):
-        return value.decode('ascii')
-
 class _BridgeSupportParser (object):
     """
     Parser for the bridge support file format. 

pyobjc-core/Lib/objc/_compat.py

-__all__ = ['runtime', 'pluginBundle', 'registerPlugin', 'splitStruct']
+__all__ = ['runtime', 'pluginBundle', 'registerPlugin', 'splitStruct', '_loadFunctionList']
 import warnings
 
 class Runtime:
     only after it has been registered with registerPlugin
     """
     warnings.warn("Deprecated: use currentBundle()", DeprecationWarning)
-    from Foundation import NSBundle
+    import objc
+    NSBundle = objc.lookUpClass('NSBundle')
     return NSBundle.bundleWithPath_(_PLUGINS[pluginName])
 
 def splitStruct(value):

pyobjc-core/Lib/objc/_descriptors.py

             raise ValueError("No selector argument with type information")
 
     else:
-        signature = callable.__metadata__().arguments[idx]['type_of_sel']
+        try:
+            signature = callable.__metadata__()['arguments'][argIndex]['sel_of_type']
+        except (IndexError, KeyError):
+            raise ValueError("Not a selector argument with type information")
 
     def addSignature(function): 
         return selector(function, signature=signature)

pyobjc-core/Lib/objc/_dyld.py

         return unicode(s, 'utf8')
     return s
 
-def injectSuffixes(iterator):
+def inject_suffixes(iterator):
     suffix = ensure_unicode(os.environ.get('DYLD_IMAGE_SUFFIX', None))
     if suffix is None:
         return iterator
                 )
 
 
-    for f in injectSuffixes(_search()):
+    for f in inject_suffixes(_search()):
         if os.path.exists(f):
             return f
     # raise ..
         ))
         for path in spath.split(':'):
             yield os.path.join(path, libname)
-    for f in injectSuffixes(_search()):
+    for f in inject_suffixes(_search()):
         if os.path.exists(f):
             return f
     raise ValueError("dylib %s could not be found" %(filename,))
 
-# Python version upto (at least) 2.5 do not propertly convert unicode
-# arguments to os.readlink, the code below works around that.
-if sys.version_info[:3] >= (2,6,0):
-    _realpath = os.path.realpath
-
-else:
-    def _realpath(path):
-        """
-        Unicode-safe version of os.path.realpath.
-        """
-        if isinstance(path, unicode):
-            fsenc = sys.getfilesystemencoding()
-            return os.path.realpath(path.encode(fsenc)).decode(fsenc)
-
-        return os.path.realpath(path)
-
 
 def dyld_find(filename):
     """Generic way to locate a dyld framework or dyld"""
-    # if they passed in a framework directory, not a mach-o file
-    # then go ahead and look where one would expect to find the mach-o
-#    filename = ensure_unicode(filename)
-#    if os.path.isdir(filename):
-#        filename = os.path.join(
-#            filename,
-#            os.path.basename(filename)[:-len(os.path.splitext(filename)[-1])]
-#        )
-    filename = _realpath(filename)
+    filename = os.path.realpath(filename)
     res = infoForFramework(filename)
     if res:
         framework_loc, framework_name, version = res

pyobjc-core/Lib/objc/_functions.py

-__all__ = [ 'signature']
-
-import os
-import sys
-
-def signature(signature, **kw):
-    """
-    A Python method decorator that allows easy specification
-    of Objective-C selectors.
-
-    Usage::
-        
-        @objc.signature('i@:if')
-        def methodWithX_andY_(self, x, y):
-            return 0
-    """
-    import warnings
-    warnings.warn("Usage objc.typedSelector instead of objc.signature", DeprecationWarning)
-    from objc._objc import selector
-    kw['signature'] = signature
-    def makeSignature(func):
-        return selector(func, **kw)
-    return makeSignature

pyobjc-core/Lib/objc/_pycoder.py

 
 from pickle import PicklingError, UnpicklingError, whichmodule
 
-if hasattr(sys, 'intern'):
-    intern = sys.intern
 
-if sys.version_info[0] == 3:
+if sys.version_info[0] == 3: # pragma: no cover (py3k)
     unicode = str
     long = int
+    intern = sys.intern
 
 
 # FIXME: This requires manual wrappers from the Foundation bindings

pyobjc-core/Lib/objc/_pythonify.py

     def __reduce__(self):
         return (float, (float(self),))
 
+base_class = int if sys.version_info[0] >= 3 else long
+
+class OC_PythonLong(base_class):
+
+    def __new__(cls, obj, value):
+        self = base_class.__new__(cls, value)
+        self.__pyobjc_object__ = obj
+        return self
+
+    __class__ = property(lambda self: self.__pyobjc_object__.__class__)
+
+    def __getattr__(self, attr):
+        return getattr(self.__pyobjc_object__, attr)
+
+    # The long type doesn't support __slots__ on subclasses, fake
+    # one part of the effect of __slots__: don't allow setting of attributes.
+    def __setattr__(self, attr, value):
+        if attr != '__pyobjc_object__':
+            raise AttributeError("'%s' object has no attribute '%s')"%(self.__class__.__name__, attr))
+        self.__dict__['__pyobjc_object__'] = value
+
+    def __reduce__(self):
+        return (base_class, (base_class(self),))
+
+
 if sys.version_info[0] == 2:
-    class OC_PythonLong(long):
-
-        def __new__(cls, obj, value):
-            self = long.__new__(cls, value)
-            self.__pyobjc_object__ = obj
-            return self
-
-        __class__ = property(lambda self: self.__pyobjc_object__.__class__)
-
-        def __getattr__(self, attr):
-            return getattr(self.__pyobjc_object__, attr)
-
-        # The long type doesn't support __slots__ on subclasses, fake
-        # one part of the effect of __slots__: don't allow setting of attributes.
-        def __setattr__(self, attr, value):
-            if attr != '__pyobjc_object__':
-                raise AttributeError("'%s' object has no attribute '%s')"%(self.__class__.__name__, attr))
-            self.__dict__['__pyobjc_object__'] = value
-
-        def __reduce__(self):
-            return (long, (long(self),))
-
     class OC_PythonInt(int):
         __slots__=('__pyobjc_object__',)
 
         def __reduce__(self):
             return (int, (int(self),))
 
-else:
-    class OC_PythonLong(int):
-
-        def __new__(cls, obj, value):
-            self = int.__new__(cls, value)
-            self.__pyobjc_object__ = obj
-            return self
-
-        __class__ = property(lambda self: self.__pyobjc_object__.__class__)
-
-        def __getattr__(self, attr):
-            return getattr(self.__pyobjc_object__, attr)
-
-        # The long type doesn't support __slots__ on subclasses, fake
-        # one part of the effect of __slots__: don't allow setting of attributes.
-        def __setattr__(self, attr, value):
-            if attr != '__pyobjc_object__':
-                raise AttributeError("'%s' object has no attribute '%s')"%(self.__class__.__name__, attr))
-            self.__dict__['__pyobjc_object__'] = value
-
-        if sys.version_info[0] == 2:
-            def __reduce__(self):
-                return (long, (long(self),))
-        else:
-            def __reduce__(self):
-                return (int, (int(self),))
 
 NSNumber = _objc.lookUpClass('NSNumber')
 NSDecimalNumber = _objc.lookUpClass('NSDecimalNumber')
 def numberWrapper(obj):
     if isinstance(obj, NSDecimalNumber):
         return obj
-        # ensure that NSDecimal is around
-        global Foundation
-        if Foundation is None:
-            import Foundation
-        # return NSDecimal
-        return Foundation.NSDecimal(obj)
+
     try:
         tp = obj.objCType()
     except AttributeError:
         import warnings
-        warnings.warn(RuntimeWarning, "NSNumber instance doesn't implement objCType? %r" % (obj,))
+        warnings.warn("NSNumber instance doesn't implement objCType? %r" % (obj,), RuntimeWarning)
         return obj
+
     if tp in b'qQLfd':
         if tp == b'q':
             return OC_PythonLong(obj, obj.longLongValue())
             return OC_PythonFloat(obj, obj.doubleValue())
     elif sys.version_info[0] == 2:
         return OC_PythonInt(obj, obj.longValue())
-    else:
+    else: # pragma: no cover (py3k)
         return OC_PythonLong(obj, obj.longValue())
 
 _objc._setNSNumberWrapper(numberWrapper)

pyobjc-core/NEWS.txt

      The names op submodules of objc are implementation details, don't import
      them directly.
 
+- The optional argument for the decorator :func:`objc.selectorFor` was broken
+
+- The :class:`PyObjCTools.KeyValueCoding.kvc` wrapper `__setattr__` wrapper 
+  incorrectly set attributes on itself as well as on the wrapped object (the latter
+  using Key-Value Coding)
+
+- Renamed (private) function injectSuffixes to inject_suffixes to match the
+  other code in objc._dyld.
+
+- Slight restructuring of objc._pythonify to reduce code duplication between the
+  python 2.x and python 3.x cases. 
+
+- Removed deprecated methods from PyObjCTools.TestSupport
+
+- :class:`collections.Sequence` objects are now automaticly proxied as NSArray 
+  instances
+
+- :class:`collections.Mapping` objects are now automaticly proxies as NSDictionary
+  instances
+
+- Removed some objects and functions from objc._bridges that weren't public
+  and weren't used by PyObjC itself:
+
+  - *BRIDGED_STRUCTURES*: mapping of python type to proxy class
+  - *BRIDGED_STRUCTURES2*: mapping of python type to proxy class (not used at all)
+  - *BRIDGED_TYPES*: mapping of python type to proxy class
+  - *_bridgePythonTypes*: uses BRIDGED_STRUCTURES and BRIDGED_TYPES to update bridge data
+
+  *_bridgePythonTypes* was called unconditionally, but never did anything because
+  the data structures were empty and no code adds anything to them.
+
 - Improved documentation
 
 
-
 Version 2.4.1
 -------------
 

pyobjc-core/PyObjCTest/test_bridgesupport.py

 import os
 import re
 
+import xml.etree.ElementTree as ET 
+
+
 try:
     basestring
 except NameError:
 
 IDENTIFIER=re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$")
 
+class TestXMLFile (TestCase):
+    def testInvalidToplevel(self):
+        self.assertRaises(objc.error, bridgesupport._BridgeSupportParser, '<signatures2></signatures2>', 'Cocoa')
+        self.assertRaises(ET.ParseError, bridgesupport._BridgeSupportParser, '<signatures2></signatures>', 'Cocoa')
+
 class TestSystemBridgeSupport (TestCase):
 
     def iter_framework_dir(self, framework_dir):

pyobjc-core/PyObjCTest/test_callbacks.py

+from PyObjCTools.TestSupport import *
+import objc
+
+
+objc.registerMetaDataForSelector(
+    b"OC_CallbackTest", b"selWithSEL:SEL:andObject:", {
+        "arguments": {
+            2:  {
+                "sel_of_type":  b"q@:q",
+            },
+            3:  {
+                "sel_of_type": b"v@:@@^v",
+            }
+        }
+    }
+)
+
+class OC_CallbackTest (objc.lookUpClass("NSObject")):
+    @objc.typedSelector(b"v@:" + objc._C_SEL + objc._C_SEL + b"@")
+    def selWithSEL_SEL_andObject_(self, s1, s2, o):
+        pass
+
+    def selWithoutSEL_(self, o):
+        pass
+
+
+class TestClosure (TestCase):
+    # tests for objc._makeClosure
+    # (note: as the name indicates _makeClosure is not a public API)
+    def testCallbackForUnsupported(self):
+        def function(arg):
+            pass
+
+        self.assertRaises(TypeError, objc._makeClosure, function, dir, -1)
+        self.assertRaises(TypeError, objc._makeClosure, function, function, -1)
+        self.assertRaises(TypeError, objc._makeClosure, function, 42, -1)
+        self.assertRaises(ValueError, objc._makeClosure, function, OC_CallbackTest.selWithSEL_SEL_andObject_,  -1)
+        self.assertRaises(ValueError, objc._makeClosure, function, OC_CallbackTest.selWithoutSEL_,  -1)
+
+    # create and use closure for 
+    # - function
+    # - selector
+    # - different kinds of arguments
+
+
+class TestCallbackFor (TestCase):
+    # tests for objc.callbackFor
+    def testCallbackForUnsupported(self):
+        def function(arg):
+            pass
+
+        self.assertRaises(TypeError, objc.callbackFor(dir), function)
+        self.assertRaises(TypeError, objc.callbackFor(function), function)
+        self.assertRaises(TypeError, objc.callbackFor(42), function)
+        self.assertRaises(ValueError, objc.callbackFor(OC_CallbackTest.selWithSEL_SEL_andObject_), function)
+        self.assertRaises(ValueError, objc.callbackFor(OC_CallbackTest.selWithoutSEL_), function)
+
+
+
+class TestSelectorFor (TestCase):
+    # tests for objc.selectorFor
+    def test_consistency(self):
+        self.assertEqual(OC_CallbackTest.selWithSEL_SEL_andObject_.signature,
+                b"v@:::@")
+
+    def testNotSelector(self):
+        self.assertRaises(ValueError, objc.selectorFor, OC_CallbackTest.selWithSEL_SEL_andObject_, 4)
+        self.assertRaises(ValueError, objc.selectorFor, OC_CallbackTest.selWithSEL_SEL_andObject_, 8)
+        self.assertRaises(ValueError, objc.selectorFor, OC_CallbackTest.selWithoutSEL_)
+
+    def testDefault(self):
+        @objc.selectorFor(OC_CallbackTest.selWithSEL_SEL_andObject_)
+        def selector(self, a):
+            pass
+
+        self.assertEqual(selector.signature, b"q@:q")
+
+    def testExplicit(self):
+
+        @objc.selectorFor(OC_CallbackTest.selWithSEL_SEL_andObject_, 2)
+        def selector(self, a):
+            pass
+
+        self.assertEqual(selector.signature, b"q@:q")
+
+        @objc.selectorFor(OC_CallbackTest.selWithSEL_SEL_andObject_, 3)
+        def selector(self, a):
+            pass
+
+        self.assertEqual(selector.signature, b"v@:@@^v")
+
+
+if __name__ == "__main__":
+    main()

pyobjc-core/PyObjCTest/test_dyld.py

+from PyObjCTools.TestSupport import *
+import os
+
+import objc._dyld as dyld
+
+try:
+    unicode
+except NameError:
+    unicode = str
+
+
+class TestDyld (TestCase):
+    def setUp(self):
+        self.orig_environ = os.environ
+        os.environ = os.environ.copy()
+
+    def tearDown(self):
+        os.environ = self.orig_environ
+
+    def test_inject_suffixes(self):
+        if 'DYLD_IMAGE_SUFFIX' in os.environ:
+            del os.environ['DYLD_IMAGE_SUFFIX']
+
+        
+        # No suffix
+        paths = [ '/usr/lib/libSystem.dylib',
+                '/lib/libfoo.3.dylib',
+                '/System/Library/Frameworks/CorePython.framework/Versions/B/CorePython',
+                '/System/Library/Frameworks/CorePython.framework/CorePython',
+        ]
+        self.assertEqual(list(dyld.inject_suffixes(iter(paths))), paths)
+        self.assertIs(dyld.inject_suffixes(paths), paths)
+
+        os.environ['DYLD_IMAGE_SUFFIX'] = '_DEBUG'
+        self.maxDiff = None
+        self.assertEqual(list(dyld.inject_suffixes(iter(paths))), [ 
+                '/usr/lib/libSystem_DEBUG.dylib',
+                '/usr/lib/libSystem.dylib',
+                '/lib/libfoo.3_DEBUG.dylib',
+                '/lib/libfoo.3.dylib',
+                '/System/Library/Frameworks/CorePython.framework/Versions/B/CorePython_DEBUG',
+                '/System/Library/Frameworks/CorePython.framework/Versions/B/CorePython',
+                '/System/Library/Frameworks/CorePython.framework/CorePython_DEBUG',
+                '/System/Library/Frameworks/CorePython.framework/CorePython',
+        ])
+
+
+    def test_ensure_unicode(self):
+        v = dyld.ensure_unicode("foo")
+        self.assertIsInstance(v, unicode)
+        self.assertEqual(v, b"foo".decode("utf-8"))
+
+        v = dyld.ensure_unicode(b"foo")
+        self.assertIsInstance(v, unicode)
+        self.assertEqual(v, b"foo".decode("utf-8"))
+
+        v = dyld.ensure_unicode(b"foo".decode("utf-8"))
+        self.assertIsInstance(v, unicode)
+        self.assertEqual(v, b"foo".decode("utf-8"))
+
+        self.assertRaises(UnicodeError, dyld.ensure_unicode, b"\xff\xff")
+
+    def test_dyld_library(self):
+        for k in ('DYLD_LIBRARY_PATH', 'DYLD_FALLBACK_LIBRARY_PATH', 'DYLD_IMAGE_SUFFIX'):
+            if k in os.environ:
+                del os.environ[k]
+
+        orig = os.path.exists
+        try:
+            os.path.exists = lambda fn: l.append(fn)
+
+            l = []
+            self.assertRaises(ValueError, dyld.dyld_library, '/usr/lib/libSystem.dylib', 'libXSystem.dylib')
+            self.assertEqual(l, [
+                '/usr/lib/libSystem.dylib',
+                os.path.expanduser('~/lib/libXSystem.dylib'),
+                '/usr/local/lib/libXSystem.dylib',
+                '/lib/libXSystem.dylib',
+                '/usr/lib/libXSystem.dylib',
+            ])
+
+            os.environ['DYLD_IMAGE_SUFFIX'] = '_debug'
+            l = []
+            self.assertRaises(ValueError, dyld.dyld_library, '/usr/lib/libSystem.dylib', 'libXSystem.dylib')
+            self.assertEqual(l, [
+                '/usr/lib/libSystem_debug.dylib',
+                '/usr/lib/libSystem.dylib',
+                os.path.expanduser('~/lib/libXSystem_debug.dylib'),
+                os.path.expanduser('~/lib/libXSystem.dylib'),
+                '/usr/local/lib/libXSystem_debug.dylib',
+                '/usr/local/lib/libXSystem.dylib',
+                '/lib/libXSystem_debug.dylib',
+                '/lib/libXSystem.dylib',
+                '/usr/lib/libXSystem_debug.dylib',
+                '/usr/lib/libXSystem.dylib',
+            ])
+
+            del os.environ['DYLD_IMAGE_SUFFIX']
+
+            os.environ['DYLD_LIBRARY_PATH'] = '/slib:/usr/slib'
+            l = []
+            self.assertRaises(ValueError, dyld.dyld_library, '/usr/lib/libSystem.dylib', 'libXSystem.dylib')
+            self.assertEqual(l, [
+                '/slib/libXSystem.dylib',
+                '/usr/slib/libXSystem.dylib',
+                '/usr/lib/libSystem.dylib',
+                os.path.expanduser('~/lib/libXSystem.dylib'),
+                '/usr/local/lib/libXSystem.dylib',
+                '/lib/libXSystem.dylib',
+                '/usr/lib/libXSystem.dylib',
+            ])
+            del os.environ['DYLD_LIBRARY_PATH']
+
+            os.environ['DYLD_FALLBACK_LIBRARY_PATH'] = '/slib:/usr/slib'
+            l = []
+            self.assertRaises(ValueError, dyld.dyld_library, '/usr/lib/libSystem.dylib', 'libXSystem.dylib')
+            self.assertEqual(l, [
+                '/usr/lib/libSystem.dylib',
+                '/slib/libXSystem.dylib',
+                '/usr/slib/libXSystem.dylib',
+            ])
+            del os.environ['DYLD_FALLBACK_LIBRARY_PATH']
+
+            os.environ['DYLD_LIBRARY_PATH'] = "/lib2:/lib3"
+            os.environ['DYLD_FALLBACK_LIBRARY_PATH'] = "/lib4:/lib5"
+            os.environ['DYLD_IMAGE_SUFFIX'] = "_profile"
+
+            l = []
+            self.assertRaises(ValueError, dyld.dyld_library, '/usr/lib/libSystem.dylib', 'libXSystem.dylib')
+            self.assertEqual(l, [
+                '/lib2/libXSystem_profile.dylib',
+                '/lib2/libXSystem.dylib',
+                '/lib3/libXSystem_profile.dylib',
+                '/lib3/libXSystem.dylib',
+                '/usr/lib/libSystem_profile.dylib',
+                '/usr/lib/libSystem.dylib',
+                '/lib4/libXSystem_profile.dylib',
+                '/lib4/libXSystem.dylib',
+                '/lib5/libXSystem_profile.dylib',
+                '/lib5/libXSystem.dylib',
+            ])
+            del os.environ['DYLD_LIBRARY_PATH']
+            del os.environ['DYLD_FALLBACK_LIBRARY_PATH']
+            del os.environ['DYLD_IMAGE_SUFFIX']
+
+        finally:
+            os.path.exists = orig
+
+
+        self.assertEqual(dyld.dyld_library('/usr/lib/libSystem.dylib', 'libXSystem.dylib'), '/usr/lib/libSystem.dylib')
+
+        os.environ['DYLD_IMAGE_SUFFIX'] = "_debug"
+        self.assertEqual(dyld.dyld_library('/usr/lib/libSystem.dylib', 'libSystem.dylib'), '/usr/lib/libSystem_debug.dylib')
+
+    def test_dyld_framework(self):
+        for k in ('DYLD_FRAMEWORK_PATH', 'DYLD_FALLBACK_FRAMEWORK_PATH', 'DYLD_IMAGE_SUFFIX'):
+            if k in os.environ:
+                del os.environ[k]
+
+        orig = os.path.exists
+        try:
+            os.path.exists = lambda fn: l.append(fn)
+
+            self.maxDiff = None
+
+            l = []
+            self.assertRaises(ImportError, dyld.dyld_framework, "/System/Library/Cocoa.framework/Cocoa", "XCocoa") 
+            self.assertEqual(l, [
+                "/System/Library/Cocoa.framework/Cocoa",
+                os.path.expanduser("~/Library/Frameworks/XCocoa.framework/XCocoa"),
+                "/Library/Frameworks/XCocoa.framework/XCocoa",
+                "/Network/Library/Frameworks/XCocoa.framework/XCocoa",
+                "/System/Library/Frameworks/XCocoa.framework/XCocoa",
+            ])
+
+            os.environ["DYLD_IMAGE_SUFFIX"] = "_profile"
+            l = []
+            self.assertRaises(ImportError, dyld.dyld_framework, "/System/Library/Cocoa.framework/Cocoa", "XCocoa") 
+            self.assertEqual(l, [
+                "/System/Library/Cocoa.framework/Cocoa_profile",
+                "/System/Library/Cocoa.framework/Cocoa",
+                os.path.expanduser("~/Library/Frameworks/XCocoa.framework/XCocoa_profile"),
+                os.path.expanduser("~/Library/Frameworks/XCocoa.framework/XCocoa"),
+                "/Library/Frameworks/XCocoa.framework/XCocoa_profile",
+                "/Library/Frameworks/XCocoa.framework/XCocoa",
+                "/Network/Library/Frameworks/XCocoa.framework/XCocoa_profile",
+                "/Network/Library/Frameworks/XCocoa.framework/XCocoa",
+                "/System/Library/Frameworks/XCocoa.framework/XCocoa_profile",
+                "/System/Library/Frameworks/XCocoa.framework/XCocoa",
+            ])
+            del os.environ["DYLD_IMAGE_SUFFIX"]
+
+            os.environ["DYLD_FRAMEWORK_PATH"] = "/Projects/Frameworks:/Company"
+            l = []
+            self.assertRaises(ImportError, dyld.dyld_framework, "/System/Library/Cocoa.framework/Cocoa", "XCocoa") 
+            self.assertEqual(l, [
+                "/Projects/Frameworks/XCocoa.framework/XCocoa",
+                "/Company/XCocoa.framework/XCocoa",
+                "/System/Library/Cocoa.framework/Cocoa",
+                os.path.expanduser("~/Library/Frameworks/XCocoa.framework/XCocoa"),
+                "/Library/Frameworks/XCocoa.framework/XCocoa",
+                "/Network/Library/Frameworks/XCocoa.framework/XCocoa",
+                "/System/Library/Frameworks/XCocoa.framework/XCocoa",
+            ])
+            del os.environ["DYLD_FRAMEWORK_PATH"]
+
+            os.environ["DYLD_FALLBACK_FRAMEWORK_PATH"] = "/Projects/Frameworks:/Company"
+            l = []
+            self.assertRaises(ImportError, dyld.dyld_framework, "/System/Library/Cocoa.framework/Cocoa", "XCocoa") 
+            self.assertEqual(l, [
+                "/System/Library/Cocoa.framework/Cocoa",
+                "/Projects/Frameworks/XCocoa.framework/XCocoa",
+                "/Company/XCocoa.framework/XCocoa",
+            ])
+            del os.environ["DYLD_FALLBACK_FRAMEWORK_PATH"]
+
+            os.environ["DYLD_FRAMEWORK_PATH"] = "/Prefix1:/Prefix2"
+            os.environ["DYLD_FALLBACK_FRAMEWORK_PATH"] = "/Suffix1:/Suffix2"
+            os.environ["DYLD_IMAGE_SUFFIX"] = "_debug"
+
+            l = []
+            self.assertRaises(ImportError, dyld.dyld_framework, "/System/Library/Cocoa.framework/Cocoa", "XCocoa", "B") 
+            self.assertEqual(l, [
+                "/Prefix1/XCocoa.framework/Versions/B/XCocoa_debug",
+                "/Prefix1/XCocoa.framework/Versions/B/XCocoa",
+                "/Prefix2/XCocoa.framework/Versions/B/XCocoa_debug",
+                "/Prefix2/XCocoa.framework/Versions/B/XCocoa",
+                "/System/Library/Cocoa.framework/Cocoa_debug",
+                "/System/Library/Cocoa.framework/Cocoa",
+                "/Suffix1/XCocoa.framework/Versions/B/XCocoa_debug",
+                "/Suffix1/XCocoa.framework/Versions/B/XCocoa",
+                "/Suffix2/XCocoa.framework/Versions/B/XCocoa_debug",
+                "/Suffix2/XCocoa.framework/Versions/B/XCocoa",
+            ])
+            del os.environ["DYLD_FRAMEWORK_PATH"]
+            del os.environ["DYLD_FALLBACK_FRAMEWORK_PATH"]
+            del os.environ["DYLD_IMAGE_SUFFIX"]
+            
+
+        finally:
+            os.path.exists = orig
+
+        self.assertEqual(dyld.dyld_framework("/System/Library/Cocoa.framework/Cocoa", "Cocoa"), "/System/Library/Frameworks/Cocoa.framework/Cocoa")
+        self.assertEqual(dyld.dyld_framework("/System/Library/Cocoa.framework/Cocoa", "Cocoa", "A"), "/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa")
+
+    def test_readlink(self):
+        # Some python versions had a readlink version that doesn't work with unicode 
+        # input, ensure that we're not one one of those
+        self.assertEqual(os.path.realpath("/usr/lib/libSystem.dylib"), "/usr/lib/libSystem.B.dylib")
+        self.assertEqual(os.path.realpath(b"/usr/lib/libSystem.dylib"), b"/usr/lib/libSystem.B.dylib")
+        self.assertEqual(os.path.realpath("/usr/lib/libSystem.dylib".decode('utf-8')), "/usr/lib/libSystem.B.dylib".decode('utf-8'))
+
+    def test_dyld_find(self):
+        self.assertEqual(dyld.dyld_find('Cocoa.framework'), '/System/Library/Frameworks/Cocoa.framework/Cocoa')
+        self.assertEqual(dyld.dyld_find('libSystem.dylib'), '/usr/lib/libSystem.dylib')
+
+    def test_pathForFramework(self):
+        self.assertEqual(dyld.pathForFramework('Cocoa.framework'), '/System/Library/Frameworks/Cocoa.framework')
+        self.assertRaises(ImportError, dyld.pathForFramework, 'Foo.framework')
+
+if __name__ == "__main__":
+    main()

pyobjc-core/PyObjCTest/test_keyvaluecoding.py

+# Tests for PyObjCTools.KeyValueCoding
+from PyObjCTools.TestSupport import *
+
+from PyObjCTools import KeyValueCoding
+import operator
+
+
+class TestHelpers (TestCase):
+    def test_msum(self):
+        self.assertEqual(KeyValueCoding.msum([1, 1e100, 1, -1e100] * 10000), 20000)
+        self.assertEqual(KeyValueCoding.msum([1.0, 2.0, 3.0, 4.0]), 10.0)
+
+    def test_keyCaps(self):
+        self.assertEqual(KeyValueCoding.keyCaps("attr"), "Attr")
+        self.assertEqual(KeyValueCoding.keyCaps("Attr"), "Attr")
+        self.assertEqual(KeyValueCoding.keyCaps("AttR"), "AttR")
+        self.assertEqual(KeyValueCoding.keyCaps("attr_with_value"), "Attr_with_value")
+
+        self.assertEqual(KeyValueCoding.keyCaps(b"attr"), b"Attr")
+        self.assertEqual(KeyValueCoding.keyCaps(b"Attr"), b"Attr")
+        self.assertEqual(KeyValueCoding.keyCaps(b"AttR"), b"AttR")
+        self.assertEqual(KeyValueCoding.keyCaps(b"attr_with_value"), b"Attr_with_value")
+
+
+class TestArrayOperators (TestCase):
+    def test_missing(self):
+        self.fail("Missing tests for ArrayOperators")
+
+class TestPythonObject (TestCase):
+    def test_missing(self):
+        self.fail("Missing tests for KVC on Python objects")
+
+
+class TestObjectiveCObject (TestCase):
+    def test_missing(self):
+        self.fail("Missing tests for KVC on Cocoa objects")
+
+
+class TestMixed (TestCase):
+    def test_missing(self):
+        self.fail("Test keypath operations on mixed graphs")
+
+
+class TestKVCHelper (TestCase):
+    def setUp(self):
+        self._orig = {
+            'getKey': KeyValueCoding.getKey,
+            'setKey': KeyValueCoding.setKey,
+            'getKeyPath': KeyValueCoding.getKeyPath,
+            'setKeyPath': KeyValueCoding.setKeyPath,
+        }
+        self._trace = []
+        def getKey(obj, k):
+            self._trace.append(('get', obj, k))
+        def setKey(obj, k, v):
+            self._trace.append(('set', obj, k, v))
+        def getKeyPath(obj, k):
+            self._trace.append(('get-path', obj, k))
+        def setKeyPath(obj, k, v):
+            self._trace.append(('set-path', obj, k, v))
+        KeyValueCoding.getKey = getKey
+        KeyValueCoding.setKey = setKey
+        KeyValueCoding.getKeyPath = getKeyPath
+        KeyValueCoding.setKeyPath = setKeyPath
+
+
+    def tearDown(self):
+        for k in self._orig:
+            setattr(KeyValueCoding, k, self._orig[k])
+
+    def test_repr(self):
+        for o in [
+                object(), 42, "42", b"42", b"42".decode('latin1')
+                ]:
+            self.assertEqual(repr(KeyValueCoding.kvc(o)), repr(o))
+
+    def test_attribute_access(self):
+        v = object()
+        o = KeyValueCoding.kvc(v)
+        o.key
+        o.key2
+        getattr(o, "key3.key4")
+        self.assertEqual(self._trace,  [
+            ('get', v, 'key'),
+            ('get', v, 'key2'),
+            ('get', v, 'key3.key4'),
+        ])
+        self._trace[:] = []
+
+        o.key = 42
+        setattr(o, "key3.key4", 99)
+        self.assertEqual(self._trace,  [
+            ('set', v, 'key', 42),
+            ('set', v, 'key3.key4', 99),
+        ])
+        self._trace[:] = []
+
+        class Object (object):
+            pass
+
+        v = Object()
+        o = KeyValueCoding.kvc(v)
+        o.key = 42
+        o._key = 99
+        self.assertEqual(self._trace,  [
+            ('set', v, 'key', 42),
+        ])
+        self.assertEqual(o._key, 99)
+        self.assertIn('_key', o.__dict__)
+        self.assertNotIn('key', o.__dict__)
+
+
+    def test_item_access(self):
+        v = object()
+        o = KeyValueCoding.kvc(v)
+        o['key']
+        o['key2']
+        o['key3.key4']
+        self.assertEqual(self._trace,  [
+            ('get-path', v, 'key'),
+            ('get-path', v, 'key2'),
+            ('get-path', v, 'key3.key4'),
+        ])
+        self._trace[:] = []
+
+        o["key"] = 42
+        o["key3.key4"] = 99
+        self.assertEqual(self._trace,  [
+            ('set-path', v, 'key', 42),
+            ('set-path', v, 'key3.key4', 99),
+        ])
+        self._trace[:] = []
+
+
+        self.assertRaises(TypeError, operator.getitem, o, 42)
+        self.assertRaises(TypeError, operator.setitem, o, 42, 99)
+
+if __name__ == "__main__":
+    main()

pyobjc-core/PyObjCTest/test_number_proxy.py

 from PyObjCTest.pythonnumber import OC_TestNumber
 import objc
 
+
 if sys.version_info[0] == 3:
     unicode = str
 
             self.assertIsNotInstance(v, OC_PythonNumber)
             self.assertIs(OC_TestNumber.numberClass_(v), NSCFNumber)
 
+    def testDecimal(self):
+        NSDecimalNumber = objc.lookUpClass("NSDecimalNumber")
+        v = NSDecimalNumber.numberWithInt_(10)
+        self.assertIsInstance(v, NSDecimalNumber)
+
+        from objc._pythonify import numberWrapper
+        o = numberWrapper(v)
+        self.assertIs(o, v)
+
+    def testLongValue(self):
+        v = NSNumber.numberWithUnsignedLongLong_(2 ** 63 + 5000)
+        self.assertIsInstance(v, long)
+
+        self.assertEqual(v.description(), str(2**63+5000))
+
+        self.assertIsNot(type(v), long)
+
+        self.assertRaises(AttributeError, setattr, v, 'x', 42)
+
+    def testEdgeCases(self):
+        from objc._pythonify import numberWrapper
+
+        n = objc.lookUpClass('NSObject').alloc().init()
+
+        with filterWarnings("error", RuntimeWarning):
+            self.assertRaises(RuntimeWarning, numberWrapper, n)
+
+        with filterWarnings("ignore", RuntimeWarning):
+            self.assertIs(numberWrapper(n), n)
+
+
+        # Fake number class, to ensure that all of 
+        # numberWrapper can be tested with a 64-bit runtime
+        class Number (objc.lookUpClass("NSObject")):
+            def objCType(self):
+                return objc._C_INT
+
+            def longValue(self):
+                return 42
+
+        n = Number.alloc().init()
+        v = numberWrapper(n)
+        self.assertEqual(v, 42)
+        self.assertIs(v.__pyobjc_object__, n)
+
+    def testPickling(self):
+        v = {
+            'long': NSNumber.numberWithUnsignedLongLong_(2 ** 63 + 5000),
+            'int':  NSNumber.numberWithInt_(42),
+            'float': NSNumber.numberWithDouble_(2.0),
+        }
+        import pickle
+        data = pickle.dumps(v)
+
+        w = pickle.loads(data)
+        self.assertEqual(w, {
+            'long': 2**63 + 5000,
+            'int': 42,
+            'float': 2.0,
+        })
+
+        for o in v.values():
+            self.assertTrue(hasattr(o, '__pyobjc_object__'))
+
+        for o in w.values():
+            self.assertFalse(hasattr(o, '__pyobjc_object__'))
+
     def testShortConversions(self):
         v = NSNumber.numberWithShort_(42)
 
+        self.assertEqual(v.stringValue(), '42')
+
         self.assertEqual(OC_TestNumber.numberAsBOOL_(v), 1)
         self.assertEqual(OC_TestNumber.numberAsChar_(v), 42)
         self.assertEqual(OC_TestNumber.numberAsShort_(v), 42)
         self.assertEqual(OC_TestNumber.numberAsFloat_(v), 42.0)
         self.assertEqual(OC_TestNumber.numberAsDouble_(v), 42.0)
 
+
     def testIntConversions(self):
         v = NSNumber.numberWithInt_(42)
 
+        self.assertEqual(v.stringValue(), '42')
+
         self.assertEqual(OC_TestNumber.numberAsBOOL_(v), 1)
         self.assertEqual(OC_TestNumber.numberAsChar_(v), 42)
         self.assertEqual(OC_TestNumber.numberAsShort_(v), 42)
         # Negative values
         v = NSNumber.numberWithInt_(-42)
 
+        self.assertEqual(v.stringValue(), '-42')
+
         self.assertEqual(OC_TestNumber.numberAsBOOL_(v), 1)
         self.assertEqual(OC_TestNumber.numberAsChar_(v), -42)
         self.assertEqual(OC_TestNumber.numberAsShort_(v), -42)
 
     def testDoubleConversions(self):
         v = NSNumber.numberWithDouble_(75.5)
+        self.assertEqual(v.stringValue(), '75.5')
 
         self.assertEqual(OC_TestNumber.numberAsBOOL_(v), 1)
         self.assertEqual(OC_TestNumber.numberAsChar_(v), 75)
 
         # Negative values
         v = NSNumber.numberWithDouble_(-127.6)
+        self.assertEqual(v.stringValue(), '-127.6')
 
         self.assertEqual(OC_TestNumber.numberAsBOOL_(v), 1)
         self.assertEqual(OC_TestNumber.numberAsChar_(v), -127)

pyobjc-core/PyObjCTest/test_objc.py

 from . import fnd as Foundation
 from .fnd import NSObject, NSArray, NSAttributedString
 import sys
+import os
 
 
 class TestConstants(TestCase):
 
         self.assertRaises(AttributeError, resolve, "distutils.command.sdist.dont_show_formats")
         self.assertRaises(AttributeError, resolve, "sys.does_not_exist")
+
+class TestPluginSupport (TestCase):
+    def test_deprecated(self):
+        with filterWarnings("error", DeprecationWarning):
+            self.assertRaises(DeprecationWarning, objc.registerPlugin, "myplugin")
+            self.assertRaises(DeprecationWarning, objc.pluginBundle, "myplugin")
+
+    def test_usage(self):
+        with filterWarnings("ignore", DeprecationWarning):
+            self.assertRaises(KeyError, objc.pluginBundle, "myplugin")
+
+            self.assertNotIn('RESOURCEPATH', os.environ)
+            self.assertRaises(KeyError, objc.registerPlugin, "myplugin")
+
+            # Actual plugin is .../MyPlugin.bundle/Contents/Resources, this is close enought and
+            # ensures that we can actually create as NSBundle later on.
+            os.environ['RESOURCEPATH'] = '/System/Library/Frameworks/Cocoa.framework/Contents/Resources'
+            try:
+                objc.registerPlugin("myplugin")
+
+                if sys.version_info[0] == 2:
+                    os.environ['RESOURCEPATH'] = b'/System/Library/Frameworks/Cocoa.framework/Contents/Resources'
+                    objc.registerPlugin("myplugin")
+            finally:
+                del os.environ['RESOURCEPATH']
+
+            b = objc.pluginBundle("myplugin")
+            self.assertIsInstance(b, objc.lookUpClass("NSBundle"))
+            self.assertEqual(b.bundlePath(), '/System/Library/Frameworks/Cocoa.framework')
+
+class TestCompatJunk (TestCase):
+    def test_loadFunctionList(self):
+        with filterWarnings("error", DeprecationWarning):
+            self.assertRaises(DeprecationWarning, objc._loadFunctionList, [])
+
+        orig = objc.loadFunctionList
+        try:
+            l = []
+            objc.loadFunctionList = lambda *args, **kwds: l.append((args, kwds))
+
+            objc._loadFunctionList(1, 2, a=3, b=3)
+            self.assertEqual(l, [((1,2), {'a':3, 'b':3})])
+
+        finally:
+            objc.loadFunctionList = orig
+
 if __name__ == '__main__':
     main()

pyobjc-core/PyObjCTest/test_testsupport.py

+from PyObjCTools.TestSupport import *
+import unittest
+import objc
+
+class Method(object):
+    def __init__(self, argno, meta, selector=False):
+        self._selector = selector
+        if argno is None:
+            self._meta = {'retval': meta}
+        else:
+            self._meta = {'arguments': { argno: meta }}
+
+    @property
+    def __class__(self):
+        if self._selector:
+            return objc.selector
+
+        else:
+            return Method
+        
+
+    def __metadata__(self):
+        return self._meta.copy()
+
+
+class TestTestSupport (TestCase):
+
+    def test_assert_opaque(self):
+        self.assertRaises(AssertionError, self.assertIsOpaquePointer, long)
+
+        class N (object):
+            @property
+            def __pointer__(self):
+                pass
+
+        self.assertRaises(AssertionError, self.assertIsOpaquePointer, N)
+
+        class N (object):
+            __typestr__  = b"^q"
+
+        self.assertRaises(AssertionError, self.assertIsOpaquePointer, N)
+
+        class N (object):
+            __typestr__  = b"^q"
+
+            @property
+            def __pointer__(self):
+                pass
+
+        try:
+            self.assertIsOpaquePointer(N)
+
+        except AssertionError:
+            self.fail("assertIsOpaque fails on opaque pointer type")
+
+
+
+    def test_assert_arg_IN(self):
+        m = Method(3, { "type": b"n^@" })
+        try:
+            self.assertArgIsIn(m, 3)
+        except AssertionError:
+            raise
+            self.fail("test failure for input argument")
+
+        m = Method(3, { "type": b"n^@" }, selector=True)
+        try:
+            self.assertArgIsIn(m, 1)
+        except AssertionError:
+            self.fail("test failure for input argument")
+
+        m = Method(3, { "type": b"^@" })
+        try:
+            self.assertArgIsIn(m, 3)
+        except AssertionError:
+            pass
+        else:
+            self.fail("test pass for not-input argument")
+
+        m = Method(3, { "type": b"^@" }, selector=True)
+        try:
+            self.assertArgIsIn(m, 1)
+        except AssertionError:
+            pass
+
+        else:
+            self.fail("test pass for not-input argument")
+
+    def test_assert_arg_OUT(self):
+        m = Method(3, { "type": b"o^@" })
+        try:
+            self.assertArgIsOut(m, 3)
+        except AssertionError:
+            raise
+            self.fail("test failure for input argument")
+
+        m = Method(3, { "type": b"o^@" }, selector=True)
+        try:
+            self.assertArgIsOut(m, 1)
+        except AssertionError:
+            self.fail("test failure for input argument")
+
+        m = Method(3, { "type": b"^@" })
+        try:
+            self.assertArgIsOut(m, 3)
+        except AssertionError:
+            pass
+        else:
+            self.fail("test pass for not-input argument")
+
+        m = Method(3, { "type": b"^@" }, selector=True)
+        try:
+            self.assertArgIsOut(m, 1)
+        except AssertionError:
+            pass
+
+        else:
+            self.fail("test pass for not-input argument")
+
+    def test_assert_arg_INOUT(self):
+        m = Method(3, { "type": b"N^@" })
+        try:
+            self.assertArgIsInOut(m, 3)
+        except AssertionError:
+            raise
+            self.fail("test failure for input argument")
+
+        m = Method(3, { "type": b"N^@" }, selector=True)
+        try:
+            self.assertArgIsInOut(m, 1)
+        except AssertionError:
+            self.fail("test failure for input argument")
+
+        m = Method(3, { "type": b"^@" })
+        try:
+            self.assertArgIsInOut(m, 3)
+        except AssertionError:
+            pass
+        else:
+            self.fail("test pass for not-input argument")
+
+        m = Method(3, { "type": b"^@" }, selector=True)
+        try:
+            self.assertArgIsInOut(m, 1)
+        except AssertionError:
+            pass
+
+        else:
+            self.fail("test pass for not-input argument")
+
+    def test_arg_bool(self):
+        m = Method(3, { "type": objc._C_NSBOOL })
+        try:
+            self.assertArgIsBOOL(m, 3)
+        except AssertionError:
+            raise
+            self.fail("unexpected test failure")
+
+        m = Method(3, { "type": objc._C_NSBOOL }, selector=True)
+        try:
+            self.assertArgIsBOOL(m, 1)
+        except AssertionError:
+            self.fail("unexpected test failure")
+
+        m = Method(3, { "type": b"@" })
+        try:
+            self.assertArgIsBOOL(m, 3)
+        except AssertionError:
+            pass
+        else:
+            self.fail("unexpected test pass")
+
+        m = Method(3, { "type": b"@" }, selector=True)
+        try:
+            self.assertArgIsBOOL(m, 1)
+        except AssertionError:
+            pass
+
+        else:
+            self.fail("unexpected test pass")
+
+    def test_result_bool(self):
+        m = Method(None, { "type": objc._C_NSBOOL })
+        try:
+            self.assertResultIsBOOL(m)
+        except AssertionError:
+            raise
+            self.fail("unexpected test failure")
+
+        m = Method(None, { "type": objc._C_NSBOOL }, selector=True)
+        try:
+            self.assertResultIsBOOL(m)
+        except AssertionError:
+            self.fail("unexpected test failure")
+
+        m = Method(None, { "type": b"@" })
+        try:
+            self.assertResultIsBOOL(m)
+        except AssertionError:
+            pass
+        else:
+            self.fail("unexpected test pass")
+
+        m = Method(None, { "type": b"@" }, selector=True)
+        try:
+            self.assertResultIsBOOL(m)
+        except AssertionError:
+            pass
+
+        else:
+            self.fail("unexpected test pass")
+        
+
+    def run(self, *args, **kwds):
+        unittest.TestCase.run(self, *args, **kwds)
+
+
+if __name__ == "__main__":
+    main()