Commits

Ronald Oussoren  committed b2d1dc2

Making progress, down to 26 failures and 8 errors. Looking up class methods now works, objc.super still does not work

  • Participants
  • Parent commits c9ee09b
  • Branches core-cleanup

Comments (0)

Files changed (16)

File pyobjc-core/Lib/PyObjCTools/TestSupport.py

         if any(x is tp for x in _nscftype):
             self.fail(message or "%r is not a unique CFTypeRef type"%(tp,))
 
-        #if not issubclass(tp, _nscftype):
-        #    self.fail(message or "%r is not a CFTypeRef subclass"%(tp,))
+        if not issubclass(tp, _nscftype):
+            self.fail(message or "%r is not a CFTypeRef subclass"%(tp,))
 
 
     def assertIsOpaquePointer(self, tp, message = None):

File pyobjc-core/Modules/objc/OC_PythonObject.m

 {
 	Method		   m;
 
-	m = class_getInstanceMethod(self, sel);
+	m = class_getClassMethod(self, sel);
 	if (m) {
 		/* A real Objective-C method */
 		return [NSMethodSignature 

File pyobjc-core/Modules/objc/method-signature.m

 
 	r = snprintf(buf, buflen, "%s", [sig methodReturnType]);
 	if (r > buflen) {
-		printf("overflow for return type\n");
 		return NULL;
 	}
 
 	for (i = 0; i < arg_count; i++) {
 		r = snprintf(buf, buflen, "%s", [sig getArgumentTypeAtIndex:i]);
 		if (r > buflen) {
-			printf("overflow for argument %d %s %d %d\n", i, buf, (int)buflen, (int)r);
 			return NULL;
 		}
 

File pyobjc-core/Modules/objc/module.m

 		PyObjC_INITERROR();
 	}
 
-
+#if 0
+	if (setup_class_meta() < 0) {
+		PyObjC_INITERROR();
+	}
+#else
+	if (PyType_Ready(&PyObjCMetaClass_Type) < 0) {
+		PyObjC_INITERROR();
+	}
+#endif
 	if (PyType_Ready(&PyObjCClass_Type) < 0) {
 		PyObjC_INITERROR();
 	}
 	}
 	/* use PyDict_SetItemString for the retain, non-heap types can't be dealloc'ed */
 
+	if (PyDict_SetItemString(d, "objc_meta_class", (PyObject*)&PyObjCMetaClass_Type) < 0) {
+		PyObjC_INITERROR();
+	}
 	if (PyDict_SetItemString(d, "objc_class", (PyObject*)&PyObjCClass_Type) < 0) {
 		PyObjC_INITERROR();
 	}

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

  * @const PyObjCClass_Type
  * @abstract The type objc.objc_class
  */
+extern PyTypeObject PyObjCMetaClass_Type;
 extern PyTypeObject PyObjCClass_Type;
 
+/*extern int setup_class_meta(void);*/
+
+
 /*!
  * @function PyObjCClass_Check
  * @abstract Check if an object is an Objective-C class
  * @result Returns True if the object is an Objective-C class, false otherwise
  */
 #define PyObjCClass_Check(obj) PyObject_TypeCheck(obj, &PyObjCClass_Type)
+#define PyObjCMetaClass_Check(obj) PyObject_TypeCheck(obj, &PyObjCMetaClass_Type)
 
 // The @const is not correct, but what else can we use here?
 /*!
 	PyObject* sel_to_py;
 	Py_ssize_t dictoffset;
 	PyObject* delmethod;
-	int hasPythonImpl;
-	int isCFWrapper;
 	int generation;
-	int useKVO;
 	PyObject* hiddenSelectors;
 	PyObject* hiddenClassSelectors;
-	struct _PyObjCClassObject* meta_class; /* To be dropped */
+
+	int  useKVO; 	/* FIXME: swith to getset in python API  and switch this to a bitfield as well. */
+	unsigned int hasPythonImpl:1;
+	unsigned int isCFWrapper:1;
 } PyObjCClassObject;
 
+
 extern PyObject* PyObjCClass_DefaultModule;
 PyObject* PyObjCClass_New(Class objc_class);
 Class PyObjCClass_GetClass(PyObject* object);
 
 PyObject* PyObjCClass_ListProperties(PyObject* cls);
 
+/* Returns a borrowed reference or NULL (without necessarily raising an exception) */
+PyObject* PyObjCClass_TryResolveSelector(PyObject* base, PyObject* name, SEL sel);
+
 
 #endif /* PyObjC_OBJC_CLASS_H */

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

 
 	result = (PyTypeObject*)PyType_Type.tp_new(&PyType_Type, args, NULL);
 	Py_DECREF(args);
-	if (result == NULL) return NULL;
+	if (result == NULL) {
+		PyErr_Print();
+		abort();
+		return NULL;
+	}
+
+	((PyObjCClassObject*)result)->class = objc_meta_class;
 
 	if (objc_class_register(objc_meta_class, (PyObject*)result) == -1) {
 		Py_DECREF(result);
 class_repr(PyObject* obj)
 {
 	Class cls = PyObjCClass_GetClass(obj);
-
 	if (cls) {
 		const char* nm = class_getName(cls);
 		if (strstr(nm, "NSCFType") != NULL) {
 				nm, (void*)cls);
 		}
 	} else {
-		return PyText_FromFormat(
-			"%s", "<objective-c class NIL>");
+		return PyText_FromString("<class objc.objc_class>");
 	}
 }
 
 
 
 static PyObject*
+metaclass_getattro(PyObject* self, PyObject* name)
+{
+	return PyObject_GenericGetAttr(self, name);
+}
+
+
+/* FIXME: This is a lightly modified version of _type_lookup in objc-object.m, need to merge these */
+static inline PyObject*
+_type_lookup(PyTypeObject* tp, PyObject* name, PyObject* name_bytes)
+{
+	Py_ssize_t i, n;
+	PyObject *mro, *base, *dict;
+	PyObject *descr = NULL;
+	PyObject* res;
+	SEL	  sel = PyObjCSelector_DefaultSelector(PyBytes_AsString(name_bytes));
+
+	/* TODO: if sel.startswith('__') and sel.endswith('__'): look_in_runtime = False */
+
+	/* Look in tp_dict of types in MRO */
+	mro = tp->tp_mro;
+	if (mro == NULL) {
+		return NULL;
+	}
+	res = NULL;
+	assert(PyTuple_Check(mro));
+	n = PyTuple_GET_SIZE(mro);
+	for (i = 0; i < n; i++) {
+		base = PyTuple_GET_ITEM(mro, i);
+#if 0
+		if (PyObjCClass_Check(base)) {
+			PyObjCClass_CheckMethodList(base, 0);
+			dict = ((PyTypeObject *)base)->tp_dict;
+
+		} else 
+#endif
+			if (PyType_Check(base)) {
+			dict = ((PyTypeObject *)base)->tp_dict;
+
+
+#if PY_MAJOR_VERSION == 2
+		} else if (PyClass_Check(base)) {
+			dict = ((PyClassObject*)base)->cl_dict;
+#endif
+		} else {
+			return NULL;
+		}
+		assert(dict && PyDict_Check(dict));
+		descr = PyDict_GetItem(dict, name);
+		if (descr != NULL) {
+			break;
+		}
+
+		if (PyObject_IsSubclass(base, (PyObject*)&PyObjCMetaClass_Type)) {
+			Class cls = objc_metaclass_locate(base);
+			int is_class = 1;
+			Method m = class_getClassMethod(cls, sel);
+
+			if (!m) {
+				/* XXX: This isn't quite correct, this is used to fake
+				 *      access to the class __dict__ and explicitly share
+				 *      functionality with _type_lookup in objc-object.m
+				 *      (that is called from class_getattro)
+				 */
+				PyObjC_DURING
+					m = class_getInstanceMethod(cls, sel);
+				PyObjC_HANDLER
+
+					/* Annoyingly enough this can result in callbacks to ObjC
+					 * that can raise an exception.
+					 */
+					m = NULL;
+			        PyObjC_ENDHANDLER
+
+				is_class = 0;
+			}
+
+			if (m) {
+				int use = 1;
+				Class sup = class_getSuperclass(cls);
+				if (sup) {
+					Method m_sup;
+					if (is_class) {
+						m_sup = class_getClassMethod(sup, sel);
+					} else {
+						m_sup = class_getInstanceMethod(sup, sel);
+					}
+					if (m_sup == m) {
+						use = 0;
+					}
+				}
+				if (!use) continue;
+
+				/* Create (unbound) selector */
+				PyObject* result = PyObjCSelector_NewNative(
+						cls, sel, method_getTypeEncoding(m), is_class);
+				if (result == NULL) {
+					return NULL;
+				}
+
+
+				/* add to __dict__ 'cache' */
+				if (PyDict_SetItem(dict, name, result) == -1) {
+					Py_DECREF(result);
+					return NULL;
+				}
+				
+				/* and return, as a borrowed reference */
+				Py_DECREF(result);
+				return result;
+			}
+		}
+#if 0
+		if (PyObjCClass_Check(base)) {
+			/* Check if the name is a selector that
+			 * is not cached yet 
+			 *
+			 * XXX: Once this works try to avoid calling class_getInstanceMethod too often
+			 */
+			Class cls = PyObjCClass_GetClass(base);
+			Method m = class_getInstanceMethod(cls, sel);
+			if (m) {
+				int use = 1;
+				Class sup = class_getSuperclass(cls);
+				if (sup) {
+					Method m_sup = class_getInstanceMethod(sup, sel);
+					if (m_sup == m) {
+						use = 0;
+					}
+				}
+				if (!use) continue;
+
+				/* Create (unbound) selector */
+				PyObject* result = PyObjCSelector_NewNative(
+						cls, sel, method_getTypeEncoding(m), 0);
+				if (result == NULL) {
+					return NULL;
+				}
+
+
+				/* add to __dict__ 'cache' */
+				if (PyDict_SetItem(dict, name, result) == -1) {
+					Py_DECREF(result);
+					return NULL;
+				}
+				
+				/* and return */
+				return result;
+			}
+		}
+#endif
+	}
+
+	return descr;
+}
+
+static PyObject*
 class_getattro(PyObject* self, PyObject* name)
 {
-	PyObject* result = NULL;
+	PyObject *descr = NULL;
+	PyObject *result = NULL;
+	PyObject *bytes;
+	descrgetfunc f;
+
 	/* Python will look for a number of "private" attributes during 
 	 * normal operations, such as when building subclasses. Avoid a
 	 * method rescan when that happens.
 	 *       class).
 	 *       
 	 */
-	if (PyUnicode_Check(name)
-			&& PyObjC_is_ascii_prefix(name, "__", 2)
-			&& !PyObjC_is_ascii_string(name, "__dict__")) {
-		result = PyType_Type.tp_getattro(self, name);
-		if (result != NULL) {
-			return result;
+	if (PyUnicode_Check(name)) {
+		if (PyObjC_is_ascii_prefix(name, "__", 2) && !PyObjC_is_ascii_string(name, "__dict__")) {
+			result = PyType_Type.tp_getattro(self, name);
+			if (result != NULL) {
+				return result;
+			}
+			PyErr_Clear();
 		}
-		PyErr_Clear();
+
+	  	bytes = PyUnicode_AsEncodedString(name, NULL, NULL);
+		if (bytes == NULL) return NULL;
+
+#if PY_MAJOR_VERSION == 2
+	} else if (PyString_Check(name)) {
+		if (strncmp(PyString_AS_STRING(name), "__", 2) == 0 && strcmp(PyString_AS_STRING(name), "__dict__") != 0) {
+			result = PyType_Type.tp_getattro(self, name);
+			if (result != NULL) {
+				return result;
+			}
+			PyErr_Clear();
+		}
+
+		bytes = name;
+		Py_INCREF(bytes);
+#endif
+	} else {
+		PyErr_Format(PyExc_TypeError, "Attribute name is not a string, but an instance of '%s'", 
+				Py_TYPE(name)->tp_name);
+		return NULL;
 	}
-
-#if PY_MAJOR_VERSION == 2
-	else if (PyString_Check(name) 
-			&& strncmp(PyString_AS_STRING(name), "__", 2) == 0 
-			&& strcmp(PyString_AS_STRING(name), "__dict__") != 0) {
-		result = PyType_Type.tp_getattro(self, name);
-		if (result != NULL) {
-			return result;
-		}
-		PyErr_Clear();
-	}
-#endif
 	PyObjCClass_CheckMethodList(self, 1);
 	
-	result = PyType_Type.tp_getattro(self, name);
-	if (result != NULL) {
-		return result;
+	descr = _type_lookup(Py_TYPE(self), name, bytes);
+
+	f = NULL;
+	if (descr != NULL 
+#if PY_MAJOR_VERSION == 2
+		&& PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_HAVE_CLASS)
+#endif
+	    ) {
+		f = Py_TYPE(descr)->tp_descr_get;
+		if (f != NULL && PyDescr_IsData(descr)) {
+			result = f(descr, self, (PyObject*)Py_TYPE(self));
+			goto done;
+		}
+	}
+
+	if (strcmp(PyBytes_AS_STRING(bytes), "__dict__") == 0) {
+		result = ((PyTypeObject*)self)->tp_dict;
+		goto done;
+
+	} else {
+		result = PyDict_GetItem(((PyTypeObject*)self)->tp_dict, name);
+		if (result != NULL) {
+			Py_INCREF(result);
+			goto done;
+		}
+	}
+
+	if (f != NULL) {
+		result = f(descr, self, (PyObject*)Py_TYPE(self));
+		goto done;
+	}
+
+	if (descr != NULL) {
+		Py_INCREF(descr);
+		result = descr;
+		goto done;
 	}
 
 
 
 	/* Try to find the method anyway */
 	PyErr_Clear();
-	if (PyUnicode_Check(name)) {
-		PyObject* bytes = PyUnicode_AsEncodedString(name, NULL, NULL);
-		if (bytes == NULL) {
-			return NULL;
-		}
-		if (PyObjCClass_HiddenSelector(self, sel_getUid(PyBytes_AsString(bytes)), YES)) {
-			Py_DECREF(bytes);
-			PyErr_SetObject(PyExc_AttributeError, name);
-			return NULL;
-		}
-		result = PyObjCSelector_FindNative(self, PyBytes_AsString(bytes));
+	if (PyObjCClass_HiddenSelector(self, sel_getUid(PyBytes_AsString(bytes)), YES)) {
 		Py_DECREF(bytes);
-#if PY_MAJOR_VERSION == 2
-	} else if (PyString_Check(name)) {
-		if (PyObjCClass_HiddenSelector(self, sel_getUid(PyString_AsString(name)), YES)) {
-			PyErr_SetObject(PyExc_AttributeError, name);
-			return NULL;
-		}
-		result = PyObjCSelector_FindNative(self, PyString_AsString(name));
-#endif
-	} else {
-		PyErr_SetString(PyExc_TypeError, "Attribute name is not a string");
+		PyErr_SetObject(PyExc_AttributeError, name);
 		return NULL;
 	}
+	result = PyObjCSelector_FindNative(self, PyBytes_AsString(bytes));
 
 	if (result != NULL) {
 		int res = PyDict_SetItem(((PyTypeObject*)self)->tp_dict, name, result);
 			PyErr_Clear();
 		}
 	}
+done:
+	Py_DECREF(bytes);
 	return result;
 }
 
 	{ 0, 0, 0, 0, 0 }
 };
 
+static PyObject* 
+meth_dir(PyObject* self)
+{
+	PyObject* result;
+	Class     cls;
+	Method*   methods;
+	unsigned int method_count, i;
+	char      selbuf[1024];
+
+	/* Start of with keys in __dict__ */
+	result = PyDict_Keys(((PyTypeObject*)self)->tp_dict);
+	if (result == NULL) {
+		return NULL;
+	}
+
+	cls = PyObjCClass_GetClass(self);
+
+	while (cls != NULL) {
+		/* Now add all method names */
+		methods = class_copyMethodList(cls, &method_count);
+		for (i = 0; i < method_count; i++) {
+			char* name;
+			PyObject* item;
+
+			/* Check if the selector should be hidden */
+			if (PyObjCClass_HiddenSelector((PyObject*)Py_TYPE(self),  /* XXX */
+						method_getName(methods[i]), NO)) {
+				continue;
+			}
+
+			name = (char*)PyObjC_SELToPythonName(
+						method_getName(methods[i]), 
+						selbuf, 
+						sizeof(selbuf));
+			if (name == NULL) continue;
+
+			item = PyText_FromString(name);
+			if (item == NULL) {
+				free(methods);
+				Py_DECREF(result);
+				return NULL;
+			}
+
+			if (PyList_Append(result, item) == -1) {
+				free(methods);
+				Py_DECREF(result);
+				Py_DECREF(item);
+				return NULL;
+			}
+			Py_DECREF(item);
+		}
+		free(methods);
+
+		cls = class_getSuperclass(cls);
+	}
+	return result;
+}
+
+
+static PyMethodDef class_methods[] = {
+	{
+		"__dir__",
+		(PyCFunction)meth_dir,
+		METH_NOARGS,
+		"dir() hook, don't call directly"
+	},
+	{
+		NULL,
+		NULL,
+		0,
+		NULL
+	}
+};
+
 static PyMemberDef class_members[] = {
 	{
 		"__useKVO__",
 };
 
 
+/*
+ * 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
+ * class methods.
+ */
+PyTypeObject PyObjCMetaClass_Type = {
+	PyVarObject_HEAD_INIT(&PyType_Type, 0)
+	"objc_meta_class",			/* tp_name */
+	sizeof (PyHeapTypeObject),		/* tp_basicsize */
+	sizeof (PyMemberDef),			/* tp_itemsize */
+	/* methods */
+	0,		 			/* tp_dealloc */
+	0,					/* tp_print */
+	0,					/* tp_getattr */
+	0,					/* tp_setattr */
+	0,					/* tp_compare */
+	0,					/* tp_repr */
+	0,					/* tp_as_number */
+	0,					/* tp_as_sequence */
+	0,		       			/* tp_as_mapping */
+	0,					/* tp_hash */
+	0,					/* tp_call */
+	0,					/* tp_str */
+	metaclass_getattro,			/* tp_getattro */
+	PyObject_GenericSetAttr,		/* tp_setattro */
+	0,					/* tp_as_buffer */
+	Py_TPFLAGS_DEFAULT,
+		// | Py_TPFLAGS_BASETYPE,		/* tp_flags */
+	0,					/* tp_doc */
+	0,					/* tp_traverse */
+	0,					/* tp_clear */
+	0,					/* tp_richcompare */
+	0,					/* tp_weaklistoffset */
+	0,					/* tp_iter */
+	0,					/* tp_iternext */
+	0,					/* tp_methods */
+	0,					/* tp_members */
+	0,					/* tp_getset */
+	&PyType_Type,				/* tp_base */
+	0,					/* tp_dict */
+	0,					/* tp_descr_get */
+	0,					/* tp_descr_set */
+	offsetof(PyTypeObject, tp_dict),					/* tp_dictoffset */
+	0,					/* tp_init */
+	0,					/* tp_alloc */
+	0,					/* tp_new */
+	0,		        		/* tp_free */
+	0,					/* tp_is_gc */
+	0,					/* tp_bases */
+	0,                                      /* tp_mro */
+	0,                                      /* tp_cache */
+	0,                                      /* tp_subclasses */
+	0,                                      /* tp_weaklist */
+	0                                       /* tp_del */
+#if PY_VERSION_HEX >= 0x02060000
+	, 0                                     /* tp_version_tag */
+#endif
+
+};
+
+
 PyTypeObject PyObjCClass_Type = {
+#if 1
+	/*PyVarObject_HEAD_INIT(&PyObjCMetaClass_Type, 0)*/
+	PyVarObject_HEAD_INIT(NULL, 0)
+#else
 	PyVarObject_HEAD_INIT(&PyType_Type, 0)
+#endif
 	"objc_class",				/* tp_name */
 	sizeof (PyObjCClassObject),		/* tp_basicsize */
 	0,					/* tp_itemsize */
 	0,					/* tp_weaklistoffset */
 	0,					/* tp_iter */
 	0,					/* tp_iternext */
-	0,					/* tp_methods */
-	class_members,					/* tp_members */
+	class_methods,				/* tp_methods */
+	class_members,				/* tp_members */
 	class_getset,				/* tp_getset */
-	&PyType_Type,				/* tp_base */
+	&PyObjCMetaClass_Type,				/* tp_base */
 	0,					/* tp_dict */
 	0,					/* tp_descr_get */
 	0,					/* tp_descr_set */
 static int
 add_class_fields(Class objc_class, PyObject* py_class, PyObject* dict, PyObject* classDict)
 {
+#if 0
 	Class     cls;
 	Method*   methods;
 	unsigned int method_count, i;
 	PyObject* descr;
 	char      selbuf[1024];
+#endif
 
 	if (objc_class == NULL) return 0;
 
 #endif
 
 
-
+#if 0 
 	/* 
 	 * Then add class methods
 	 */
 		Py_DECREF(descr);
 	}
 	free(methods);
+#endif
 
 	return  0;
 }
 		return result;
 	}
 
-
 	if (class_isMetaClass(objc_class)) {
 		result =  (PyObject*)PyObjCClass_NewMetaClass(objc_class);
 		Py_DECREF(result);
 	PyObject* args;
 
 	if (class_isMetaClass(cls)) {
+		/* XXX: is this needed after all? */
 		return 0;
 	}
 

File pyobjc-core/Modules/objc/objc-object.h

 
 PyObject* PyObjCObject_GetAttr(PyObject* object, PyObject* key);
 PyObject* PyObjCObject_GetAttrString(PyObject* object, char* key);
-
-
 PyObject* PyObjCObject_NewTransient(id objc_object, int* cookie);
 void PyObjCObject_ReleaseTransient(PyObject* proxy, int cookie);
 

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

 	PyObject* res;
 	SEL	  sel = PyObjCSelector_DefaultSelector(PyBytes_AsString(name_bytes));
 
-	/* FIXME: Support for method name cache */
-
 	/* Look in tp_dict of types in MRO */
 	mro = tp->tp_mro;
 	if (mro == NULL) {
 			 *
 			 * XXX: Once this works try to avoid calling class_getInstanceMethod too often
 			 */
-			Class cls = PyObjCClass_GetClass(base);
-			Method m = class_getInstanceMethod(cls, sel);
-			if (m) {
-				int use = 1;
-				Class sup = class_getSuperclass(cls);
-				if (sup) {
-					Method m_sup = class_getInstanceMethod(sup, sel);
-					if (m_sup == m) {
-						use = 0;
-					}
-				}
-				if (!use) continue;
-
-				/* Create (unbound) selector */
-				PyObject* result = PyObjCSelector_NewNative(
-						cls, sel, method_getTypeEncoding(m), 0);
-				if (result == NULL) {
-					return NULL;
-				}
-
-
-				/* add to __dict__ 'cache' */
-				if (PyDict_SetItem(dict, name, result) == -1) {
-					Py_DECREF(result);
-					return NULL;
-				}
-				
-				/* and return */
-				return result;
+			descr = PyObjCClass_TryResolveSelector(base, name, sel);
+			if (descr) {
+				return descr;
+			} else if (PyErr_Occurred()) {
+				return NULL;
 			}
 		}
 	}
 	return descr;
 }
 
+PyObject*
+PyObjCClass_TryResolveSelector(PyObject* base, PyObject* name, SEL sel)
+{
+	Class cls = PyObjCClass_GetClass(base);
+	PyObject* dict = ((PyTypeObject *)base)->tp_dict;
+	Method m = class_getInstanceMethod(cls, sel);
+	if (m) {
+		int use = 1;
+		Class sup = class_getSuperclass(cls);
+		if (sup) {
+			Method m_sup = class_getInstanceMethod(sup, sel);
+			if (m_sup == m) {
+				use = 0;
+			}
+		}
+		if (!use) return NULL;
+
+		/* Create (unbound) selector */
+		PyObject* result = PyObjCSelector_NewNative(
+				cls, sel, method_getTypeEncoding(m), 0);
+		if (result == NULL) {
+			return NULL;
+		}
+
+
+		/* add to __dict__ 'cache' */
+		if (PyDict_SetItem(dict, name, result) == -1) {
+			Py_DECREF(result);
+			return NULL;
+		}
+		
+		/* and return as a borrowed reference */
+		Py_DECREF(result);
+		return result;
+	}
+	return NULL;
+}
+
 static PyObject** _get_dictptr(PyObject* obj)
 {
 	Py_ssize_t dictoffset;

File pyobjc-core/Modules/objc/objc_super.m

 {
 	superobject *su = (superobject *)self;
 	int skip = su->obj_type == NULL;
+	SEL sel = PyObjCSelector_DefaultSelector(PyBytes_AsString(name)); /* XXX: needs to be changed for py3k */
 
 
 
 				}
 				return res;
 			}
+
+			if (PyObjCClass_Check(tmp)) {
+				res = PyObjCClass_TryResolveSelector(tmp, name, sel);
+				if (res) {
+					Py_INCREF(res);
+					f = Py_TYPE(res)->tp_descr_get;
+					if (f != NULL) {
+						tmp = f(res,
+							/* Only pass 'obj' param if
+							   this is instance-mode super 
+							   (See SF ID #743627)
+							*/
+							(su->obj == (PyObject *)
+								    su->obj_type 
+								? (PyObject *)NULL 
+								: su->obj),
+							(PyObject *)starttype);
+						Py_DECREF(res);
+						res = tmp;
+					}
+					return res;
+				} else if (PyErr_Occurred()) {
+					return NULL;
+				}
+			} /* TODO: same trick for class methods */
 		}
 	}
 	return PyObject_GenericGetAttr(self, name);

File pyobjc-core/Modules/objc/selector.m

 	/* Bind 'self' */
 	if (meth->sel_flags & PyObjCSelector_kCLASS_METHOD) {
 		obj = class;
+	} else {
+		if (obj && PyObjCClass_Check(obj)) {
+			obj = NULL;
+		}
 	}
 	result = PyObject_New(PyObjCNativeSelector, &PyObjCNativeSelector_Type);
 	result->sel_selector   = meth->sel_selector;
 
 
 		NS_DURING
-			if ([cls instancesRespondToSelector:sel]) {
-				methsig = [cls instanceMethodSignatureForSelector:sel];
+			if ([cls respondsToSelector:sel]) {
+				methsig = [cls methodSignatureForSelector:sel];
 				retval = PyObjCSelector_NewNative(cls, sel, 
-					PyObjC_NSMethodSignatureToTypeString(methsig, buf, sizeof(buf)), 0);
+					PyObjC_NSMethodSignatureToTypeString(methsig, buf, sizeof(buf)), 1);
 			} else if ((Object_class != nil) && (cls != Object_class) && nil != (methsig = [(NSObject*)cls methodSignatureForSelector:sel])) {
 				retval = PyObjCSelector_NewNative(cls, sel, 
 					PyObjC_NSMethodSignatureToTypeString(
 				retval = NULL;
 			}
 		NS_HANDLER
+			PyObjCErr_FromObjC(localException);
+			PyErr_Print();
 			PyErr_Format(PyExc_AttributeError,
 				"No attribute %s", name);
 			retval = NULL;
 	if (signature == NULL) {
 		PyErr_Format(PyExc_RuntimeError, 
 			"PyObjCSelector_NewNative: nil signature for %s", sel_getName(selector));
-		printf("** PyObjCSelector_NewNative: nil signature for %s\n", sel_getName(selector));
 		return NULL;
 	}
 

File pyobjc-core/PyObjCTest/dejagnu.py

 
 def testSuiteForDirectory(dirname):
     tests = []
-    return unittest.TestSuite(tests) # XXX
     for fn in os.listdir(dirname):
         if not fn.endswith('.c') and not fn.endswith('.m'): continue
         tst = DgTestCase(os.path.join(dirname, fn))

File pyobjc-core/PyObjCTest/test_bridgesupport.py

         for item in self.iter_framework_dir('/System/Library/Frameworks'):
             yield item
 
-    def no_test_system_bridgesupport(self): # XXX
+    def test_system_bridgesupport(self): # XXX
         with filterWarnings("ignore", RuntimeWarning):
             # Check that all system bridgesupport files can be processed correctly
             for fn in self.iter_system_bridgesupport_files():

File pyobjc-core/PyObjCTest/test_convenience.py

 import objc._convenience as convenience
 
 class TestConvenienceHelpers (TestCase):
-    def test_add_for_selector(self):
-        methods = [
-            ('add', lambda self, x: self.testMethod_(x))
-        ]
-
-        with filterWarnings("error", DeprecationWarning):
-            self.assertRaises(DeprecationWarning, objc.addConvenienceForSelector, b'testMethod:', methods)
-            if b'testMethod' in convenience._CONVENIENCE_METHODS:
-                del convenience._CONVENIENCE_METHODS[b'testMethods:']
-
-        with filterWarnings("ignore", DeprecationWarning):
-            self.assertNotIn(b'testMethod:', convenience._CONVENIENCE_METHODS)
-            try:
-                objc.addConvenienceForSelector(b'testMethod:', methods)
-
-                self.assertEqual(convenience._CONVENIENCE_METHODS[b'testMethod:'], methods)
-
-            finally:
-                if b'testMethod' in convenience._CONVENIENCE_METHODS:
-                    del convenience._CONVENIENCE_METHODS[b'testMethods:']
-
-
     def test_add_for_class(self):
         self.assertNotIn("MyObject", convenience.CLASS_METHODS)
 

File pyobjc-core/PyObjCTest/test_locking.py

 
 class TestLockingBasic (TestCase):
 
-    # XXX: test disabled for now due to speed
-    def no_testBasicLocking(self):
+    def testBasicLocking(self):
         lst = []
 
         obj = BaseClass.alloc().initWithList_(lst)
             if lst[idx].endswith(' a'):
                 self.assertTrue(lst[idx+1].endswith(' b'))
 
-    # XXX: test disabled for now due to speed
-    def no_testObjectiveCLocking(self):
+    def testObjectiveCLocking(self):
         lst = []
         lst = []
 
 
 class TestLockingWithStatement (TestCase):
 
-    # XXX: test disabled for now due to speed
-    def no_testBasicLocking(self):
+    def testBasicLocking(self):
         lst = []
         lst = []
 

File pyobjc-core/PyObjCTest/test_set_interface.py

 
 This is a port of the set tests from the Python stdlib for 3.2
 """
-raise ImportError
+raise ImportError("XXX: disable set API tests")
 from PyObjCTools.TestSupport import *
 
 import objc

File pyobjc-core/setup.py

         if isinstance(vars[k], str) and '-O0' in vars[k]:
             vars[k] = vars[k].replace('-O0', '-O1')
 
+#vars = get_config_vars()
+#for k in vars: # XXX
+#    if isinstance(vars[k], str) and '-O2' in vars[k]:
+#        vars[k] = vars[k].replace('-O2', '-O1')
+
 OBJC_LDFLAGS = frameworks('CoreFoundation', 'Foundation', 'Carbon')
 
 if not os.path.exists('/usr/include/objc/runtime.h'):