Commits

Ronald Oussoren  committed d22f7ee

Use runtime APIs for creating formal protocols

With this patch PyObjC uses the OSX 10.7 runtime API for
creating formal protocols. A compatibility API for doing this
on OSX 10.6 (32-bit) is also provided.

  • Participants
  • Parent commits e4f7fad

Comments (0)

Files changed (6)

File pyobjc-core/Modules/objc/formal-protocol.m

  */
 #include "pyobjc.h"
 
-/*
- * FIXME: Looking in the Protocol structure is a rather crude hack, especially with the Objective-C 2.0
- * runtime API. Too bad there is no real API for doing what we want...
- */
-struct Protocol_struct {
-#ifndef __OBJC2__
-	@defs(Protocol);
-#else
-	char *protocol_name;
-	struct objc_protocol_list *protocol_list;
-	struct objc_method_description_list *instance_methods, *class_methods;
-#endif
-};
-
 PyDoc_STRVAR(proto_cls_doc,
 "objc.formal_protocol(name, supers, selector_list)\n"
 "\n"
 	PyObject* selectors;
 	Py_ssize_t i, len;
 
-#ifndef __LP64__
 	PyObjCFormalProtocol* result = NULL;
-	Py_ssize_t numInstance = 0;
-	Py_ssize_t numClass = 0;
-	struct Protocol_struct* theProtocol = NULL;
-	struct objc_method_description* c;
-#endif
+	Protocol* theProtocol;
 
 	if (!PyArg_ParseTupleAndKeywords(args, kwds, "sOO:formal_protocol",
 			keywords, &name, &supers, &selectors)) { 
 		return NULL;
 	}
 
-#ifdef __LP64__
-	/* Radar #5272299: the objective-C 2.0 runtime API doesn't have an interface for constructing new 
-	 * formal protocols. We can kind-of fake this for now in 32-bit mode, but that won't work in 64-bit
-	 * mode due to additional flexibility in that mode (which in itself is a good thing).
-	 */
-	Py_DECREF(selectors);
-	PyErr_SetString(PyObjCExc_Error, "The Objective-C 2.0 runtime API doesn't allow creation of formal protocols");
-	return NULL;
-
-#else
-	/*
-	 * The code below isn't actually supported on the ObjC 2.0 runtime, but happens to work
-	 * in 32-bit mode. Radar #5272299 asks for a formal API to do this.
-	 */
-
-
 	len = PySequence_Fast_GET_SIZE(selectors);
 	for (i = 0; i < len; i++) {
 		PyObject* sel = PySequence_Fast_GET_ITEM(selectors, i);
-		if (sel == NULL || !PyObjCSelector_Check(sel)) {
-			PyErr_SetString(PyExc_TypeError,
-				"selectors need to be a sequence of selectors");
+		if (!PyObjCSelector_Check(sel)) {
+			PyErr_SetString(PyExc_TypeError, "Selectors is not a list of selectors");
 			Py_DECREF(supers);
-			Py_DECREF(selectors);
 			return NULL;
 		}
-		if (PyObjCSelector_GetFlags(sel)&PyObjCSelector_kCLASS_METHOD) {
-			numClass++;
-		} else {
-			numInstance++;
-		}
 	}
 
-	theProtocol = (struct Protocol_struct*)NSAllocateObject([Protocol class], 0, NULL);
+
+	if (objc_allocateProtocol == NULL) {
+		/* Protocol creation API is new in OSX 10.7, can will be weak-linked when
+		 * building on OSX 10.7 with a 10.6 deployment target.
+		 */
+		Py_DECREF(selectors);
+		PyErr_SetString(PyObjCExc_Error, "Cannot create formal protocols on this platform");
+		return NULL;
+	}
+
+	theProtocol = objc_allocateProtocol(name);
 	if (theProtocol == NULL) {
 		PyErr_NoMemory();
 		goto error;
 	}
 
-
-	theProtocol->protocol_name = strdup(name);
-	if (theProtocol->protocol_name == NULL) {
-		PyErr_NoMemory();
-		goto error;
+	if (supers != Py_None) {
+		len = PySequence_Fast_GET_SIZE(supers);
+		for (i = 0; i < len; i++) {
+			PyObject* v = PySequence_Fast_GET_ITEM(supers, i);
+			protocol_addProtocol(theProtocol, PyObjCFormalProtocol_GetProtocol(v));
+		}
 	}
 
-	if (supers == Py_None) {
-		theProtocol->protocol_list = NULL;
-	} else {
-		len = PySequence_Fast_GET_SIZE(supers);
-		theProtocol->protocol_list = malloc(
-			sizeof(struct objc_protocol_list) +
-			(1+len) * sizeof(Protocol*));
-		theProtocol->protocol_list->next = NULL;
-		theProtocol->protocol_list->count = len;
-		for (i = 0; i < len; i++) {
-			PyObject* v = PySequence_Fast_GET_ITEM(supers, i);
-			theProtocol->protocol_list->list[i] =
-				PyObjCFormalProtocol_GetProtocol(v);
-			if (theProtocol->protocol_list->list[i] == NULL) {
-				goto error;
-			}
-		}
-		theProtocol->protocol_list->list[i] = NULL;
-	}
-
-	if (numInstance != 0) {
-		theProtocol->instance_methods = malloc(
-			sizeof(struct objc_method_description_list) +
-			(1+numInstance)  * sizeof(struct objc_method_description));
-		if (theProtocol->instance_methods == NULL) {
-			PyErr_NoMemory();
-			goto error;
-		}
-		theProtocol->instance_methods->count = 0;
-	}
-	if (numClass != 0) {
-		theProtocol->class_methods = malloc(
-			sizeof(struct objc_method_description_list) + 
-			(1+numClass)  * sizeof(struct objc_method_description));
-		if (theProtocol->class_methods == NULL) {
-			PyErr_NoMemory();
-			goto error;
-		}
-		theProtocol->class_methods->count = 0;
-	}
 
 	len = PySequence_Fast_GET_SIZE(selectors);
 	for (i = 0; i < len; i++) {
 		SEL theSel = PyObjCSelector_GetSelector(sel);
 		const char* theSignature = PyObjCSelector_Signature(sel);
 
-		if (PyObjCSelector_GetFlags(sel)&PyObjCSelector_kCLASS_METHOD) {
-			c = &(theProtocol->class_methods->list[
-				theProtocol->class_methods->count++]);
-			c->name = theSel;
-			c->types = strdup(theSignature);
-			if (c->types == NULL) goto error;
-		} else {
-			c = &(theProtocol->instance_methods->list[
-				theProtocol->instance_methods->count++]);
-			c->name = theSel;
-			c->types = strdup(theSignature);
-			if (c->types == NULL) goto error;
-		}
+		protocol_addMethodDescription(theProtocol, theSel, theSignature, PyObjCSelector_Required(sel), !PyObjCSelector_IsClassMethod(sel));
 	}
 
-	if (theProtocol->instance_methods) {
-		c = &(theProtocol->instance_methods->list[
-			theProtocol->instance_methods->count]);
-		c->name = NULL;
-		c->types = NULL;
-	}
-
-	if (theProtocol->class_methods) {
-		c = &(theProtocol->class_methods->list[
-			theProtocol->class_methods->count]);
-		c->name = NULL;
-		c->types = NULL;
-	}
-
+	objc_registerProtocol(theProtocol);
 
 	result = (PyObjCFormalProtocol*)PyObject_New(
 			PyObjCFormalProtocol, &PyObjCFormalProtocol_Type);
 	Py_DECREF(selectors);
 	Py_DECREF(supers);
 
-	result->objc = (Protocol*)theProtocol;
+	result->objc = theProtocol;
 	PyObjC_RegisterPythonProxy(result->objc, (PyObject*)result);
 	return (PyObject*)result;
 
 	Py_DECREF(selectors);
 	Py_DECREF(supers);
 
-	if (theProtocol == NULL) return NULL;
-
-	if (theProtocol->protocol_name != NULL) {
-		free(theProtocol->protocol_name);
-	}
-
-	if (theProtocol->protocol_list != NULL) {
-		free(theProtocol->protocol_list);
-	}
-
-	if (theProtocol->instance_methods != NULL) {
-		for (i = 0; i < theProtocol->instance_methods->count; i++) {
-			c = theProtocol->instance_methods->list + i;
-			if (c->name) {
-				free(c->name);
-			}
-		}
-		free(theProtocol->instance_methods);
-	}
-
-	if (theProtocol->class_methods != NULL) {
-		for (i = 0; i < theProtocol->class_methods->count; i++) {
-			c = theProtocol->class_methods->list + i;
-			if (c->name) {
-				free(c->name);
-			}
-		}
-		free(theProtocol->class_methods);
-	}
 	return NULL;
-
-#endif /* !__LP64__ */
 }
 
 static PyObject*
 		aSelector = sel_getUid(s);
 #endif
 	} else {
-		PyErr_Format(PyExc_TypeError, "expecting a SEL, got instance of %s",
+		PyErr_Format(PyExc_TypeError, "expecting a SEL, got instance of '%s'",
 				Py_TYPE(sel)->tp_name);
 		return NULL;
 	}
 		aSelector = sel_getUid(s);
 #endif
 	} else {
-		PyErr_Format(PyExc_TypeError, "expecting a SEL, got instance of %s",
+		PyErr_Format(PyExc_TypeError, "expecting a SEL, got instance of '%s'",
 				Py_TYPE(sel)->tp_name);
 		return NULL;
 	}
 
 	if (!PyObjCFormalProtocol_Check(self)) {
 		PyErr_Format(PyExc_TypeError, 
-			"Expecting objc.formal_protocol, got %s",
+			"Expecting objc.formal_protocol, got instance of '%s'",
 			Py_TYPE(self)->tp_name);
 		return NULL;
 	}

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

 #define preclass_addMethod		PyObjC_preclass_addMethod
 #define preclass_addProtocol		PyObjC_preclass_addProtocol
 
-extern void PyObjC_SetupRuntimeCompat(void);
 
 extern BOOL (*PyObjC_preclass_addMethod)(Class, SEL, IMP, const char*);
 extern BOOL (*PyObjC_preclass_addIvar)(Class cls, 
 #define preclass_addMethod		class_addMethod
 #define preclass_addProtocol		class_addProtocol
 
-static inline void PyObjC_SetupRuntimeCompat(void) { }
 extern BOOL PyObjC_class_addMethodList(Class class, 
 		struct PyObjC_method* list, unsigned int count);
 
 #endif
 
 
+#if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7)
+extern Protocol* (*PyObjC_objc_allocateProtocol)(const char *);
+extern void (*PyObjC_objc_registerProtocol)(Protocol*);
+extern void (*PyObjC_protocol_addMethodDescription)(Protocol*, SEL, const char*, BOOL, BOOL);
+extern void (*PyObjC_protocol_addProtocol)(Protocol*, Protocol*);
+
+#ifndef PYOBJC_COMPAT_IMPL
+#define objc_allocateProtocol	PyObjC_objc_allocateProtocol
+#define objc_registerProtocol	PyObjC_objc_registerProtocol
+#define protocol_addMethodDescription	PyObjC_protocol_addMethodDescription
+#define protocol_addProtocol	PyObjC_protocol_addProtocol
+#endif
+
+#endif
+
+extern void PyObjC_SetupRuntimeCompat(void);
+
 #endif /* PyObjC_RUNTIME_COMPAT */

File pyobjc-core/Modules/objc/objc-runtime-compat.m

 
 
 
-void PyObjC_SetupRuntimeCompat(void)
-{
-#ifdef NO_OBJC2_RUNTIME
-	/* 
-	 * Don't use ObjC 2.0 runtime (compiling on 10.4 or earlier), always
-	 * use the compat implementation.
-	 */
-	PyObjC_class_addMethodList  = compat_class_addMethodList;
-	PyObjC_methodlist_magic     = compat_methodlist_magic;
-	PyObjC_objc_disposeClassPair   = compat_objc_disposeClassPair;
-	PyObjC_preclass_addMethod   = compat_preclass_addMethod;
-	PyObjC_preclass_addIvar     = compat_preclass_addIvar;
-	PyObjC_preclass_addProtocol = compat_preclass_addProtocol;
-
-#   define SETUP(funcname) \
-		PyObjC_##funcname = compat_##funcname
-
-#else
-	if (class_addMethod) {
-		PyObjC_class_addMethodList = objc20_class_addMethodList;
-		PyObjC_preclass_addMethod  = class_addMethod;
-		PyObjC_preclass_addIvar    = class_addIvar;
-		PyObjC_preclass_addProtocol= class_addProtocol;
-	} else {
-		PyObjC_class_addMethodList = compat_class_addMethodList;
-		PyObjC_preclass_addMethod  = compat_preclass_addMethod;
-		PyObjC_preclass_addIvar    = compat_preclass_addIvar;
-		PyObjC_preclass_addProtocol= compat_preclass_addProtocol;
-	}
-
-
-	if (class_copyMethodList) {
-		PyObjC_methodlist_magic = objc20_methodlist_magic;
-	} else {
-		PyObjC_methodlist_magic = compat_methodlist_magic;
-	}
-
-#   define SETUP(funcname) \
-	if ((funcname) == NULL) { \
-		PyObjC_##funcname = compat_##funcname; \
-	} else { \
-		PyObjC_##funcname = funcname; \
-	} 
-#endif
-	SETUP(protocol_getName);
-	SETUP(protocol_conformsToProtocol);
-	SETUP(protocol_copyMethodDescriptionList);
-	SETUP(protocol_copyProtocolList);
-	SETUP(protocol_getMethodDescription);
-
-	SETUP(objc_allocateClassPair);
-	SETUP(objc_registerClassPair);
-	SETUP(objc_disposeClassPair);
-	SETUP(objc_copyProtocolList);
-
-	SETUP(object_getClass);
-	SETUP(object_setClass);
-	SETUP(object_getClassName);
-	SETUP(object_getIvar);
-	SETUP(object_setIvar);
-
-	SETUP(class_getSuperclass);
-	SETUP(class_addMethod);
-	SETUP(class_copyIvarList);
-	SETUP(class_copyProtocolList);
-	SETUP(class_copyMethodList);
-	SETUP(class_getName);
-	SETUP(class_isMetaClass);
-
-	SETUP(method_getName);
-	SETUP(method_getTypeEncoding);
-	SETUP(method_getImplementation);
-	SETUP(method_setImplementation);
-
-	SETUP(sel_isEqual);
-
-	SETUP(ivar_getName);
-	SETUP(ivar_getTypeEncoding);
-	SETUP(ivar_getOffset);
-#undef SETUP
-
-}
 
 #else
 
 	
 
 #endif
+
+#if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7)
+Protocol* (*PyObjC_objc_allocateProtocol)(const char *) = NULL;
+void (*PyObjC_objc_registerProtocol)(Protocol*) = NULL;
+void (*PyObjC_protocol_addMethodDescription)(Protocol*, SEL, const char*, BOOL, BOOL) = NULL;
+void (*PyObjC_protocol_addProtocol)(Protocol*, Protocol*) = NULL;
+
+#ifndef __LP64__
+struct Protocol_struct {
+	char *protocol_name;
+	struct objc_protocol_list *protocol_list;
+	struct objc_method_description_list *instance_methods, *class_methods;
+	struct objc_method_description_list *optional_instance_methods, *optional_class_methods;
+	void *instance_properties;
+};
+
+static Protocol* compat_objc_allocateProtocol(const char *name)
+{
+	struct Protocol_struct* result;
+
+	result = (struct Protocol_struct*)NSAllocateObject([Protocol class], 0, NULL);
+	if (result == NULL) {
+		return NULL;
+	}
+	result->protocol_name = strdup(name);
+	if (result->protocol_name == NULL) {
+		/* Leaking object */
+		return NULL;
+	}
+	result->protocol_list = NULL;
+	result->instance_methods = NULL;
+	result->class_methods = NULL;
+	result->optional_instance_methods = NULL;
+	result->optional_class_methods = NULL;
+	result->instance_properties = NULL;
+	return (Protocol*)result;
+}
+
+static void compat_objc_registerProtocol(Protocol* proto __attribute__((__unused__)))
+{
+	/* Don't know how to register a new protocol in classic
+	 * runtime. Luckily we don't actually need this.
+	 */
+}
+
+static void compat_protocol_addMethodDescription(Protocol* proto, SEL sel, const char* types, BOOL required, BOOL instance_method)
+{
+	struct Protocol_struct* proto_struct = (struct Protocol_struct*)proto;
+	struct objc_method_description_list** plist;
+
+	if (!instance_method) {
+		if (required) {
+			plist = &(proto_struct->class_methods);
+		} else {
+			plist = &(proto_struct->optional_class_methods);
+		}
+	} else {
+		if (required) {
+			plist = &(proto_struct->instance_methods);
+		} else {
+			plist = &(proto_struct->optional_instance_methods);
+		}
+	}
+
+	if (*plist == NULL) {
+		*plist = malloc(sizeof(struct objc_method_description_list) + (2*sizeof(struct objc_method_description)));
+		if (*plist == NULL) {
+			/* Cannot report errors */
+			abort();
+		}
+		(*plist)->count = 0;
+	} else {
+		*plist = realloc(*plist, sizeof(struct objc_method_description_list) + (2+((*plist)->count)*sizeof(struct objc_method_description)));
+	}
+	(*plist)->list[(*plist)->count].name = sel;
+	(*plist)->list[(*plist)->count].types = strdup(types);
+	if ((*plist)->list[(*plist)->count].types == NULL) {
+		/* Cannot report errors */
+		abort();
+	}
+
+	(*plist)->list[(*plist)->count+1].name = NULL;
+	(*plist)->list[(*plist)->count+1].types = NULL;
+	(*plist)->count++;
+}
+
+static void compat_protocol_addProtocol(Protocol* proto, Protocol* newProto)
+{
+	struct Protocol_struct* proto_struct = (struct Protocol_struct*)proto;
+
+	if (proto_struct->protocol_list == NULL) {
+		proto_struct->protocol_list = malloc(sizeof(struct objc_protocol_list) + 2*sizeof(Protocol*));
+		if (proto_struct->protocol_list == NULL) {
+			/* Cannot report an error! */
+			abort();
+		}
+		proto_struct->protocol_list->next = NULL;
+		proto_struct->protocol_list->count = 0;
+	} else {
+		proto_struct->protocol_list = realloc(proto_struct->protocol_list,
+				sizeof(struct objc_protocol_list) + (2+proto_struct->protocol_list->count)*sizeof(Protocol*));
+		if (proto_struct->protocol_list == NULL) {
+			/* Cannot report an error! */
+			abort();
+		}
+	}
+	proto_struct->protocol_list->list[proto_struct->protocol_list->count] = newProto;
+	proto_struct->protocol_list->list[proto_struct->protocol_list->count+1] = NULL;
+	proto_struct->protocol_list->count++;
+}
+
+#endif
+#endif
+
+
+void PyObjC_SetupRuntimeCompat(void)
+{
+#if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5)  && !defined(__OBJC2__)
+
+#ifdef NO_OBJC2_RUNTIME
+	/* 
+	 * Don't use ObjC 2.0 runtime (compiling on 10.4 or earlier), always
+	 * use the compat implementation.
+	 */
+	PyObjC_class_addMethodList  = compat_class_addMethodList;
+	PyObjC_methodlist_magic     = compat_methodlist_magic;
+	PyObjC_objc_disposeClassPair   = compat_objc_disposeClassPair;
+	PyObjC_preclass_addMethod   = compat_preclass_addMethod;
+	PyObjC_preclass_addIvar     = compat_preclass_addIvar;
+	PyObjC_preclass_addProtocol = compat_preclass_addProtocol;
+
+#   define SETUP(funcname) \
+		PyObjC_##funcname = compat_##funcname
+
+#else
+	if (class_addMethod) {
+		PyObjC_class_addMethodList = objc20_class_addMethodList;
+		PyObjC_preclass_addMethod  = class_addMethod;
+		PyObjC_preclass_addIvar    = class_addIvar;
+		PyObjC_preclass_addProtocol= class_addProtocol;
+	} else {
+		PyObjC_class_addMethodList = compat_class_addMethodList;
+		PyObjC_preclass_addMethod  = compat_preclass_addMethod;
+		PyObjC_preclass_addIvar    = compat_preclass_addIvar;
+		PyObjC_preclass_addProtocol= compat_preclass_addProtocol;
+	}
+
+
+	if (class_copyMethodList) {
+		PyObjC_methodlist_magic = objc20_methodlist_magic;
+	} else {
+		PyObjC_methodlist_magic = compat_methodlist_magic;
+	}
+
+#   define SETUP(funcname) \
+	if ((funcname) == NULL) { \
+		PyObjC_##funcname = compat_##funcname; \
+	} else { \
+		PyObjC_##funcname = funcname; \
+	} 
+#endif
+	SETUP(protocol_getName);
+	SETUP(protocol_conformsToProtocol);
+	SETUP(protocol_copyMethodDescriptionList);
+	SETUP(protocol_copyProtocolList);
+	SETUP(protocol_getMethodDescription);
+
+	SETUP(objc_allocateClassPair);
+	SETUP(objc_registerClassPair);
+	SETUP(objc_disposeClassPair);
+	SETUP(objc_copyProtocolList);
+
+	SETUP(object_getClass);
+	SETUP(object_setClass);
+	SETUP(object_getClassName);
+	SETUP(object_getIvar);
+	SETUP(object_setIvar);
+
+	SETUP(class_getSuperclass);
+	SETUP(class_addMethod);
+	SETUP(class_copyIvarList);
+	SETUP(class_copyProtocolList);
+	SETUP(class_copyMethodList);
+	SETUP(class_getName);
+	SETUP(class_isMetaClass);
+
+	SETUP(method_getName);
+	SETUP(method_getTypeEncoding);
+	SETUP(method_getImplementation);
+	SETUP(method_setImplementation);
+
+	SETUP(sel_isEqual);
+
+	SETUP(ivar_getName);
+	SETUP(ivar_getTypeEncoding);
+	SETUP(ivar_getOffset);
+#endif /* MIN_REQUIRED < 10.5 && !OBJC2 */
+
+
+#if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7)
+	/* Compat definitions for protocol creation
+	 *
+	 * - Runtime APIs were introduced in OSX 10.7
+	 * - Compat functions can only be implemented for 32-bit runtime
+	 */
+
+#if PyObjC_BUILD_RELEASE < 1007
+	
+#ifndef __LP64__
+	PyObjC_objc_allocateProtocol = compat_objc_allocateProtocol;
+	PyObjC_objc_registerProtocol = compat_objc_registerProtocol;
+	PyObjC_protocol_addMethodDescription = compat_protocol_addMethodDescription;
+	PyObjC_protocol_addProtocol = compat_protocol_addProtocol;
+#endif
+
+#ifdef SETUP 
+#undef SETUP
+#endif
+
+#elif defined(__LP64__)
+	PyObjC_objc_allocateProtocol = objc_allocateProtocol;
+	PyObjC_objc_registerProtocol = objc_registerProtocol;
+	PyObjC_protocol_addMethodDescription = protocol_addMethodDescription;
+	PyObjC_protocol_addProtocol = protocol_addProtocol;
+
+#else
+#   define SETUP(funcname) \
+	if ((funcname) == NULL) { \
+		PyObjC_##funcname = compat_##funcname; \
+	} else { \
+		PyObjC_##funcname = funcname; \
+	} 
+	SETUP(objc_allocateProtocol);
+	SETUP(objc_registerProtocol);
+	SETUP(protocol_addMethodDescription);
+	SETUP(protocol_addProtocol);
+#endif
+
+#endif
+
+#undef SETUP
+}

File pyobjc-core/NEWS.txt

 Version 2.4  (or 3.0)
 ---------------------
 
+- Creating new formal protocols now uses the new runtime API that was
+  introduced in OSX 10.7. Because of this it is now possible to create
+  new formal protocols in 64-bit code (when running on OSX 10.7 or later)
+
 - Codebase should work again when Python using ``--enable-unicode=ucs4``.
 
 - BUG: Avoid crashes in calculating with NSDecimal values in Python 3

File pyobjc-core/PyObjCTest/test3_protocol.py

 from PyObjCTools.TestSupport import *
 import objc
 import warnings
+import platform
 import sys
 
 # Most useful systems will at least have 'NSObject'.
 
 
 
-if sys.maxsize < 2 ** 32:
+if (sys.maxsize < 2 ** 32) or (platform.mac_ver()[0] >= '10.7'):
     EmptyProtocol = objc.formal_protocol("EmptyProtocol", None, ())
 
     MyProtocol = objc.formal_protocol("MyProtocol", None, (

File pyobjc-core/PyObjCTest/test_protocol.py

 import objc
 import warnings
 import sys
+import platform
 
 # Most useful systems will at least have 'NSObject'.
 NSObject = objc.lookUpClass('NSObject')
 
 
 
-if sys.maxsize < 2 ** 32 and sys.version_info[0] == 2:
+if (sys.maxsize < 2 ** 32 or platform.mac_ver()[0] >= '10.7') and sys.version_info[0] == 2:
     EmptyProtocol = objc.formal_protocol("EmptyProtocol", None, ())
 
     MyProtocol = objc.formal_protocol("MyProtocol", None, (