Commits

Ronald Oussoren committed 051013f

* Some 'XXX' comments solved

* Ensure that all setters from getset lists check for a NULL value ('del Foo.attribute')

* OC_PythonUnicode is encodes as itself in a keyed-archiver

* whitespace cleanup in objc_support.m

Comments (0)

Files changed (20)

pyobjc-core/Modules/objc/OC_PythonData.m

 
     } else {
         [NSException raise:NSInvalidArgumentException
-                format:@"encoding Python objects is not supported"];
+                format:@"encoding Python data objects is not supported"];
 
     }
     return self;

pyobjc-core/Modules/objc/OC_PythonDictionary.h

     PyObject* value;
 }
 
-/*!
- * @method newWithPythonObject:
- * @abstract Create a new autoreleased proxy object
- * @param value  A Python dict
- * @result Returns an autoreleased proxy object for the Python dict
- *
- * The caller must own the GIL.
- */
 +(OC_PythonDictionary*)dictionaryWithPythonObject:(PyObject*)value;
-
-/*!
- * @method initWithPythonObject:
- * @abstract Initialize a proxy object
- * @param value  A Python dict
- * @result Returns self
- * @discussion
- *    Makes the proxy object a proxy for the specified Python dict.
- *
- *    The caller must own the GIL.
- */
 -(OC_PythonDictionary*)initWithPythonObject:(PyObject*)value;
-
-/*!
- * @method dealloc
- * @abstract Deallocate the object
- */
 - (void)dealloc;
-
-/*!
- * @method dealloc
- * @abstract Access the wrapped Python sequence
- * @result  Returns a new reference to the wrapped Python sequence.
- */
 - (PyObject*)__pyobjc_PythonObject__;
-
-/*!
- * @method count
- * @abstract Find the number of elements in the dictionary
- * @result Returns the size of the wrapped Python dictionary
- */
 - (NSUInteger)count;
-
-/*
- * @method keyEnumerator
- * @abstract Enumerate all keys in the wrapped dictionary
- * @result Returns an NSEnumerator instance for iterating over the keys
- */
 - (NSEnumerator*)keyEnumerator;
-
-/*
- * @method setObject:forKey:
- * @param object An object
- * @param key    A key, must be hashable.
- */
 - (void)setObject:(id)object forKey:(id)key;
-
-/*
- * @method removeObjectForKey:
- * @param key A key, must be hashable
- */
 - (void)removeObjectForKey:(id)key;
-
-/*
- * @method objectForKey:
- * @param key A key
- * @result Returns the object corresponding with key, or nil.
- */
 - (id)objectForKey:(id)key;
-
-/*
- * XXX - document these, internal
- */
--(BOOL)wrappedKey:(id*)keyPtr value:(id*)valuePtr atPosition:(Py_ssize_t*)positionPtr;
--(int)depythonify:(PyObject*)v toId:(id*)datum;
-
-/* These two are only present to *disable* coding, not implement it */
 - (void)encodeWithCoder:(NSCoder*)coder;
 -(id)initWithCoder:(NSCoder*)coder;
 

pyobjc-core/Modules/objc/OC_PythonDictionary.m

 @end /* interface OC_PythonDictionaryEnumerator */
 
 
-
 @implementation OC_PythonDictionaryEnumerator
 
 +(instancetype)enumeratorWithWrappedDictionary:(OC_PythonDictionary*)v
 -(id)nextObject
 {
     id key = nil;
+    PyObject* pykey = NULL;
 
-    if (valid) {
-        valid = [value wrappedKey:&key value:nil atPosition:&pos];
-    }
+    PyObjC_BEGIN_WITH_GIL
+        PyObject* dct = [value __pyobjc_PythonObject__];
+        if (unlikely(!PyDict_Next(dct, &pos, &pykey, NULL))) {
+            key = nil;
+
+        } else if (pykey == Py_None) {
+            key = [NSNull null];
+
+        } else {
+            if (depythonify_c_value(@encode(id), pykey, &key) == -1) {
+                Py_DECREF(dct);
+                PyObjC_GIL_FORWARD_EXC();
+            }
+        }
+        Py_DECREF(dct);
+
+    PyObjC_END_WITH_GIL
+
+    valid = (key != nil) ? YES : NO;
+
     return key;
 }
 
     PyObjC_END_WITH_GIL
 }
 
-
-
 -(void)dealloc
 {
     PyObjC_BEGIN_WITH_GIL
 
 -(PyObject*)__pyobjc_PythonObject__
 {
-    Py_INCREF(value);
+    Py_XINCREF(value);
     return value;
 }
 
 -(PyObject*)__pyobjc_PythonTransient__:(int*)cookie
 {
     *cookie = 0;
-    Py_INCREF(value);
+    Py_XINCREF(value);
     return value;
 }
 
     return result;
 }
 
--(int)depythonify:(PyObject*)v toId:(id*)datum
-{
-    if (unlikely(depythonify_c_value(@encode(id), v, datum) == -1)) {
-        return -1;
-    }
-    if (unlikely(*datum == nil)) {
-        *datum = [NSNull null];
-    }
-    return 0;
-}
-
 -(id)objectForKey:key
 {
     PyObject* v;
             PyObjC_GIL_RETURN(nil);
         }
 
-        if (unlikely([self depythonify:v toId:&result] == -1)) {
+        if (v == Py_None) {
+            result = [NSNull null];
+
+        } else if (unlikely(depythonify_c_value(@encode(id), v, &result) == -1)) {
             Py_DECREF(v);
             PyObjC_GIL_FORWARD_EXC();
-
         }
         Py_DECREF(v);
 
     PyObjC_END_WITH_GIL
 }
 
--(BOOL)wrappedKey:(id*)keyPtr value:(id*)valuePtr atPosition:(Py_ssize_t*)positionPtr
-{
-    PyObject *pykey = NULL;
-    PyObject *pyvalue = NULL;
-    PyObject **pykeyptr = (keyPtr == nil) ? NULL : &pykey;
-    PyObject **pyvalueptr = (valuePtr == nil) ? NULL : &pyvalue;
-
-    PyObjC_BEGIN_WITH_GIL
-        if (unlikely(!PyDict_Next(value, positionPtr, pykeyptr, pyvalueptr))) {
-            PyObjC_GIL_RETURN(NO);
-        }
-        if (keyPtr) {
-            if (unlikely([self depythonify:pykey toId:keyPtr] == -1)) {
-                PyObjC_GIL_FORWARD_EXC();
-            }
-        }
-        if (likely(valuePtr)) {
-            if (unlikely([self depythonify:pyvalue toId:valuePtr] == -1)) {
-                PyObjC_GIL_FORWARD_EXC();
-            }
-        }
-    PyObjC_END_WITH_GIL
-    return YES;
-}
 
 -(void)removeObjectForKey:key
 {
     return [OC_PythonDictionary class];
 }
 
++(NSArray*)classFallbacksForKeyedArchiver
+{
+    return [NSArray arrayWithObject:@"NSDictionary"];
+}
+
 - (void)encodeWithCoder:(NSCoder*)coder
 {
     if (PyDict_CheckExact(value)) {
     }
 }
 
-+(NSArray*)classFallbacksForKeyedArchiver
-{
-    return [NSArray arrayWithObject:@"NSDictionary"];
-}
-
-
 @end  // interface OC_PythonDictionary

pyobjc-core/Modules/objc/OC_PythonSet.m

 
 /* It seems impossible to create an efficient implementation of this method,
  * iteration is basicly the only way to fetch the requested object
- *
- * XXX: this means we should implement more of NS(Mutable)Set interface,
- * that's a lot more efficient than iterating over and over again.
- *
  */
 -(id)member:(id)anObject
 {
     return [NSArray arrayWithObject:@"NSSet"];
 }
 
-
 @end

pyobjc-core/Modules/objc/OC_PythonString.m

 
     } else {
         [NSException raise:NSInvalidArgumentException
-                    format:@"encoding Python objects is not supported"];
+                    format:@"encoding Python string objects is not supported"];
     }
     return self;
 }

pyobjc-core/Modules/objc/OC_PythonUnicode.h

 {
     PyObject* value;
     id realObject;
-
-#ifdef PyObjC_STR_CACHE_IMP
-    /* Cache IMPs for proxied methods, for slightly better efficiency */
-    NSUInteger (*imp_length)(id, SEL);
-    unichar (*imp_charAtIndex)(id, SEL, NSUInteger);
-    void (*imp_getCharacters)(id, SEL, unichar*, NSRange);
-#endif /* PyObjC_STR_CACHE_IMP */
 }
 
 /*!

pyobjc-core/Modules/objc/OC_PythonUnicode.m

 }
 
 
-
 -(BOOL)supportsWeakPointers {
     return YES;
 }
     [super dealloc];
 }
 
-/*
- * XXX: The code below should work for PyObjC_UNICODE_FAST_PATH
- * but causes failures on 64-bit builds on OSX 10.7
- *
-
--(NSUInteger)length
-{
-    return (NSUInteger)PyUnicode_GET_SIZE(value);
-}
-
--(unichar)characterAtIndex:(NSUInteger)anIndex
-{
-    if (anIndex > PY_SSIZE_T_MAX) {
-        [NSException raise:@"NSRangeException" format:@"Range or index out of bounds"];
-    }
-    if (anIndex >= (NSUInteger)PyUnicode_GET_SIZE(value)) {
-        [NSException raise:@"NSRangeException" format:@"Range or index out of bounds"];
-    }
-
-    return (unichar)PyUnicode_AS_UNICODE(value)[anIndex];
-}
-
--(void)getCharacters:(unichar *)buffer range:(NSRange)aRange
-{
-    if (aRange.location + aRange.length > (NSUInteger)PyUnicode_GET_SIZE(value)) {
-        [NSException raise:@"NSRangeException" format:@"Range or index out of bounds"];
-    }
-
-    memmove(buffer,
-           (PyUnicode_AS_UNICODE(value)) + aRange.location,
-           sizeof(unichar) * aRange.length);
-}
-
-*/
-
-
 #if PY_VERSION_HEX >= 0x03030000
 
 -(id)__realObject__
 
 -(NSUInteger)length
 {
-#ifdef PyObjC_STR_CACHE_IMP
-    if (!imp_length) {
-        [self __realObject__];
-        imp_length = (__typeof__(imp_length))([realObject methodForSelector:@selector(length)]);
-    }
-    if (!imp_length) abort();
-    if (!realObject) abort();
-    return imp_length(realObject, @selector(length));
-
-#else /* !PyObjC_STR_CACHE_IMP */
     return [[self __realObject__] length];
-
-#endif /* !PyObjC_STR_CACHE_IMP */
 }
 
 -(unichar)characterAtIndex:(NSUInteger)anIndex
 {
-#ifdef PyObjC_STR_CACHE_IMP
-    if (!imp_charAtIndex) {
-        [self __realObject__];
-        imp_charAtIndex = (__typeof__(imp_charAtIndex))([realObject methodForSelector:@selector(characterAtIndex:)]);
-    }
-    if (!imp_charAtIndex) abort();
-    if (!realObject) abort();
-    return imp_charAtIndex(realObject, @selector(characterAtIndex:), anIndex);
-
-#else /* !PyObjC_STR_CACHE_IMP */
     return [[self __realObject__] characterAtIndex:anIndex];
-
-#endif /* !PyObjC_STR_CACHE_IMP */
 }
 
 -(void)getCharacters:(unichar *)buffer range:(NSRange)aRange
 {
-#ifdef PyObjC_STR_CACHE_IMP
-    if (!imp_getCharacters) {
-        [self __realObject__];
-        imp_getCharacters = (__typeof__(imp_getCharacters))([realObject methodForSelector:@selector(getCharacters:range:)]);
-    }
-    if (!imp_getCharacters) abort();
-    if (!realObject) abort();
-    imp_getCharacters(realObject, @selector(getCharacters:range:), buffer, aRange);
-
-#else    /* !PyObjC_STR_CACHE_IMP */
     return [[self __realObject__] getCharacters:buffer range:aRange];
-
-#endif
 }
 
 -(void)getCharacters:(unichar*)buffer
 
 /*
  * NSCoding support
- *
- * We need explicit NSCoding support to get full fidelity, otherwise we'll
- * get archived as generic NSStrings.
  */
 - (id)initWithCharactersNoCopy:(unichar *)characters
             length:(NSUInteger)length
         }
     } else {
         [NSException raise:NSInvalidArgumentException
-            format:@"encoding Python objects is not supported"];
+            format:@"encoding Python unicode objects is not supported"];
         return nil;
     }
 }
     PyObjC_END_WITH_GIL
 
     if (is_exact_unicode) {
+        if ([coder allowsKeyedCoding]) {
+            [coder encodeInt32:1 forKey:@"pytype"];
+        }
         [super encodeWithCoder:coder];
     } else {
         if ([coder allowsKeyedCoding]) {
  * when reading them back, but does allow for better interop with code
  * that uses a non-keyed archiver.
  */
--(Class)classForArchiver
+-(Class)classForCoder
 {
     Class result;
     PyObjC_BEGIN_WITH_GIL
 
 -(Class)classForKeyedArchiver
 {
-    return [self classForArchiver];
+    return [OC_PythonUnicode class];
 }
 
--(Class)classForCoder
-{
-    return [self classForArchiver];
-}
-
--(Class)classForPortCoder
-{
-    return [self classForArchiver];
-}
 
 /* Ensure that we can be unarchived as a generic string by pure ObjC
  * code.

pyobjc-core/Modules/objc/class-list.h

 #ifndef PyObjC_CLASS_LIST_H
 #define PyObjC_CLASS_LIST_H
+
+/*!
+ * PYOBJC_EXPECTED_CLASS_COUNT: Hint about the number of classes to expect
+ *
+ * Loading Quartz results close to 5K classes on OSX 10.8
+ */
+#define PYOBJC_EXPECTED_CLASS_COUNT 10000
+
 /*!
  * @header class-list.h
  * @abstract Get the list of classes in the Objective-C runtime

pyobjc-core/Modules/objc/objc-class.h

  */
 typedef struct _PyObjCClassObject {
     PyHeapTypeObject base;
-    __strong Class class;
+    Class class;
     PyObject* sel_to_py;
-    Py_ssize_t dictoffset;
     PyObject* delmethod;
-    Py_ssize_t generation;
     PyObject* hiddenSelectors;
     PyObject* hiddenClassSelectors;
 
-    int  useKVO;     /* FIXME: swith to getset in python API  and switch this to a bitfield as well. */
+    Py_ssize_t dictoffset;
+    Py_ssize_t generation;
+    unsigned int useKVO:1;
     unsigned int hasPythonImpl:1;
     unsigned int isCFWrapper:1;
 } PyObjCClassObject;
 extern PyObject* PyObjCClass_TryResolveSelector(PyObject* base, PyObject* name, SEL sel);
 extern PyObject* PyObjCMetaClass_TryResolveSelector(PyObject* base, PyObject* name, SEL sel);
 
-/* XXX: This should be in a different file! */
-char* PyObjC_SELToPythonName(SEL, char*, size_t);
-
-
 #endif /* PyObjC_OBJC_CLASS_H */

pyobjc-core/Modules/objc/objc-class.m

     int   val;
     int   r;
 
+    if (newVal == NULL) {
+        PyErr_SetString(PyExc_TypeError, "Cannot delete __version__  attribute");
+        return -1;
+    }
+
     r = depythonify_c_value(@encode(int), newVal, &val);
     if (r == -1) {
         return -1;
     return 0;
 }
 
+static PyObject*
+cls_get_useKVO(PyObject* self, void* closure __attribute__((__unused__)))
+{
+    return PyBool_FromLong(((PyObjCClassObject*)self)->useKVO);
+}
+
+static  int
+cls_set_useKVO(PyObject* self, PyObject* newVal, void* closure __attribute__((__unused__)))
+{
+    if (newVal == NULL) {
+        PyErr_SetString(PyExc_TypeError, "Cannot delete __useKVO__ attribute");
+        return -1;
+    }
+
+    ((PyObjCClassObject*)self)->useKVO = PyObject_IsTrue(newVal);
+    return 0;
+}
+
 
 static PyGetSetDef class_getset[] = {
     {
         cls_version_doc,
         0
     },
-
+    {
+        "__useKVO__",
+        cls_get_useKVO,
+        cls_set_useKVO,
+        "Use KVO notifications when setting attributes from Python",
+        0
+    },
     {
         /* Access __name__ through a property: Objective-C name
          * might change due to posing.
     }
 };
 
-static PyMemberDef class_members[] = {
-    {
-        "__useKVO__",
-        T_INT,
-        offsetof(PyObjCClassObject, useKVO),
-        0,
-        "Use KVO notifications when setting attributes from Python",
-    },
-    { NULL, 0, 0, 0, NULL}
-};
-
-
 /*
  * This is the class for type(NSObject), and is a subclass of type()
  * with an overridden tp_getattro that is used to dynamicly look up
     .tp_doc         = class_doc,
     .tp_richcompare = class_richcompare,
     .tp_methods     = class_methods,
-    .tp_members     = class_members,
     .tp_getset      = class_getset,
     .tp_base        = &PyObjCMetaClass_Type,
     .tp_init        = class_init,
     .tp_new         = class_new,
 };
 
-char*
-PyObjC_SELToPythonName(SEL sel, char* buf, size_t buflen)
-{
-    size_t res = snprintf(buf, buflen, "%s", sel_getName(sel));
-    char* cur;
-
-    if (res != strlen(sel_getName(sel))) {
-        return NULL;
-    }
-
-    if (PyObjC_IsPythonKeyword(buf)) {
-        res = snprintf(buf, buflen, "%s__", sel_getName(sel));
-        if (res != 2+strlen(sel_getName(sel))) {
-            return NULL;
-        }
-        return buf;
-    }
-
-    cur = strchr(buf, ':');
-    while (cur) {
-        *cur = '_';
-        cur = strchr(cur, ':');
-    }
-    return buf;
-}
-
 /*
  * Create a new objective-C class  proxy.
  *

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

 static int
 obj_set_blocksignature(PyObject* self, PyObject* newVal, void* closure __attribute__((__unused__)))
 {
+    if (newVal == NULL) {
+        PyErr_SetString(PyExc_TypeError, "Cannot delete '__block_signature'");
+        return -1;
+    }
     if (!PyObjCObject_IsBlock(self)) {
-        PyErr_SetString(PyExc_TypeError, "You can only change this value on blocks");
+        PyErr_SetString(PyExc_TypeError, "'__block_signature__' can only be set on Block objects");
         return  -1;
     }
 

pyobjc-core/Modules/objc/objc_support.m

 
 -(PyObject*)__pyobjc_PythonObject__
 {
-    /* Don't register the proxy, see XXX */
     PyObject *rval = (PyObject *)PyObjCUnicode_New(self);
     return rval;
 }
 @implementation NSNumber (PyObjCSupport)
 -(PyObject*)__pyobjc_PythonObject__
 {
-    /* FIXME: rewrite PyObjC_NSNumberWrapper in C */
     PyObject *rval;
 
-
     /* shortcut for booleans */
     if (kCFBooleanTrue == (CFBooleanRef)self) {
         return PyBool_FromLong(1);
+
     } else if (kCFBooleanFalse == (CFBooleanRef)self) {
         return PyBool_FromLong(0);
     }
 {
     if (v % a == 0) {
         return v;
+
     } else {
         return v + a - (v % a);
     }
 
 
 const char*
-PyObjCRT_SkipTypeQualifiers (const char* type)
+PyObjCRT_SkipTypeQualifiers(const char* type)
 {
     PyObjC_Assert(type != NULL, NULL);
 
 }
 
 const char *
-PyObjCRT_SkipTypeSpec (const char *type)
+PyObjCRT_SkipTypeSpec(const char *type)
 {
     PyObjC_Assert(type != NULL, NULL);
 
-    type = PyObjCRT_SkipTypeQualifiers (type);
+    type = PyObjCRT_SkipTypeQualifiers(type);
 
     switch (*type) {
     case '"':
         break;
 
     case _C_BFLD:
-        while (isdigit (*++type));
+        while (isdigit(*++type));
         break;
 
     case _C_ID:
     case _C_ARY_B:
         /* skip digits, typespec and closing ']' */
 
-        while (isdigit (*++type));
-        type = PyObjCRT_SkipTypeSpec (type);
+        while (isdigit(*++type));
+        type = PyObjCRT_SkipTypeSpec(type);
         PyObjC_Assert(type == NULL || *type == _C_ARY_E, NULL);
         if (type) type++;
         break;
                     return NULL;
                 }
             }
-            type = PyObjCRT_SkipTypeSpec (type);
+            type = PyObjCRT_SkipTypeSpec(type);
         }
         if (type) type++;
         break;
                     return NULL;
                 }
             }
-            type = PyObjCRT_SkipTypeSpec (type);
+            type = PyObjCRT_SkipTypeSpec(type);
         }
         if (type) type++;
         break;
     case _C_ONEWAY:
 
         /* Just skip the following typespec */
-        type = PyObjCRT_SkipTypeSpec (type+1);
+        type = PyObjCRT_SkipTypeSpec(type+1);
         break;
 
 
 {
     PyObjC_Assert(type != NULL, NULL);
 
-    type = PyObjCRT_SkipTypeQualifiers (type);
+    type = PyObjCRT_SkipTypeQualifiers(type);
 
     switch (*type) {
     /* The following are one character type codes */
     case _C_ARY_B:
         /* skip digits, typespec and closing ']' */
 
-        while (isdigit (*++type));
-        type = PyObjCRT_SkipTypeSpec (type);
+        while (isdigit(*++type));
+        type = PyObjCRT_SkipTypeSpec(type);
         if (unlikely(type == NULL)) {
             if (!PyErr_Occurred()) {
                 PyErr_SetString(PyObjCExc_InternalError,
                     return NULL;
                 }
             }
-            type = PyObjCRT_SkipTypeSpec (type);
+            type = PyObjCRT_SkipTypeSpec(type);
         }
         if (unlikely(type == NULL)) {
             if (!PyErr_Occurred()) {
                     return NULL;
                 }
             }
-            type = PyObjCRT_SkipTypeSpec (type);
+            type = PyObjCRT_SkipTypeSpec(type);
         }
         if (unlikely(type == NULL)) {
             if (!PyErr_Occurred()) {
 *  8.
 *
 *  Other platform don't seem to have this inconsistency.
-*
-*  XXX: sizeof_struct, alignof_struct and {de,}pythonify_c_struct should
-*  probably be moved to platform dependend files. As long as this is the
-*  only platform dependent code this isn't worth the effort.
 */
 
 static inline Py_ssize_t
-PyObjC_EmbeddedAlignOfType (const char*  type)
+PyObjC_EmbeddedAlignOfType(const char*  type)
 {
     PyObjC_Assert(type != NULL, -1);
 
 }
 
 Py_ssize_t
-PyObjCRT_AlignOfType (const char *type)
+PyObjCRT_AlignOfType(const char *type)
 {
     PyObjC_Assert(type != NULL, -1);
 
 
     case _C_ARY_B:
         while (isdigit(*++type)) /* do nothing */;
-        return PyObjCRT_AlignOfType (type);
+        return PyObjCRT_AlignOfType(type);
 
     case _C_STRUCT_B:
     {
             Py_ssize_t item_align = PyObjCRT_AlignOfType(type);
             if (item_align == -1) return -1;
             maxalign = MAX (maxalign, item_align);
-            type = PyObjCRT_SkipTypeSpec (type);
+            type = PyObjCRT_SkipTypeSpec(type);
         }
         return maxalign;
     }
 */
 
 Py_ssize_t
-PyObjCRT_AlignedSize (const char *type)
+PyObjCRT_AlignedSize(const char *type)
 {
     PyObjC_Assert(type != NULL, -1);
 
-    Py_ssize_t size = PyObjCRT_SizeOfType (type);
-    Py_ssize_t align = PyObjCRT_AlignOfType (type);
+    Py_ssize_t size = PyObjCRT_SizeOfType(type);
+    Py_ssize_t align = PyObjCRT_AlignOfType(type);
 
     if (size == -1 || align == -1) return -1;
     return ROUND(size, align);
 */
 
 Py_ssize_t
-PyObjCRT_SizeOfType (const char *type)
+PyObjCRT_SizeOfType(const char *type)
 {
     PyObjC_Assert(type != NULL, -1);
 
             max_align = MAX(align, max_align);
             acc_size = ROUND (acc_size, align);
 
-            itemSize = PyObjCRT_SizeOfType (type);
+            itemSize = PyObjCRT_SizeOfType(type);
             if (itemSize == -1) return -1;
             acc_size += itemSize;
-            type = PyObjCRT_SkipTypeSpec (type);
+            type = PyObjCRT_SkipTypeSpec(type);
         }
 
         if (max_align) {
 
         /* Calculate size: */
         while (*type != _C_UNION_E) {
-            itemSize = PyObjCRT_SizeOfType (type);
+            itemSize = PyObjCRT_SizeOfType(type);
             if (itemSize == -1) return -1;
             max_size = MAX (max_size, itemSize);
-            type = PyObjCRT_SkipTypeSpec (type);
+            type = PyObjCRT_SkipTypeSpec(type);
         }
 
         return max_size;
     PyObjC_Assert(datum != NULL, NULL);
 
     Py_ssize_t count = 0;
-    Py_ssize_t sizeofitem = PyObjCRT_SizeOfType (type);
+    Py_ssize_t sizeofitem = PyObjCRT_SizeOfType(type);
     unsigned char* curdatum = datum;
 
     type = PyObjCRT_SkipTypeQualifiers(type);
 /*#F Returns a tuple of objects representing the content of a C array
 of type @var{type} pointed by @var{datum}. */
 static PyObject *
-pythonify_c_array (const char *type, void *datum)
+pythonify_c_array(const char *type, void *datum)
 {
     PyObjC_Assert(type != NULL, NULL);
     PyObjC_Assert(datum != NULL, NULL);
     Py_ssize_t nitems, itemidx, sizeofitem;
     unsigned char* curdatum;
 
-    nitems = atoi (type+1);
-    while (isdigit (*++type))
+    nitems = atoi(type+1);
+    while (isdigit(*++type))
         ;
-    sizeofitem = PyObjCRT_SizeOfType (type);
+    sizeofitem = PyObjCRT_SizeOfType(type);
     if (sizeofitem == -1) return NULL;
 
-    ret = PyTuple_New (nitems);
+    ret = PyTuple_New(nitems);
     if (!ret) return NULL;
 
     curdatum = datum;
     for (itemidx=0; itemidx < nitems; itemidx++) {
         PyObject *pyitem = NULL;
 
-        pyitem = pythonify_c_value (type, curdatum);
+        pyitem = pythonify_c_value(type, curdatum);
 
         if (pyitem) {
             PyTuple_SET_ITEM (ret, itemidx, pyitem);
 /*#F Returns a tuple of objects representing the content of a C structure
 of type @var{type} pointed by @var{datum}. */
 static PyObject *
-pythonify_c_struct (const char *type, void *datum)
+pythonify_c_struct(const char *type, void *datum)
 {
     PyObjC_Assert(type != NULL, NULL);
     PyObjC_Assert(datum != NULL, NULL);
         }
 
         haveTuple = 1;
-        ret = PyTuple_New (nitems);
+        ret = PyTuple_New(nitems);
         if (!ret) return NULL;
 
         item = type;
 
         offset = ROUND(offset, align);
 
-        pyitem = pythonify_c_value (item, ((char*)datum)+offset);
+        pyitem = pythonify_c_value(item, ((char*)datum)+offset);
 
         if (pyitem) {
             if (haveTuple) {
         }
 
         itemidx++;
-        offset += PyObjCRT_SizeOfType (item);
-        item = PyObjCRT_SkipTypeSpec (item);
+        offset += PyObjCRT_SizeOfType(item);
+        item = PyObjCRT_SkipTypeSpec(item);
     }
 
     return ret;
     unsigned char* curdatum;
     PyObject* seq;
 
-    sizeofitem = PyObjCRT_AlignedSize (type);
+    sizeofitem = PyObjCRT_AlignedSize(type);
     if (sizeofitem == -1) {
         PyErr_Format(PyExc_ValueError,
             "cannot depythonify array of unknown type");
         PyObject *pyarg = PySequence_Fast_GET_ITEM(seq, itemidx);
         int err;
 
-        err = depythonify_c_value (type, pyarg, curdatum);
+        err = depythonify_c_value(type, pyarg, curdatum);
         if (err == -1) {
             Py_DECREF(seq);
             return err;
 int
 depythonify_c_array_nullterminated(const char* type, Py_ssize_t count, PyObject* value, void* datum, BOOL already_retained, BOOL already_cfretained)
 {
+    PyObjC_Assert(count >= 0, -1);
     PyObjC_Assert(type != NULL, -1);
     PyObjC_Assert(value != NULL, -1);
     PyObjC_Assert(datum != NULL, -1);
 
-    /* XXX: we can do better than this: just clear the last item */
-    /* Clear memory: */
-    memset(datum, 0, count * PyObjCRT_SizeOfType(type));
-
+    /* Ensure that the list will be NULL terminated */
+    if (count > 0) {
+        Py_ssize_t sz = PyObjCRT_SizeOfType(type);
+        memset(((unsigned char*)datum) + ((count - 1) * sz), 0, sz);
+    }
+
+    /* Shortcut: empty list */
     if (count == 1) {
         return 0;
     }
 of type @var{type} pointed by @var{datum}. Returns an error message, or
 NULL on success. */
 static int
-depythonify_c_array (const char *type, PyObject *arg, void *datum)
+depythonify_c_array(const char *type, PyObject *arg, void *datum)
 {
     PyObjC_Assert(type != NULL, -1);
     PyObjC_Assert(arg != NULL, -1);
     unsigned char* curdatum;
     PyObject* seq;
 
-    nitems = atoi (type+1);
-    while (isdigit (*++type))
+    nitems = atoi(type+1);
+    while (isdigit(*++type))
         ;
-    sizeofitem = PyObjCRT_AlignedSize (type);
+    sizeofitem = PyObjCRT_AlignedSize(type);
     if (sizeofitem == -1) {
         PyErr_Format(PyExc_ValueError,
             "cannot depythonify array of unknown type");
         PyObject *pyarg = PySequence_Fast_GET_ITEM(seq, itemidx);
         int err;
 
-        err = depythonify_c_value (type, pyarg, curdatum);
+        err = depythonify_c_value(type, pyarg, curdatum);
         if (err == -1) {
             Py_DECREF(seq);
             return err;
             type++;
         }
         nitems++;
-        type = PyObjCRT_SkipTypeSpec (type);
+        type = PyObjCRT_SkipTypeSpec(type);
     }
 
     seq = PySequence_Fast(arg, "depythonifying struct, got no sequence");
         Py_DECREF(seq);
         PyErr_Format(PyExc_ValueError,
             "depythonifying struct of %"PY_FORMAT_SIZE_T"d members, got tuple of %"PY_FORMAT_SIZE_T"d",
-            nitems, PyTuple_Size (arg));
+            nitems, PyTuple_Size(arg));
         return -1;
     }
 
         }
 
         itemidx++;
-        offset += PyObjCRT_SizeOfType (type);
-        type = PyObjCRT_SkipTypeSpec (type);
+        offset += PyObjCRT_SizeOfType(type);
+        type = PyObjCRT_SkipTypeSpec(type);
     }
     Py_DECREF(seq);
     return 0;
 }
 
 PyObject *
-pythonify_c_value (const char *type, void *datum)
+pythonify_c_value(const char *type, void *datum)
 {
     PyObjC_Assert(type != NULL, NULL);
     PyObjC_Assert(datum != NULL, NULL);
 
     PyObject *retobject = NULL;
 
-    type = PyObjCRT_SkipTypeQualifiers (type);
+    type = PyObjCRT_SkipTypeQualifiers(type);
 
     switch (*type) {
     case _C_UNICHAR:
          * We don't return a string because BOOL is an alias for
          * char (at least on MacOS X)
          */
-        retobject = (PyObject*)PyInt_FromLong ((int)(*(char*)datum));
+        retobject = (PyObject*)PyInt_FromLong((int)(*(char*)datum));
         break;
 
     case _C_UCHR:
-        retobject = (PyObject*)PyInt_FromLong (
+        retobject = (PyObject*)PyInt_FromLong(
             (long)(*(unsigned char*)datum));
         break;
 
 
 #ifdef _C_BOOL
     case _C_BOOL:
-        retobject = (PyObject *) PyBool_FromLong (*(bool*) datum);
+        retobject = (PyObject *) PyBool_FromLong(*(bool*) datum);
         break;
 #endif
 
     case _C_NSBOOL:
-        retobject = (PyObject *) PyBool_FromLong (*(BOOL*) datum);
+        retobject = (PyObject *) PyBool_FromLong(*(BOOL*) datum);
         break;
 
     case _C_INT:
-        retobject = (PyObject *) PyInt_FromLong (*(int*) datum);
+        retobject = (PyObject *) PyInt_FromLong(*(int*) datum);
         break;
 
     case _C_UINT:
 #if __LP64__
-        retobject = (PyObject*)PyInt_FromLong (
+        retobject = (PyObject*)PyInt_FromLong(
             *(unsigned int *) datum);
 
 #else
             retobject = (PyObject*)PyLong_FromUnsignedLongLong(
                 *(unsigned int*)datum);
         } else {
-            retobject = (PyObject*)PyInt_FromLong (
+            retobject = (PyObject*)PyInt_FromLong(
                 *(unsigned int *) datum);
         }
 #endif
         break;
 
     case _C_SHT:
-        retobject = (PyObject *) PyInt_FromLong (*(short *) datum);
+        retobject = (PyObject *) PyInt_FromLong(*(short *) datum);
         break;
 
     case _C_USHT:
-        retobject = (PyObject *) PyInt_FromLong (
+        retobject = (PyObject *) PyInt_FromLong(
             *(unsigned short *) datum);
         break;
 
             retobject = (PyObject*)PyLong_FromUnsignedLongLong(
                 *(unsigned long*)datum);
         } else {
-            retobject = (PyObject*)PyInt_FromLong (
+            retobject = (PyObject*)PyInt_FromLong(
                 *(unsigned long*) datum);
         }
 #else
         break;
 
     case _C_FLT:
-        retobject = (PyObject *) PyFloat_FromDouble (*(float*) datum);
+        retobject = (PyObject *) PyFloat_FromDouble(*(float*) datum);
         break;
 
     case _C_DBL:
-        retobject = (PyObject *) PyFloat_FromDouble (*(double*) datum);
+        retobject = (PyObject *) PyFloat_FromDouble(*(double*) datum);
         break;
 
     case _C_ID:
 
     case _C_UNION_B:
     {
-        Py_ssize_t size = PyObjCRT_SizeOfType (type);
+        Py_ssize_t size = PyObjCRT_SizeOfType(type);
         if (size == -1) return NULL;
-        retobject = PyBytes_FromStringAndSize ((void*)datum, size);
+        retobject = PyBytes_FromStringAndSize((void*)datum, size);
         break;
     }
 
     case _C_STRUCT_B:
-        retobject = pythonify_c_struct (type, datum);
+        retobject = pythonify_c_struct(type, datum);
         break;
 
     case _C_ARY_B:
-        retobject = pythonify_c_array (type, datum);
+        retobject = pythonify_c_array(type, datum);
         break;
 
     case _C_VOID:
     PyObjC_Assert(out != NULL, -1);
 
 #if PY_MAJOR_VERSION == 2
-    if (PyInt_Check (argument)) {
+    if (PyInt_Check(argument)) {
         long temp = PyInt_AsLong(argument);
         if (PyErr_Occurred()) {
             return -1;
     PyObjC_Assert(out != NULL, -1);
 
 #if PY_MAJOR_VERSION == 2
-    if (PyInt_Check (argument)) {
+    if (PyInt_Check(argument)) {
         *out = (long long)PyInt_AsLong(argument);
         if (PyErr_Occurred()) {
             return -1;
 
     case _C_CHAR_AS_TEXT:
         if (PyBytes_Check(argument) && PyBytes_Size(argument) == 1) {
-            *(int*) datum = PyBytes_AsString (argument)[0];
+            *(int*) datum = PyBytes_AsString(argument)[0];
             return 0;
 #ifdef PyByteArray_Check
         } else if (PyByteArray_Check(argument) && PyByteArray_Size(argument) == 1) {
-            *(int*) datum = PyByteArray_AsString (argument)[0];
+            *(int*) datum = PyByteArray_AsString(argument)[0];
             return 0;
 #endif
         } else {
 
     case _C_CHR:
         if (PyBytes_Check(argument) && PyBytes_Size(argument) == 1) {
-            *(int*) datum = PyBytes_AsString (argument)[0];
+            *(int*) datum = PyBytes_AsString(argument)[0];
             return 0;
 #ifdef PyByteArray_Check
         } else if (PyByteArray_Check(argument) && PyByteArray_Size(argument) == 1) {
-            *(int*) datum = PyByteArray_AsString (argument)[0];
+            *(int*) datum = PyByteArray_AsString(argument)[0];
             return 0;
 #endif
         }
     case _C_UCHR:
         if (PyBytes_Check(argument) && PyBytes_Size(argument) == 1) {
             *(unsigned int*) datum =
-                PyBytes_AsString (argument)[0];
+                PyBytes_AsString(argument)[0];
             return 0;
         }
         r = depythonify_unsigned_int_value(argument, "unsigned char",
 }
 
 PyObject *
-pythonify_c_return_value (const char *type, void *datum)
+pythonify_c_return_value(const char *type, void *datum)
 {
     PyObjC_Assert(type != NULL, NULL);
     PyObjC_Assert(datum != NULL, NULL);
 }
 
 int
-depythonify_c_value (const char *type, PyObject *argument, void *datum)
+depythonify_c_value(const char *type, PyObject *argument, void *datum)
 {
     PyObjC_Assert(type != NULL, -1);
     PyObjC_Assert(argument != NULL, -1);
 
     if (!datum) return 0;
 
-    type = PyObjCRT_SkipTypeQualifiers (type);
+    type = PyObjCRT_SkipTypeQualifiers(type);
 
     switch (*type) {
 #ifdef _C_ATOM
 
     case _C_CHR:
         if (PyBytes_Check(argument) && PyBytes_Size(argument) == 1) {
-            *(char*) datum = PyBytes_AsString (argument)[0];
+            *(char*) datum = PyBytes_AsString(argument)[0];
             return 0;
 #ifdef PyByteArray_Check
         } else if (PyByteArray_Check(argument) && PyByteArray_Size(argument) == 1) {
-            *(char*) datum = PyByteArray_AsString (argument)[0];
+            *(char*) datum = PyByteArray_AsString(argument)[0];
             return 0;
 #endif
         }
 
     case _C_CHAR_AS_TEXT:
         if (PyBytes_Check(argument) && PyBytes_Size(argument) == 1) {
-            *(char*) datum = PyBytes_AsString (argument)[0];
+            *(char*) datum = PyBytes_AsString(argument)[0];
             return 0;
 
 #ifdef PyByteArray_Check
         } else if (PyByteArray_Check(argument) && PyByteArray_Size(argument) == 1) {
-            *(char*) datum = PyByteArray_AsString (argument)[0];
+            *(char*) datum = PyByteArray_AsString(argument)[0];
             return 0;
 #endif
 
     case _C_UCHR:
         if (PyBytes_Check(argument) && PyBytes_Size(argument) == 1) {
             *(unsigned char*) datum =
-                PyBytes_AsString (argument)[0];
+                PyBytes_AsString(argument)[0];
             return 0;
 
 #ifdef PyByteArray_Check
         } else if (PyByteArray_Check(argument) && PyByteArray_Size(argument) == 1) {
-            *(unsigned char*) datum = PyByteArray_AsString (argument)[0];
+            *(unsigned char*) datum = PyByteArray_AsString(argument)[0];
             return 0;
 #endif
         }
         if (argument == Py_None) {
             *(SEL*)datum = NULL;
 
-        } else if (PyObjCSelector_Check (argument)) {
+        } else if (PyObjCSelector_Check(argument)) {
             *(SEL *) datum = PyObjCSelector_GetSelector(argument);
 
         } else if (PyUnicode_Check(argument)) {
             if (bytes == NULL) {
                 return -1;
             }
-            char *selname = PyBytes_AsString (bytes);
+            char *selname = PyBytes_AsString(bytes);
             SEL sel;
 
             if (*selname == '\0') {
                 Py_DECREF(bytes);
 
             } else {
-                sel = sel_getUid (selname);
+                sel = sel_getUid(selname);
                 Py_DECREF(bytes);
 
                 if (sel)  {
             }
 
         } else if (PyBytes_Check(argument)) {
-            char *selname = PyBytes_AsString (argument);
+            char *selname = PyBytes_AsString(argument);
             SEL sel;
 
             if (*selname == '\0') {
                 *(SEL*)datum = NULL;
 
             } else {
-                sel = sel_getUid (selname);
+                sel = sel_getUid(selname);
 
                 if (sel)  {
                     *(SEL*) datum = sel;
             }
 #ifdef PyByteArray_Check
         } else if (PyByteArray_Check(argument)) {
-            char *selname = PyByteArray_AsString (argument);
+            char *selname = PyByteArray_AsString(argument);
             SEL sel;
 
             if (*selname == '\0') {
                 *(SEL*)datum = NULL;
 
             } else {
-                sel = sel_getUid (selname);
+                sel = sel_getUid(selname);
 
                 if (sel)  {
                     *(SEL*) datum = sel;
             if (PyErr_Occurred()) {
                 return -1;
 
-            } else if (PyObjCPointer_Check (argument)) {
+            } else if (PyObjCPointer_Check(argument)) {
                 *(void **) datum = PyObjCPointer_Ptr(argument);
 
             } else {
         break;
 
     case _C_FLT:
-        if (PyFloat_Check (argument)) {
-            *(float *) datum = (float)PyFloat_AsDouble (argument);
+        if (PyFloat_Check(argument)) {
+            *(float *) datum = (float)PyFloat_AsDouble(argument);
 
 #if PY_MAJOR_VERSION == 2
-        } else if (PyInt_Check (argument)) {
-            *(float *) datum = (float) PyInt_AsLong (argument);
+        } else if (PyInt_Check(argument)) {
+            *(float *) datum = (float) PyInt_AsLong(argument);
 #endif
 
-        } else if (PyLong_Check (argument)) {
+        } else if (PyLong_Check(argument)) {
             *(float*) datum = (float) PyLong_AsDouble(argument);
             if (*(float*)datum == -1 && PyErr_Occurred()) {
                 return -1;
         break;
 
     case _C_DBL:
-        if (PyFloat_Check (argument)) {
-            *(double *) datum = PyFloat_AsDouble (argument);
+        if (PyFloat_Check(argument)) {
+            *(double *) datum = PyFloat_AsDouble(argument);
 
 #if PY_MAJOR_VERSION == 2
-        } else if (PyInt_Check (argument)) {
-            *(double *) datum = (double) PyInt_AsLong (argument);
+        } else if (PyInt_Check(argument)) {
+            *(double *) datum = (double) PyInt_AsLong(argument);
 #endif
 
-        } else if (PyLong_Check (argument)) {
-            *(double *) datum = PyLong_AsDouble (argument);
+        } else if (PyLong_Check(argument)) {
+            *(double *) datum = PyLong_AsDouble(argument);
             if (*(double*)datum == -1 && PyErr_Occurred()) {
                 return -1;
             }
         break;
 
     case _C_UNION_B:
-        if (PyBytes_Check (argument)) {
-            Py_ssize_t expected_size = PyObjCRT_SizeOfType (type);
+        if (PyBytes_Check(argument)) {
+            Py_ssize_t expected_size = PyObjCRT_SizeOfType(type);
 
             if (expected_size == -1) {
                 PyErr_Format(PyExc_ValueError,
                     "unknown size");
                 return -1;
 
-            } else if (expected_size != PyBytes_Size (argument)) {
+            } else if (expected_size != PyBytes_Size(argument)) {
                 PyErr_Format(PyExc_ValueError,
                     "depythonifying 'union' of size %"PY_FORMAT_SIZE_T"d, "
                     "got byte string of %"PY_FORMAT_SIZE_T"d",
                            expected_size,
-                           PyBytes_Size (argument));
+                           PyBytes_Size(argument));
                 return -1;
 
             } else {
-                memcpy ((void *) datum,
+                memcpy((void *) datum,
                     PyBytes_AS_STRING (argument),
                 expected_size);
             }
         break;
 
     case _C_STRUCT_B:
-        return depythonify_c_struct (type, argument, datum);
+        return depythonify_c_struct(type, argument, datum);
 
     case _C_ARY_B:
-        return depythonify_c_array (type, argument, datum);
+        return depythonify_c_array(type, argument, datum);
 
     default:
         PyErr_Format(PyExc_ValueError,
             type1++;
             while (isdigit(*type1)) type1++;
             return PyObjC_signatures_compatible(type1, type2+1);
+
         } else if (type2[0] == _C_ARY_B) {
             type1++;
             while (isdigit(*type1)) type1++;
         switch (*type2) {
         case _C_FLT: case _C_DBL:
             return YES;
+
          default:
             return NO;
         }
         if (*type2 == _C_ID) {
             return YES;
         }
+
         if (type2[0] == _C_PTR && type2[1] == _C_VOID) {
             return YES;
         }
+
         return NO;
 
     case _C_CHARPTR:
         if (*type2 == _C_CHARPTR) {
             return YES;
+
         } else if (*type2 == _C_PTR) {
             return PyObjC_signatures_compatible("c", type2+1);
+
         } else {
             return NO;
         }
         if (type1[1] == _C_VOID && type2[0] == _C_ID) {
             return YES;
         }
+
         if (*type2 == _C_CHARPTR) {
             return PyObjC_signatures_compatible(type1+1, "c");
         }
+
         if (*type2 != _C_PTR) {
             return NO;
         }
+
         if (type1[1] == _C_VOID || type2[1] == _C_VOID) {
             return YES;
         }
+
         return PyObjC_signatures_compatible(type1+1, type2+1);
 
-
     default:
         switch (*type2) {
         case _C_ID: case _C_PTR: return NO;

pyobjc-core/Modules/objc/objc_util.h

 extern PyObject* PyObjC_FindSELInDict(PyObject*, SEL);
 extern int PyObjCRT_SignaturesEqual(const char*, const char*);
 
+extern char* PyObjC_SELToPythonName(SEL, char*, size_t);
+
 static inline Py_ssize_t align(Py_ssize_t offset, Py_ssize_t alignment)
 {
     Py_ssize_t rest = offset % alignment;
     return offset + (alignment - rest);
 }
 
+/*
+ * SET_FIELD(op, value):
+ *    macro for updating the value of 'op' to 'value',
+ *    steals a reference to 'value'.
+ *
+ *    use this instead of 'Py_XDECREF(op); op = value'
+ */
+#define SET_FIELD(op, value)                    \
+    do {                                        \
+        PyObject* _py_tmp = (PyObject*)(op);    \
+        (op) = value;                           \
+        Py_XDECREF(_py_tmp);                    \
+    } while(0)
 
+/*
+ * SET_FIELD_INCREF(op, value):
+ *    macro for updating the value of 'op' to 'value'.
+ *
+ *    use this instead of 'Py_XDECREF(op); Py_INCREF(value); op = value'
+ */
+#define SET_FIELD_INCREF(op, value)             \
+    do {                                        \
+        PyObject* _py_tmp = (PyObject*)(op);    \
+        Py_XINCREF(value);                      \
+        (op) = value;                           \
+        Py_XDECREF(_py_tmp);                    \
+    } while(0)
 
 #endif /* OBJC_UTIL */

pyobjc-core/Modules/objc/objc_util.m

     Py_DECREF(values);
     return NULL;
 }
+
+char*
+PyObjC_SELToPythonName(SEL sel, char* buf, size_t buflen)
+{
+    size_t res = snprintf(buf, buflen, "%s", sel_getName(sel));
+    char* cur;
+
+    if (res != strlen(sel_getName(sel))) {
+        return NULL;
+    }
+
+    if (PyObjC_IsPythonKeyword(buf)) {
+        res = snprintf(buf, buflen, "%s__", sel_getName(sel));
+        if (res != 2+strlen(sel_getName(sel))) {
+            return NULL;
+        }
+        return buf;
+    }
+
+    cur = strchr(buf, ':');
+    while (cur) {
+        *cur = '_';
+        cur = strchr(cur, ':');
+    }
+    return buf;
+}

pyobjc-core/Modules/objc/options.m

     static int NAME ## _set(PyObject* s __attribute__((__unused__)),        \
             PyObject* newVal, void* c __attribute__((__unused__)))          \
     {                                                                       \
+        if (newVal == NULL) {                                               \
+            PyErr_SetString(PyExc_TypeError, "Cannot delete option '" STR(NAME) "'"); \
+            return -1;                                                      \
+        }                                                                   \
         VAR = PyObject_IsTrue(newVal) ? YES : NO;                           \
         return 0;                                                           \
     }
     static int NAME ## _set(PyObject* s __attribute__((__unused__)),        \
             PyObject* newVal, void* c __attribute__((__unused__)))          \
     {                                                                       \
+        if (newVal == NULL) {                                               \
+            PyErr_SetString(PyExc_TypeError, "Cannot delete option '" STR(NAME) "'"); \
+            return -1;                                                      \
+        }                                                                   \
         SET_FIELD_INCREF(VAR, newVal);                                      \
         return 0;                                                           \
     }
 static int _nscoding_version_set(PyObject* s __attribute__((__unused__)),
         PyObject* newVal, void* c __attribute__((__unused__)))
 {
+    if (newVal == NULL) {
+        PyErr_SetString(PyExc_TypeError, "Cannot delete option 'nscoding_version'");
+        return -1;
+    }
     if (PyArg_Parse(newVal, "i", &PyObjC_NSCoding_Version) < 0) {
         return -1;
     }

pyobjc-core/Modules/objc/pyobjc-api.h

 #else /* PyObjC_BUILD */
 
 extern struct pyobjc_api    objc_api;
+extern int PyObjCAPI_Register(PyObject* module);
 
 #endif /* !PYOBJC_BUILD */
 

pyobjc-core/Modules/objc/pyobjc-compat.h

 #define PyObjC__STR(x) #x
 #define PyObjC_STR(x) PyObjC__STR(x)
 
+/* Define PyObjC_UNICODE_FAST_PATH when
+ * 1) We're before Python 3.3, and
+ * 2) Py_UNICODE has the same size as unichar
+ *
+ * Python 3.3 has an optimized representation that
+ * makes it impossible (and unnecessary) to use the
+ * "fast path"
+ */
+#if PY_VERSION_HEX >= 0x03030000
 
+#undef PyObjC_UNICODE_FAST_PATH
 
+#elif Py_UNICODE_SIZE == 2
 
+#define PyObjC_UNICODE_FAST_PATH
 
+#endif
 
 #if PY_MAJOR_VERSION == 2
 

pyobjc-core/Modules/objc/pyobjc.h

  * headers
  */
 
-extern PyObject *PyObjCStrBridgeWarning;
-
-int PyObjCAPI_Register(PyObject* module);
-
 /* module.m */
 extern PyObject* PyObjC_TypeStr2CFTypeID;
 extern PyObject* PyObjC_callable_docstr_get(PyObject* callable, void* closure);
 #endif
 
 
-/*!
- * PYOBJC_EXPECTED_CLASS_COUNT: Hint about the number of classes to expect
- *
- * Loading Quartz results close to 5K classes on OSX 10.8
- */
-#define PYOBJC_EXPECTED_CLASS_COUNT 10000
-
-/*
- * SET_FIELD(op, value):
- *    macro for updating the value of 'op' to 'value',
- *    steals a reference to 'value'.
- *
- *    use this instead of 'Py_XDECREF(op); op = value'
- */
-#define SET_FIELD(op, value)                    \
-    do {                                        \
-        PyObject* _py_tmp = (PyObject*)(op);    \
-        (op) = value;                           \
-        Py_XDECREF(_py_tmp);                    \
-    } while(0)
-
-/*
- * SET_FIELD_INCREF(op, value):
- *    macro for updating the value of 'op' to 'value'.
- *
- *    use this instead of 'Py_XDECREF(op); Py_INCREF(value); op = value'
- */
-#define SET_FIELD_INCREF(op, value)             \
-    do {                                        \
-        PyObject* _py_tmp = (PyObject*)(op);    \
-        Py_XINCREF(value);                      \
-        (op) = value;                           \
-        Py_XDECREF(_py_tmp);                    \
-    } while(0)
-
-
-/* Define PyObjC_UNICODE_FAST_PATH when
- * 1) We're before Python 3.3, and
- * 2) Py_UNICODE has the same size as unichar
- *
- * Python 3.3 has an optimized representation that
- * makes it impossible (and unnecessary) to use the
- * "fast path"
- */
-#if PY_VERSION_HEX >= 0x03030000
-
-#undef PyObjC_UNICODE_FAST_PATH
-
-#elif Py_UNICODE_SIZE == 2
-
-#define PyObjC_UNICODE_FAST_PATH
-
-#endif
 
 #ifdef PyObjC_DEBUG
 
+#ifdef PyObjC_ERROR_ABORT
+#   define _PyObjC_InternalError_Bailout()    abort()
 
-#if 1 /* def PyObjCErr_InternalError */
-#define _PyObjC_InternalError_Bailout()    abort()
-#else
-#define _PyObjC_InternalError_Bailout()    ((void)0)
-#endif
+#else /* !PyObjC_ERROR_ABORT */
+#   define _PyObjC_InternalError_Bailout()    ((void)0)
+
+#endif /* !PyObjC_ERROR_ABORT */
 
 #define PyObjCErr_InternalError() 				\
     do { 							\

pyobjc-core/Modules/objc/selector.m

 {
     PyObjCNativeSelector* self = (PyObjCNativeSelector*)_self;
     char* t;
+
+    if (newVal == NULL) {
+        PyErr_SetString(PyExc_TypeError, "Cannot delete 'signature'");
+        return -1;
+    }
+
     if (!PyBytes_Check(newVal)) {
         PyErr_SetString(PyExc_TypeError, "signature must be byte string");
         return -1;
 static int
 base_hidden_setter(PyObject* _self, PyObject* newVal, void* closure __attribute__((__unused__)))
 {
+    if (newVal == NULL) {
+        PyErr_SetString(PyExc_TypeError, "Cannot delete 'isHidden'");
+        return -1;
+    }
+
     if (PyObject_IsTrue(newVal)) {
         ((PyObjCSelector*)_self)->sel_flags |= PyObjCSelector_kHIDDEN;
     } else {

pyobjc-core/NEWS.txt

 * PyObjC now supports blocks that have a large struct as the return value
   (for example a block that returns an NSRect structure).
 
+* Reduced the number of unnecessary methods implemented by the various
+  OC_Python* classes, this might affect some Objective-C code that directly
+  uses these classes instead of just using the interface of their
+  superclasses.
+
+* ``del NSObject.__version__`` crashed the interpreter because the setter
+  didn't guard against deletion attempts.
 
 Version 2.6
 -----------
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.