[PyObjC-svn] r2415 - in trunk/pyobjc/pyobjc-core: . Modules/objc PyObjCTest

[email protected] Tue, 23 Mar 2010 16:08:38 -0500
Newsgroups gmane.comp.python.pyobjc.cvs
Message-ID <[email protected]>
Author: ronaldoussoren
Date: Tue Mar 23 16:08:37 2010
New Revision: 2415

Log:
Improve test coverage for hidden selectors, and
fix most issues uncovered by them.


Modified:
   trunk/pyobjc/pyobjc-core/Modules/objc/class-builder.h
   trunk/pyobjc/pyobjc-core/Modules/objc/class-builder.m
   trunk/pyobjc/pyobjc-core/Modules/objc/module.m
   trunk/pyobjc/pyobjc-core/Modules/objc/objc-class.h
   trunk/pyobjc/pyobjc-core/Modules/objc/objc-class.m
   trunk/pyobjc/pyobjc-core/Modules/objc/selector.h
   trunk/pyobjc/pyobjc-core/Modules/objc/selector.m
   trunk/pyobjc/pyobjc-core/NEWS.txt
   trunk/pyobjc/pyobjc-core/PyObjCTest/test_hidden_selector.py
   trunk/pyobjc/pyobjc-core/PyObjCTest/test_methodedits.py
   trunk/pyobjc/pyobjc-core/setup.py

Modified: trunk/pyobjc/pyobjc-core/Modules/objc/class-builder.h
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/class-builder.h	(original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/class-builder.h	Tue Mar 23 16:08:37 2010
@@ -9,7 +9,8 @@
 		char* name, 
 		PyObject* class_dict,
 		PyObject* meta_dict,
-		PyObject* hiddenSelectors);
+		PyObject* hiddenSelectors,
+		PyObject* hiddenClassSelectors);
 
 int PyObjCClass_UnbuildClass(Class new_class);
 int PyObjCClass_FinishClass(Class objc_class);

Modified: trunk/pyobjc/pyobjc-core/Modules/objc/class-builder.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/class-builder.m	(original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/class-builder.m	Tue Mar 23 16:08:37 2010
@@ -168,7 +168,7 @@
  * is already registered with the Objective-C runtime.
  */
 int 
-PyObjCClass_UnbuildClass(Class objc_class)
+PyObjCClass_UnbuildClass(Class objc_class __attribute__((__unused__)))
 {
 	PyObjC_Assert(objc_class != nil, -1);
 	PyObjC_Assert(objc_lookUpClass(class_getName(objc_class)) == nil, -1);
@@ -611,7 +611,7 @@
 Class 
 PyObjCClass_BuildClass(Class super_class,  PyObject* protocols,
 		char* name, PyObject* class_dict, PyObject* meta_dict,
-		PyObject* hiddenSelectors)
+		PyObject* hiddenSelectors, PyObject* hiddenClassSelectors)
 {
 	PyObject* seq;
 	PyObject*                key_list = NULL;
@@ -1005,6 +1005,15 @@
 					goto error_cleanup;
 				}
 
+
+				if (!PyObjCSelector_IsHidden(value)) {
+					if (PyDict_SetItem(meta_dict, key, value) == -1) {
+						goto error_cleanup;
+					}
+				} else {
+					shouldCopy = NO;
+				}
+
 				if (shouldCopy) {
 					r = PyDict_SetItem(meta_dict, pyname, value);
 					Py_DECREF(pyname);
@@ -1012,14 +1021,21 @@
 						goto error_cleanup;
 					}
 				}
-				if (PyDict_SetItem(meta_dict, key, value) == -1) {
-					goto error_cleanup;
-				}
 				if (PyDict_DelItem(class_dict, key) == -1) {
 					goto error_cleanup;
 				}
 			} else {
 				r = PySet_Add(instance_methods, value);
+				if (r == -1) {
+					goto error_cleanup;
+				}
+				if (PyObjCSelector_IsHidden(value)) {
+					r = PyDict_DelItem(class_dict, key);
+					if (r == -1) {
+						goto error_cleanup;
+					}
+					shouldCopy = NO;
+				}
 				if (shouldCopy) {
 					r = PyDict_SetItem(class_dict, pyname, value);
 					Py_DECREF(pyname);
@@ -1087,8 +1103,10 @@
 
 
 					if (PyObjCSelector_IsClassMethod(value)) {
-						if (PyDict_SetItem(meta_dict, key, value) == -1) {
-							goto error_cleanup;
+						if (!PyObjCSelector_IsHidden(value)) {
+							if (PyDict_SetItem(meta_dict, key, value) == -1) {
+								goto error_cleanup;
+							}
 						}
 						if (PyDict_DelItem(class_dict, key) == -1) {
 							goto error_cleanup;
@@ -1097,9 +1115,16 @@
 						r = PySet_Add(class_methods, value);
 
 					} else {
-						if (PyDict_SetItem(class_dict, key, value) < 0) {
-							Py_CLEAR(value);
-							goto error_cleanup;
+						if (PyObjCSelector_IsHidden(value)) {
+							if (PyDict_DelItem(class_dict, key) == -1) {
+								goto error_cleanup;
+							}
+						} else {
+
+							if (PyDict_SetItem(class_dict, key, value) < 0) {
+								Py_CLEAR(value);
+								goto error_cleanup;
+							}
 						}
 
 						r = PySet_Add(instance_methods, value);
@@ -1210,6 +1235,13 @@
 	for (i = 0; i < PySequence_Fast_GET_SIZE(class_methods); i++) {
 		value = PySequence_Fast_GET_ITEM(class_methods, i);
 
+		if (PyBytes_Check(value)) {
+			int r = PySet_Add(hiddenClassSelectors, value);
+			if (r == -1) {
+				goto error_cleanup;
+			}
+		}
+
 		if (!PyObjCSelector_Check(value)) {
 			continue;
 		}
@@ -1233,6 +1265,19 @@
 
 			/* Set sel_class */
 			sel->sel_class = new_class;
+
+			if (sel->sel_flags & PyObjCSelector_kHIDDEN) {
+				PyObject* v = PyBytes_InternFromString(
+					sel_getName(PyObjCSelector_GetSelector(value)));
+				if (v == NULL) {
+					goto error_cleanup;
+				}
+				int r = PySet_Add(hiddenClassSelectors, v);
+				Py_DECREF(v);
+				if (r == -1) {
+					goto error_cleanup;
+				}
+			}
 		}
 	}
 

Modified: trunk/pyobjc/pyobjc-core/Modules/objc/module.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/module.m	(original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/module.m	Tue Mar 23 16:08:37 2010
@@ -220,16 +220,6 @@
 	static 	char* kwlist[] = { "targetClass", "methodsArray", NULL };
 	PyObject* classObject = NULL;
 	PyObject* methodsArray = NULL;
-	Class targetClass;
-	Py_ssize_t methodCount;
-	Py_ssize_t methodIndex;
-	int r;
-	struct PyObjC_method *methodsToAdd;
-	size_t curMethodIndex;
-	struct PyObjC_method *classMethodsToAdd;
-	size_t curClassMethodIndex;
-	PyObject* extraDict = NULL;
-	PyObject* metaDict = NULL;
 
 	if (!PyArg_ParseTupleAndKeywords(args, keywds, 
 			"OO:classAddMethods", kwlist,
@@ -246,156 +236,21 @@
 			methodsArray, "methodsArray must be a sequence");
 	if (methodsArray == NULL) return NULL;
 	
-	targetClass  = PyObjCClass_GetClass(classObject);
-	methodCount  = PySequence_Fast_GET_SIZE(methodsArray);
+	int r = PyObjCClass_AddMethods(classObject, 
+			PySequence_Fast_ITEMS(methodsArray),
+			PySequence_Fast_GET_SIZE(methodsArray));
+	Py_DECREF(methodsArray);
 
-	if (methodCount == 0) {
-		Py_INCREF(Py_None);
-		return Py_None;
-	}
-	
-	extraDict = PyDict_New();
-	if (extraDict == NULL) {
-		return NULL;
-	}
-
-	metaDict = PyDict_New();
-	if (metaDict == NULL) {
-		Py_DECREF(extraDict);
-		return NULL;
-	}
-
-	methodsToAdd = PyMem_Malloc(sizeof(*methodsToAdd) * methodCount);
-	if (methodsToAdd == NULL) {
-		Py_DECREF(extraDict);
-		Py_DECREF(metaDict);
-		PyErr_NoMemory();
-		return NULL;
-	}
-
-	classMethodsToAdd = PyMem_Malloc(sizeof(*methodsToAdd) * methodCount);
-	if (classMethodsToAdd == NULL) {
-		Py_DECREF(extraDict);
-		Py_DECREF(metaDict);
-		PyMem_Free(methodsToAdd);
-		PyErr_NoMemory();
+	if (r == -1) {
 		return NULL;
 	}
-		
-	curMethodIndex = 0;
-	curClassMethodIndex = 0;
-
-	for (methodIndex = 0; methodIndex < methodCount; methodIndex++) {
-		PyObject* aMethod = PySequence_Fast_GET_ITEM(
-				methodsArray, methodIndex);
-		PyObject* name;
-		struct PyObjC_method *objcMethod;
-
-		if (PyObjCNativeSelector_Check(aMethod)) {
-			PyErr_Format(PyExc_TypeError,
-				"Cannot add a native selector to other "
-				"classes");
-			goto cleanup_and_return_error;
-		}
-
-		aMethod = PyObjCSelector_FromFunction(
-			NULL,
-			aMethod,
-			classObject,
-			NULL);
-		if (aMethod == NULL) {
-			PyErr_Format(PyExc_TypeError ,
-			      "All objects in methodArray must be of "
-			      "type <objc.selector>, <function>, "
-			      " <method> or <classmethod>");
-			goto cleanup_and_return_error;
-		}
-
-		/* install in methods to add */
-		if (PyObjCSelector_IsClassMethod(aMethod)) {
-			objcMethod = classMethodsToAdd + curClassMethodIndex++;
-		} else {
-			objcMethod = methodsToAdd + curMethodIndex++;
-		}
-		
-		objcMethod->name = PyObjCSelector_GetSelector(aMethod);
-		objcMethod->type = strdup(
-				PyObjCSelector_Signature(aMethod));
-
-		PyObjC_RemoveInternalTypeCodes((char*)(objcMethod->type));
-		if (objcMethod->type == NULL) {
-			goto cleanup_and_return_error;
-		}
-		objcMethod->imp = PyObjCFFI_MakeIMPForPyObjCSelector(
-			(PyObjCSelector*)aMethod);
-		
-		name = PyObject_GetAttrString(aMethod, "__name__");
-
-#if PY_MAJOR_VERSION == 3
-		if (PyBytes_Check(name)) {
-			PyObject* t = PyUnicode_Decode(
-					PyBytes_AsString(name),
-					PyBytes_Size(name),
-					NULL, NULL);
-			if (t == NULL) {
-				Py_DECREF(name); name = NULL;
-				Py_DECREF(aMethod); aMethod = NULL;
-				goto cleanup_and_return_error;
-			}
-			Py_DECREF(name);
-			name = t;
-		}
-#endif
-
-		if (!PyObjCClass_HiddenSelector(classObject, objcMethod->name)) {
-			if (PyObjCSelector_IsClassMethod(aMethod)) {
-				r = PyDict_SetItem(metaDict, name, aMethod);
-			} else {
-				r = PyDict_SetItem(extraDict, name, aMethod);
-			}
-			Py_DECREF(name); name = NULL;
-			Py_DECREF(aMethod); aMethod = NULL;
-			if (r == -1) {
-				goto cleanup_and_return_error;
-			}
-		} else {
-			Py_DECREF(name); name = NULL;
-			Py_DECREF(aMethod); aMethod = NULL;
-		}
-	}
-
-	/* add the methods */
-	if (curMethodIndex != 0) {
-		class_addMethodList(targetClass, methodsToAdd, curMethodIndex);
-	}
-	PyMem_Free(methodsToAdd);
-	if (curClassMethodIndex != 0) {
-		class_addMethodList(object_getClass(targetClass),
-				classMethodsToAdd, curClassMethodIndex);
-	}
-	PyMem_Free(classMethodsToAdd);
-
-	r = PyDict_Merge(((PyTypeObject*)classObject)->tp_dict, extraDict, 1);
-	if (r == -1) goto cleanup_and_return_error;
-
-	r = PyDict_Merge(Py_TYPE(classObject)->tp_dict, metaDict, 1);
-	if (r == -1) goto cleanup_and_return_error;
-
-	Py_DECREF(extraDict); extraDict = NULL;
-	Py_DECREF(metaDict); metaDict = NULL;
 
 	Py_INCREF(Py_None);
 	return Py_None;
-
-cleanup_and_return_error:
-	Py_XDECREF(metaDict);
-	Py_XDECREF(extraDict);
-	if (methodsToAdd) PyMem_Free(methodsToAdd);
-	if (classMethodsToAdd) PyMem_Free(classMethodsToAdd);
-	return NULL;
 }
 
 
+
 PyDoc_STRVAR(remove_autorelease_pool_doc,
   "removeAutoreleasePool()\n"
   "\n"
@@ -1648,6 +1503,139 @@
 	return curval;
 }
 
+/* 
+ * Helper function for decoding XML metadata:
+ *
+ * This fixes an issue with metadata files: metadata files use
+ * _C_BOOL to represent type 'BOOL', but that the string should
+ * be used to represent 'bool' which has a different size on
+ * PPC. Therefore swap usage of _C_BOOL and _C_NSBOOL in data
+ * from metadata files.
+ */
+static void typecode2typecode(char* buf)
+{
+	/* Skip pointer declarations and anotations */
+	for (;;) {
+		switch(*buf) {
+		case _C_PTR:
+		case _C_IN:
+		case _C_OUT:
+		case _C_INOUT:
+		case _C_ONEWAY:
+		case _C_CONST:
+			buf++;
+			break;
+		default:
+		      goto exit;
+		}
+	}
+exit:
+
+	switch (*buf) {
+	case _C_BOOL:
+		*buf = _C_NSBOOL;
+		break;
+	case _C_NSBOOL:
+		*buf = _C_BOOL;
+		break;
+        case _C_STRUCT_B:
+		while (buf && *buf != _C_STRUCT_E && *buf && *buf++ != '=') {
+		}
+		while (buf && *buf && *buf != _C_STRUCT_E) {
+			if (*buf == '"') {
+				/* embedded field name */
+				buf = strchr(buf+1, '"');
+				if (buf == NULL) {
+					return;
+				}
+				buf++;
+			}
+			typecode2typecode(buf);
+			buf = (char*)PyObjCRT_SkipTypeSpec(buf);
+		}
+		break;
+	
+	case _C_UNION_B:
+		while (buf && *buf != _C_UNION_E && *buf && *buf++ != '=') {
+		}
+		while (buf && *buf && *buf != _C_UNION_E) {
+			if (*buf == '"') {
+				/* embedded field name */
+				buf = strchr(buf+1, '"');
+				if (buf == NULL) {
+					return;
+				}
+				buf++;
+			}
+			typecode2typecode(buf);
+			buf = (char*)PyObjCRT_SkipTypeSpec(buf);
+		}
+		break;
+
+
+	case _C_ARY_B:
+		while (isdigit(*++buf));
+		typecode2typecode(buf);
+		break;
+	}
+}
+
+
+
+static PyObject*
+typestr2typestr(PyObject* args)
+{
+	char* s;
+	char* buf;
+
+	if (PyUnicode_Check(args)) {
+		PyObject* bytes = PyUnicode_AsEncodedString(args, NULL, NULL);
+		if (bytes == NULL) {
+			return NULL;
+		}
+		buf = PyObjCUtil_Strdup(PyBytes_AsString(args));
+		Py_DECREF(bytes);
+
+	} else if (PyBytes_Check(args)) {
+		buf = PyObjCUtil_Strdup(PyBytes_AsString(args));
+	} else {
+		PyErr_SetString(PyExc_TypeError, "expecing string");
+		return NULL;
+	}
+
+	
+	if (buf == NULL) {
+		PyErr_NoMemory();
+		return NULL;
+	}
+
+	s = buf;
+	while (s && *s) {
+		typecode2typecode(s);
+		if (s && *s == '\"') {
+			PyErr_Format(PyObjCExc_InternalError,
+				"typecode2typecode: invalid typecode '%c' "
+				"at \"%s\"", *s, s);
+			*s = '\0';
+			PyMem_Free(buf);
+			return NULL;
+
+		} else {
+			s = (char*)PyObjCRT_SkipTypeSpec(s);
+		}
+	}
+
+	PyObject* result = PyString_FromString(buf);
+	PyMem_Free(buf);
+
+	return result;
+}
+
+
+
+
+
+
 
 static PyMethodDef mod_methods[] = {
 	{
@@ -1757,6 +1745,9 @@
 		METH_VARARGS,
 		"_block_call(block, signature, args, kwds) -> retval" },
 
+	{ "_typestr2typestr", (PyCFunction)typestr2typestr, 
+		METH_O, "private function" },
+
 
 	{ 0, 0, 0, 0 } /* sentinel */
 };

Modified: trunk/pyobjc/pyobjc-core/Modules/objc/objc-class.h
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/objc-class.h	(original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/objc-class.h	Tue Mar 23 16:08:37 2010
@@ -95,6 +95,7 @@
 	int useKVO;
 	PyObject* protectedMethods;
 	PyObject* hiddenSelectors;
+	PyObject* hiddenClassSelectors;
 	struct _PyObjCClassObject* meta_class; /* To be dropped */
 } PyObjCClassObject;
 
@@ -110,7 +111,9 @@
 void PyObjCClass_SetDelMethod(PyObject* cls, PyObject* newval);
 int  PyObjCClass_HasPythonImplementation(PyObject* cls);
 PyObject* PyObjCClass_ClassForMetaClass(PyObject* meta);
-BOOL PyObjCClass_HiddenSelector(PyObject* tp, SEL sel);
+BOOL PyObjCClass_HiddenSelector(PyObject* tp, SEL sel, BOOL classMethod);
+int PyObjCClass_SetHidden(PyObject* tp, SEL sel, BOOL classMethod);
+int PyObjCClass_AddMethods(PyObject* cls, PyObject** methods, Py_ssize_t count);
 
 PyObject* PyObjCClass_ListProperties(PyObject* cls);
 

Modified: trunk/pyobjc/pyobjc-core/Modules/objc/objc-class.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/objc-class.m	(original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/objc-class.m	Tue Mar 23 16:08:37 2010
@@ -7,8 +7,36 @@
 
 #include <stddef.h>
 
+int PyObjCClass_SetHidden(PyObject* tp, SEL sel, BOOL classMethod)
+{
+	PyObject* hidden;
+	if (classMethod) {
+		hidden = ((PyObjCClassObject*)tp)->hiddenClassSelectors;
+		if (hidden == NULL) {
+			hidden = PySet_New(NULL);
+			if (hidden == NULL) {
+				return -1;
+			}
+			((PyObjCClassObject*)tp)->hiddenClassSelectors = hidden;
+		}
+	} else {
+		hidden = ((PyObjCClassObject*)tp)->hiddenSelectors;
+		if (hidden == NULL) {
+			hidden = PySet_New(NULL);
+			if (hidden == NULL) {
+				return -1;
+			}
+			((PyObjCClassObject*)tp)->hiddenSelectors = hidden;
+		}
+	}
+	PyObject* v = PyBytes_InternFromString(sel_getName(sel));
+	int r = PySet_Add(hidden, v);
+	Py_DECREF(v);
+	return r;
+}
+
 
-BOOL PyObjCClass_HiddenSelector(PyObject* tp, SEL sel)
+BOOL PyObjCClass_HiddenSelector(PyObject* tp, SEL sel, BOOL classMethod)
 {
 	PyObject* mro = ((PyTypeObject*)tp)->tp_mro;
 	int i, n;
@@ -21,7 +49,12 @@
 	for (i = 0; i < n; i++) {
 		PyObject* base = PyTuple_GET_ITEM(mro, i);
 		if (PyObjCClass_Check(base)) {
-			PyObject* hidden = ((PyObjCClassObject*)base)->hiddenSelectors;
+			PyObject* hidden;
+			if (classMethod) {
+				hidden = ((PyObjCClassObject*)base)->hiddenClassSelectors;
+			} else {
+				hidden = ((PyObjCClassObject*)base)->hiddenSelectors;
+			}
 			if (hidden != NULL) {
 				PyObject* v = PyBytes_InternFromString(sel_getName(sel));
 				if (v == NULL) {
@@ -109,7 +142,7 @@
 	nsdata_getsegcount,
 	NULL
 #if PY_VERSION_HEX >= 0x02060000
-	, NULL                                     
+	, nsdata_getbuffer
 	, NULL                                     
 #endif
 
@@ -127,7 +160,7 @@
 	nsdata_getsegcount,
 	NULL
 #if PY_VERSION_HEX >= 0x02060000
-	, NULL                                     
+	, nsmutabledata_getbuffer
 	, NULL                                     
 #endif
 
@@ -378,6 +411,7 @@
 	Ivar var;
 	PyObject* protectedMethods = NULL;
 	PyObject* hiddenSelectors = NULL;
+	PyObject* hiddenClassSelectors = NULL;
 	BOOL      isCFProxyClass = NO;
 
 	if (!PyArg_ParseTupleAndKeywords(args, kwds, "sOO:__new__",
@@ -432,6 +466,13 @@
 		return NULL;
 	}
 
+	hiddenClassSelectors = PySet_New(NULL);
+	if (hiddenClassSelectors == NULL) {
+		Py_DECREF(protectedMethods);
+		Py_DECREF(hiddenSelectors);
+		return NULL;
+	}
+
 
 	/*
 	 * __pyobjc_protocols__ contains the list of protocols supported
@@ -445,6 +486,7 @@
 		if (protocols == NULL) {
 			Py_DECREF(protectedMethods);
 			Py_DECREF(hiddenSelectors);
+			Py_DECREF(hiddenClassSelectors);
 			return NULL;
 		}
 	} else {
@@ -456,6 +498,7 @@
 		if (seq == NULL) {
 			Py_DECREF(protectedMethods);
 			Py_DECREF(hiddenSelectors);
+			Py_DECREF(hiddenClassSelectors);
 			Py_DECREF(protocols);
 			return NULL;
 		}
@@ -466,6 +509,7 @@
 		if (protocols == NULL) {
 			Py_DECREF(protectedMethods);
 			Py_DECREF(hiddenSelectors);
+			Py_DECREF(hiddenClassSelectors);
 			return NULL;
 		}
 		for (i = 0; i < protocols_len; i++) {
@@ -481,12 +525,14 @@
 		Py_DECREF(protocols);
 		Py_DECREF(protectedMethods);
 		Py_DECREF(hiddenSelectors);
+		Py_DECREF(hiddenClassSelectors);
 		return NULL;
 	}
 	PyList_Append(real_bases, py_super_class);
 	if (PyErr_Occurred()) {
 		Py_DECREF(protectedMethods);
 		Py_DECREF(hiddenSelectors);
+		Py_DECREF(hiddenClassSelectors);
 		Py_DECREF(protocols);
 		Py_DECREF(real_bases);
 		return NULL;
@@ -499,6 +545,7 @@
 			Py_DECREF(real_bases);
 			Py_DECREF(protectedMethods);
 			Py_DECREF(hiddenSelectors);
+			Py_DECREF(hiddenClassSelectors);
 			return NULL;
 		}
 		if (PyObjCClass_Check(v)) {
@@ -506,6 +553,7 @@
 			Py_DECREF(real_bases);
 			Py_DECREF(protectedMethods);
 			Py_DECREF(hiddenSelectors);
+			Py_DECREF(hiddenClassSelectors);
 			PyErr_SetString(PyExc_TypeError, 
 					"multiple objective-C bases");
 			return NULL;
@@ -524,6 +572,7 @@
 		Py_DECREF(real_bases);
 		Py_DECREF(protectedMethods);
 		Py_DECREF(hiddenSelectors);
+		Py_DECREF(hiddenClassSelectors);
 		return NULL;
 	}
 
@@ -534,13 +583,14 @@
 		/* First generate the objective-C class. This may change the
 		 * class dict.
 		 */
-		objc_class = PyObjCClass_BuildClass(super_class, protocols, name, dict, metadict, hiddenSelectors);
+		objc_class = PyObjCClass_BuildClass(super_class, protocols, name, dict, metadict, hiddenSelectors, hiddenClassSelectors);
 		if (objc_class == NULL) {
 			Py_DECREF(protocols);
 			Py_DECREF(metadict);
 			Py_DECREF(real_bases);
 			Py_DECREF(protectedMethods);
 			Py_DECREF(hiddenSelectors);
+			Py_DECREF(hiddenClassSelectors);
 			return NULL;
 		}
 
@@ -554,6 +604,7 @@
 			Py_DECREF(metadict);
 			Py_DECREF(protectedMethods);
 			Py_DECREF(hiddenSelectors);
+			Py_DECREF(hiddenClassSelectors);
 			return NULL;
 		} else {
 			PyObjCClass_CheckMethodList(py_super_class, 1);
@@ -573,6 +624,7 @@
 		Py_DECREF(real_bases);
 		Py_DECREF(protectedMethods);
 		Py_DECREF(hiddenSelectors);
+		Py_DECREF(hiddenClassSelectors);
 		return NULL;
 	}
 	Py_DECREF(real_bases);
@@ -598,6 +650,7 @@
 				Py_DECREF(metadict);
 				Py_DECREF(protectedMethods);
 				Py_DECREF(hiddenSelectors);
+				Py_DECREF(hiddenClassSelectors);
 				(void)PyObjCClass_UnbuildClass(objc_class);
 				return NULL;
 			}
@@ -609,6 +662,7 @@
 				Py_DECREF(metadict);
 				Py_DECREF(protectedMethods);
 				Py_DECREF(hiddenSelectors);
+				Py_DECREF(hiddenClassSelectors);
 				(void)PyObjCClass_UnbuildClass(objc_class);
 				return NULL;
 			}
@@ -625,6 +679,7 @@
 		Py_DECREF(metadict);
 		Py_DECREF(protectedMethods);
 		Py_DECREF(hiddenSelectors);
+		Py_DECREF(hiddenClassSelectors);
 		(void)PyObjCClass_UnbuildClass(objc_class);
 		return NULL;
 	}
@@ -653,6 +708,7 @@
 			Py_DECREF(metadict);
 			Py_DECREF(protectedMethods);
 			Py_DECREF(hiddenSelectors);
+			Py_DECREF(hiddenClassSelectors);
 			return NULL;
 		} else {
 			if (PyDict_DelItemString(dict, "__del__") < 0) {
@@ -664,6 +720,7 @@
 				Py_DECREF(metadict);
 				Py_DECREF(protectedMethods);
 				Py_DECREF(hiddenSelectors);
+				Py_DECREF(hiddenClassSelectors);
 				return NULL;
 			}
 		}
@@ -683,6 +740,7 @@
 		Py_DECREF(metadict);
 		Py_DECREF(protectedMethods);
 		Py_DECREF(hiddenSelectors);
+		Py_DECREF(hiddenClassSelectors);
 		return NULL;
 	}
 		
@@ -695,6 +753,7 @@
 			Py_DECREF(metadict);
 			Py_DECREF(protectedMethods);
 			Py_DECREF(hiddenSelectors);
+			Py_DECREF(hiddenClassSelectors);
 			return NULL;
 		}
 	}
@@ -711,6 +770,7 @@
 			Py_DECREF(metadict);
 			Py_DECREF(protectedMethods);
 			Py_DECREF(hiddenSelectors);
+			Py_DECREF(hiddenClassSelectors);
 			return NULL;
 		}
 		if (PyDict_Update(metatype->tp_dict, metadict) == -1) {
@@ -720,6 +780,7 @@
 			Py_DECREF(metadict);
 			Py_DECREF(protectedMethods);
 			Py_DECREF(hiddenSelectors);
+			Py_DECREF(hiddenClassSelectors);
 			return NULL;
 		}
 	} else {
@@ -743,6 +804,7 @@
 		Py_DECREF(old_dict);
 		Py_DECREF(protectedMethods);
 		Py_DECREF(hiddenSelectors);
+		Py_DECREF(hiddenClassSelectors);
 		(void)PyObjCClass_UnbuildClass(objc_class);
 		return NULL;
 	}
@@ -766,6 +828,7 @@
 			Py_DECREF(old_dict);
 			Py_DECREF(protectedMethods);
 			Py_DECREF(hiddenSelectors);
+			Py_DECREF(hiddenClassSelectors);
 			(void)PyObjCClass_UnbuildClass(objc_class);
 			return NULL;
 		}
@@ -788,6 +851,7 @@
 	info->isCFWrapper = 0;
 	info->protectedMethods = protectedMethods;
 	info->hiddenSelectors = hiddenSelectors;
+	info->hiddenClassSelectors = hiddenClassSelectors;
 
 
 	var = class_getInstanceVariable(objc_class, "__dict__");
@@ -966,6 +1030,8 @@
 		return result;
 	}
 
+
+
 	/* Try to find the method anyway */
 	PyErr_Clear();
 	if (PyUnicode_Check(name)) {
@@ -973,7 +1039,7 @@
 		if (bytes == NULL) {
 			return NULL;
 		}
-		if (PyObjCClass_HiddenSelector(self, sel_getUid(PyString_AsString(bytes)))) {
+		if (PyObjCClass_HiddenSelector(self, sel_getUid(PyString_AsString(bytes)), YES)) {
 			Py_DECREF(bytes);
 			PyErr_SetObject(PyExc_AttributeError, name);
 			return NULL;
@@ -982,7 +1048,7 @@
 		Py_DECREF(bytes);
 #if PY_MAJOR_VERSION == 2
 	} else if (PyString_Check(name)) {
-		if (PyObjCClass_HiddenSelector(self, sel_getUid(PyString_AsString(name)))) {
+		if (PyObjCClass_HiddenSelector(self, sel_getUid(PyString_AsString(name)), YES)) {
 			PyErr_SetObject(PyExc_AttributeError, name);
 			return NULL;
 		}
@@ -1116,7 +1182,8 @@
 		}
 
 
-		if (PyObjCClass_HiddenSelector(self, PyObjCSelector_GetSelector(newVal))) {
+		if (PyObjCClass_HiddenSelector(self, PyObjCSelector_GetSelector(newVal),
+				PyObjCSelector_IsClassMethod(newVal))) {
 			Py_DECREF(newVal);
 		} else {
 			if (PyObjCSelector_IsClassMethod(newVal)) {
@@ -1482,7 +1549,7 @@
 
 		/* Check if the selector should be hidden */
 		if (PyObjCClass_HiddenSelector(py_class, 
-					method_getName(methods[i]))) {
+					method_getName(methods[i]), NO)) {
 			continue;
 		}
 
@@ -1536,7 +1603,7 @@
 
 		/* Check if the selector should be hidden */
 		if (PyObjCClass_HiddenSelector(py_class, 
-					method_getName(methods[i]))) {
+					method_getName(methods[i]), YES)) {
 			continue;
 		}
 
@@ -2268,3 +2335,168 @@
 	return PyObjCClass_New(objc_metaclass_locate(meta));
 }
 
+
+int PyObjCClass_AddMethods(PyObject* classObject, PyObject** methods, Py_ssize_t methodCount)
+{
+	Class targetClass;
+	Py_ssize_t methodIndex;
+	int r;
+	struct PyObjC_method *methodsToAdd;
+	size_t curMethodIndex;
+	struct PyObjC_method *classMethodsToAdd;
+	size_t curClassMethodIndex;
+	PyObject* extraDict = NULL;
+	PyObject* metaDict = NULL;
+
+	targetClass  = PyObjCClass_GetClass(classObject);
+	if (targetClass == NULL) {
+		return -1;
+	}
+
+	if (methodCount == 0) {
+		return 0;
+	}
+
+	extraDict = PyDict_New();
+	if (extraDict == NULL) {
+		return -1;
+	}
+
+	metaDict = PyDict_New();
+	if (metaDict == NULL) {
+		Py_DECREF(extraDict);
+		return -1;
+	}
+
+	methodsToAdd = PyMem_Malloc(sizeof(*methodsToAdd) * methodCount);
+	if (methodsToAdd == NULL) {
+		Py_DECREF(extraDict);
+		Py_DECREF(metaDict);
+		PyErr_NoMemory();
+		return -1;
+	}
+
+	classMethodsToAdd = PyMem_Malloc(sizeof(*methodsToAdd) * methodCount);
+	if (classMethodsToAdd == NULL) {
+		Py_DECREF(extraDict);
+		Py_DECREF(metaDict);
+		PyMem_Free(methodsToAdd);
+		PyErr_NoMemory();
+		return -1;
+	}
+		
+	curMethodIndex = 0;
+	curClassMethodIndex = 0;
+
+	for (methodIndex = 0; methodIndex < methodCount; methodIndex++) {
+		PyObject* aMethod = methods[methodIndex]; 
+		PyObject* name;
+		struct PyObjC_method *objcMethod;
+
+		if (PyObjCNativeSelector_Check(aMethod)) {
+			PyErr_Format(PyExc_TypeError,
+				"Cannot add a native selector to other "
+				"classes");
+			goto cleanup_and_return_error;
+		}
+
+		aMethod = PyObjCSelector_FromFunction(
+			NULL,
+			aMethod,
+			classObject,
+			NULL);
+		if (aMethod == NULL) {
+			PyErr_Format(PyExc_TypeError ,
+			      "All objects in methodArray must be of "
+			      "type <objc.selector>, <function>, "
+			      " <method> or <classmethod>");
+			goto cleanup_and_return_error;
+		}
+
+		/* install in methods to add */
+		if (PyObjCSelector_IsClassMethod(aMethod)) {
+			objcMethod = classMethodsToAdd + curClassMethodIndex++;
+		} else {
+			objcMethod = methodsToAdd + curMethodIndex++;
+		}
+		
+		objcMethod->name = PyObjCSelector_GetSelector(aMethod);
+		objcMethod->type = strdup(
+				PyObjCSelector_Signature(aMethod));
+
+		PyObjC_RemoveInternalTypeCodes((char*)(objcMethod->type));
+		if (objcMethod->type == NULL) {
+			goto cleanup_and_return_error;
+		}
+		objcMethod->imp = PyObjCFFI_MakeIMPForPyObjCSelector(
+			(PyObjCSelector*)aMethod);
+		
+		name = PyObject_GetAttrString(aMethod, "__name__");
+
+#if PY_MAJOR_VERSION == 3
+		if (PyBytes_Check(name)) {
+			PyObject* t = PyUnicode_Decode(
+					PyBytes_AsString(name),
+					PyBytes_Size(name),
+					NULL, NULL);
+			if (t == NULL) {
+				Py_DECREF(name); name = NULL;
+				Py_DECREF(aMethod); aMethod = NULL;
+				goto cleanup_and_return_error;
+			}
+			Py_DECREF(name);
+			name = t;
+		}
+#endif
+		if (PyObjCSelector_IsHidden(aMethod)) {
+			r = PyObjCClass_SetHidden(classObject, objcMethod->name, PyObjCSelector_IsClassMethod(aMethod));
+			if (r == -1) {
+				goto cleanup_and_return_error;
+			}
+		}
+
+		r = 0;
+		if (!PyObjCClass_HiddenSelector(classObject, objcMethod->name, 
+					PyObjCSelector_IsClassMethod(aMethod))) {
+			if (PyObjCSelector_IsClassMethod(aMethod)) {
+				r = PyDict_SetItem(metaDict, name, aMethod);
+			} else {
+				r = PyDict_SetItem(extraDict, name, aMethod);
+			}
+		}
+		Py_DECREF(name); name = NULL;
+		Py_DECREF(aMethod); aMethod = NULL;
+		if (r == -1) {
+			goto cleanup_and_return_error;
+		}
+	}
+
+	/* add the methods */
+	if (curMethodIndex != 0) {
+		class_addMethodList(targetClass, methodsToAdd, curMethodIndex);
+	}
+	PyMem_Free(methodsToAdd);
+	if (curClassMethodIndex != 0) {
+		class_addMethodList(object_getClass(targetClass),
+				classMethodsToAdd, curClassMethodIndex);
+	}
+	PyMem_Free(classMethodsToAdd);
+
+	r = PyDict_Merge(((PyTypeObject*)classObject)->tp_dict, extraDict, 1);
+	if (r == -1) goto cleanup_and_return_error;
+
+	r = PyDict_Merge(Py_TYPE(classObject)->tp_dict, metaDict, 1);
+	if (r == -1) goto cleanup_and_return_error;
+
+	Py_DECREF(extraDict); extraDict = NULL;
+	Py_DECREF(metaDict); metaDict = NULL;
+
+	return 0;
+
+cleanup_and_return_error:
+	Py_XDECREF(metaDict);
+	Py_XDECREF(extraDict);
+	if (methodsToAdd) PyMem_Free(methodsToAdd);
+	if (classMethodsToAdd) PyMem_Free(classMethodsToAdd);
+	return -1;
+}

Modified: trunk/pyobjc/pyobjc-core/Modules/objc/selector.h
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/selector.h	(original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/selector.h	Tue Mar 23 16:08:37 2010
@@ -63,6 +63,7 @@
 Class PyObjCSelector_GetClass(PyObject* obj);
 int   PyObjCSelector_Required(PyObject* obj);
 int   PyObjCSelector_IsClassMethod(PyObject* obj);
+int   PyObjCSelector_IsHidden(PyObject* obj);
 int ObjC_SignatureForSelector(char* class_name, SEL selector, char* signature);
 PyObjCMethodSignature* PyObjCSelector_GetMetadata(PyObject* _self);
 
@@ -77,6 +78,7 @@
 PyObject* PyObjCSelector_New(PyObject* callable, SEL selector, char* signature, int class_method, Class class) ;
 SEL PyObjCSelector_DefaultSelector(const char* methname);
 
+
 PyObject* 
 PyObjCSelector_FromFunction(
 	PyObject* pyname,

Modified: trunk/pyobjc/pyobjc-core/Modules/objc/selector.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/selector.m	(original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/selector.m	Tue Mar 23 16:08:37 2010
@@ -782,6 +782,20 @@
 	NSMethodSignature* methsig;
 	char  buf[1024];
 
+	if (PyObjCObject_Check(self)) {
+		if (PyObjCClass_HiddenSelector((PyObject*)Py_TYPE(self), sel, NO)) {
+			PyErr_Format(PyExc_AttributeError,
+				"No attribute %s", name);
+			return NULL;
+		}
+	} else {
+		if (PyObjCClass_HiddenSelector(self, sel, YES)) {
+			PyErr_Format(PyExc_AttributeError,
+				"No attribute %s", name);
+			return NULL;
+		}
+	}
+
 	if (Object_class == nil) {
 		Object_class = [Object class];
 	}
@@ -1487,7 +1501,7 @@
 {
 static	char*	keywords[] = { "function", "selector", "signature", 
 				"isClassMethod", "argumentTypes", 
-				"returnType", "isRequired", NULL };
+				"returnType", "isRequired", "isHidden", NULL };
 	PyObjCPythonSelector* result;
 	PyObject* callable;
 	char*     signature = NULL;
@@ -1498,11 +1512,12 @@
 	int	  class_method = 0;
 	char      signature_buf[1024];
 	int       required = 1;
+	int       hidden = 0;
 
 	if (!PyArg_ParseTupleAndKeywords(args, kwds, 
-				"O|"Py_ARG_BYTES Py_ARG_BYTES"issi:selector",
+				"O|"Py_ARG_BYTES Py_ARG_BYTES"issii:selector",
 			keywords, &callable, &selector, &signature,
-			&class_method, &argtypes, &rettype, &required)) {
+			&class_method, &argtypes, &rettype, &required, &hidden)) {
 		return NULL;
 	}
 
@@ -1585,6 +1600,9 @@
 	if (required) {
 		result->sel_flags |= PyObjCSelector_kREQUIRED;
 	}
+	if (hidden) {
+		result->sel_flags |= PyObjCSelector_kHIDDEN;
+	}
 	return (PyObject *)result;
 }
 
@@ -1788,6 +1806,11 @@
 	return (PyObjCSelector_GetFlags(obj) & PyObjCSelector_kCLASS_METHOD) != 0;
 }
 
+int   PyObjCSelector_IsHidden(PyObject* obj)
+{
+	return (PyObjCSelector_GetFlags(obj) & PyObjCSelector_kHIDDEN) != 0;
+}
+
 int   PyObjCSelector_GetFlags(PyObject* obj)
 {
 	return ((PyObjCSelector*)obj)->sel_flags;
@@ -1903,6 +1926,9 @@
 		if (result->callable) {
 			Py_INCREF(result->callable);
 		}
+		if (PyObjCClass_HiddenSelector(template_class, PyObjCSelector_GetSelector(callable), PyObjCSelector_IsClassMethod(callable))) {
+			((PyObjCSelector*)result)->sel_flags |= PyObjCSelector_kHIDDEN;
+		}
 		return (PyObject*)result;
 	}
 
@@ -2001,6 +2027,9 @@
 	 * is.
 	 */
 	super_sel = PyObjCClass_FindSelector(template_class, selector, is_class_method);
+	if (super_sel == NULL) {
+		PyErr_Clear();
+	}
 
 	if (is_class_method) {
 		meth = class_getClassMethod(oc_class, selector);
@@ -2028,17 +2057,22 @@
 		 * the user may have specified a more exact
 		 * signature!
 		 */
+		char* typestr = NULL;
+
 		if (super_sel == NULL) {
-			return NULL;
+			/* FIXME: This isn't optimal when hiding methods with non-standard types */
+			typestr = method_getTypeEncoding(meth);
+		} else {
+			typestr = PyObjCSelector_Signature(super_sel);
 		}
 
 		value = PyObjCSelector_New(
 			callable, 
 			selector, 
-			PyObjCSelector_Signature(super_sel),
+			typestr,
 			is_class_method,
 			oc_class);
-		Py_DECREF(super_sel);
+		Py_XDECREF(super_sel);
 	} else {
 		char* signature = NULL;
 
@@ -2058,7 +2092,7 @@
 			is_class_method,
 			oc_class);
 	}
-	if (PyObjCClass_HiddenSelector(template_class, selector)) {
+	if (PyObjCClass_HiddenSelector(template_class, selector, PyObjCSelector_IsClassMethod(value))) {
 		((PyObjCSelector*)value)->sel_flags |= PyObjCSelector_kHIDDEN;
 	}
 

Modified: trunk/pyobjc/pyobjc-core/NEWS.txt
==============================================================================
--- trunk/pyobjc/pyobjc-core/NEWS.txt	(original)
+++ trunk/pyobjc/pyobjc-core/NEWS.txt	Tue Mar 23 16:08:37 2010
@@ -140,7 +140,7 @@
   (At the very least least: the PyObjCMethodSignature objects can be shared 
   more than they are now). 
 
-  This needs further investigation to determine why we use more memory
+  This needs further investigation to determine why we seem to use more memory
   than Ruby.
 
 - TODO: Drop support for 2.5 and 

Modified: trunk/pyobjc/pyobjc-core/PyObjCTest/test_hidden_selector.py
==============================================================================
--- trunk/pyobjc/pyobjc-core/PyObjCTest/test_hidden_selector.py	(original)
+++ trunk/pyobjc/pyobjc-core/PyObjCTest/test_hidden_selector.py	Tue Mar 23 16:08:37 2010
@@ -1,43 +1,202 @@
 from PyObjCTools.TestSupport import *
 import objc
 
+class hidden_method (object):
+     def __pyobjc_class_setup__(self, name, class_dict, instance_methods, class_methods):
+         @objc.selector
+         def method(self):
+             return 42
+
+         method.isHidden = True
+
+         def clsmethod(self):
+             return 99
+         clsmethod=objc.selector(clsmethod, isClassMethod=True)
+         clsmethod.isHidden = True
+
+         instance_methods.add(method)
+         class_methods.add(clsmethod)
+
+
+
+class OCTestHidden (objc.lookUpClass('NSObject')):
+    m = hidden_method()
+
+    @objc.selector
+    def body(self):
+        return "BODY"
+    body.isHidden = True
+
+
+    def bodyclass(self):
+        return "BODYCLASS"
+    bodyclass=objc.selector(bodyclass, isClassMethod=True)
+    bodyclass.isHidden=True
+
+    @objc.selector
+    def somebody(self):
+        return "instance"
+    somebody.isHidden = True
+
+    def boolMethod(self):
+        return 1
+    boolMethod = objc.selector(boolMethod, signature=objc._C_NSBOOL + '@:')
+    boolMethod.isHidden = True
+
+class OCTestSubHidden (OCTestHidden):
+    def body(self):
+        return "BODY2"
+
+    @classmethod
+    def bodyclass(self):
+        return "BODYCLASS2"
+
+    @classmethod
+    def somebody(self):
+        return "class"
+
+    def boolMethod(self):
+        return 0
 
 class TestHiddenSelector (TestCase):
     def testHiddenInClassDef(self):
-        self.fail("todo")
+        o = OCTestHidden.alloc().init()
+        self.assertRaises(AttributeError, getattr, o, 'body')
 
-        # define method in a class definition
-        # and make the method read only (while
-        # still in the class body). Check that
-        # the method is not present in the class
-        # __dict__, but is callable.
-        #
-        # (Callable means through pyobjc_instanceMethods,
-        # not directly)
+        v = o.performSelector_(b'body')
+        self.assertEquals(v, "BODY")
 
-    def testHiddenAddMethods(self):
-        self.fail("todo")
+        v = o.pyobjc_instanceMethods.body()
+        self.assertEquals(v, "BODY")
+
+        self.assertRaises(AttributeError, getattr, OCTestHidden, 'bodyclass')
+        v = OCTestHidden.performSelector_(b'bodyclass')
+        self.assertEquals(v, "BODYCLASS")
+
+        v = OCTestHidden.pyobjc_classMethods.bodyclass()
+        self.assertEquals(v, "BODYCLASS")
+
+        o = OCTestHidden.alloc().init()
+        self.assertRaises(AttributeError, getattr, o, 'boolMethod')
+        v = o.pyobjc_instanceMethods.boolMethod()
+        self.assertIsObject(v, True)
 
-        # Add a hidden selector using objc.classAddMethods
-        # and check that the selector is callable but not
-        # present in the class __dict__
-        #
-        # (Callable means through pyobjc_instanceMethods,
-        # not directly)
 
     def testHiddenInSetupHook(self):
-        self.fail("todo")
+        o = OCTestHidden.alloc().init()
+
+        # Instance method
+        self.assertRaises(AttributeError, getattr, o, 'method')
+
+        v = o.performSelector_(b'method')
+        self.assertEquals(v, 42)
+
+        v = o.pyobjc_instanceMethods.method()
+        self.assertEquals(v, 42)
+
+        # Class method
+        self.assertRaises(AttributeError, getattr, OCTestHidden, 'clsmethod')
+
+        v = OCTestHidden.performSelector_(b'clsmethod')
+        self.assertEquals(v, 99)
+
+        v = OCTestHidden.pyobjc_classMethods.clsmethod()
+        self.assertEquals(v, 99)
+
+
+    def testHiddenAddMethods(self):
+
+        @objc.selector
+        def addedmethod(self):
+            return "NEW"
+        addedmethod.isHidden = True
+
+        def addedclass(self):
+            return "NEWCLASS"
+        addedclass=objc.selector(addedclass, isClassMethod=True)
+        addedclass.isHidden=True
+
+        objc.classAddMethods(OCTestHidden, [addedmethod, addedclass])
+
+        o = OCTestHidden.alloc().init()
+
+        # Instance method
+        self.assertRaises(AttributeError, getattr, o, 'addedmethod')
+
+        v = o.performSelector_(b'addedmethod')
+        self.assertEquals(v, "NEW")
+
+        v = o.pyobjc_instanceMethods.addedmethod()
+        self.assertEquals(v, "NEW")
+
+        # Class method
+        self.assertRaises(AttributeError, getattr, OCTestHidden, 'addedclass')
+
+        v = OCTestHidden.performSelector_(b'addedclass')
+        self.assertEquals(v, "NEWCLASS")
+
+        v = OCTestHidden.pyobjc_classMethods.addedclass()
+        self.assertEquals(v, "NEWCLASS")
+
+    def testClassVsInstance(self):
+        o = OCTestHidden.alloc().init()
+        self.assertRaises(AttributeError, getattr, o, "sombody")
+        v = o.performSelector_(b'somebody')
+        self.assertEquals(v, "instance")
+
+        v = OCTestSubHidden.somebody()
+        self.assertEquals(v, "class")
+
+    def testHiddenInSubClass(self):
+
+        # Instance 
+        o = OCTestSubHidden.alloc().init()
+        self.assertRaises(AttributeError, getattr, o, "body")
+        v = o.performSelector_(b'body')
+        self.assertEquals(v, "BODY2")
+
+        @objc.selector
+        def subclassbody(self):
+            return "base"
+        subclassbody.isHidden = True
+
+        @objc.selector
+        def subclassbody2(self):
+            return "base2"
+        subclassbody.isHidden = True
+
+        objc.classAddMethods(OCTestHidden, [subclassbody, subclassbody2])
+
+
+        @objc.selector
+        def subclassbody(self):
+            return "sub"
+
+        @objc.selector
+        def subclassbody2(self):
+            return "sub2"
+
+        objc.classAddMethods(OCTestSubHidden, [subclassbody])
+        self.assertRaises(AttributeError, getattr, o, "subclassbody")
+        v = o.performSelector_(b'subclassbody')
+        self.assertEquals(v, "sub")
+
+        OCTestSubHidden.subclassbody2 = subclassbody2
+        #self.assertRaises(AttributeError, getattr, o, "subclassbody2")
+        v = o.performSelector_(b'subclassbody2')
+        self.assertEquals(v, "sub2")
 
-        # Use a helper class with a __pyobjc_class_setup__ 
-        # hook to insert hidden selectors in the class 
-        # dict and/or the instance and class methods lists,
-        # check that this behaves correctly.
+        self.assertRaises(AttributeError, getattr, o, 'boolMethod')
+        v = o.pyobjc_instanceMethods.boolMethod()
+        self.assertIsObject(v, False)
 
-    def testHiddenClassMethods(self):
-        self.fail("todo")
+        # Class
+        self.assertRaises(AttributeError, getattr, OCTestSubHidden, 'bodyclass')
+        v = OCTestSubHidden.performSelector_(b'bodyclass')
+        self.assertEquals(v, "BODYCLASS2")
 
-        # Same as testHiddenAddMethods, testHiddenInSetupHook 
-        # and testHiddenInClassDef, but now using a class method.
+    def testTypes(self):
+        self.fail("Add tests with objc._C_CHAR_AS_INT, objc._C_UNICHAR and complex APIs")
 
 if __name__ == "__main__":
     main()

Modified: trunk/pyobjc/pyobjc-core/PyObjCTest/test_methodedits.py
==============================================================================
--- trunk/pyobjc/pyobjc-core/PyObjCTest/test_methodedits.py	(original)
+++ trunk/pyobjc/pyobjc-core/PyObjCTest/test_methodedits.py	Tue Mar 23 16:08:37 2010
@@ -212,14 +212,14 @@
         MEClass.classSomethingElse = classmethod(lambda self: 2*2)
         MEClass.classDuplicate_ = classmethod(lambda self, x: 2*x)
 
-        self.assertTrue(MEClass.pyobjc_classMethods.respondsToSelector_("classSomethingElse"))
-        self.assertTrue(MEClass.pyobjc_classMethods.respondsToSelector_("classDuplicate:"))
+        self.assertTrue(MEClass.pyobjc_classMethods.respondsToSelector_(b"classSomethingElse"))
+        self.assertTrue(MEClass.pyobjc_classMethods.respondsToSelector_(b"classDuplicate:"))
 
         self.assertEquals(4, MEClass.classSomethingElse())
         self.assertEquals(8, MEClass.classDuplicate_(4))
 
     def testAssignFuzzyMethod(self):
-        self.assertRaises(ValueError, setattr, MEClass, 'fuzzyMethod', objc.selector(None, selector=b'fuzzy', signature=b'@@:'))
+        self.assertRaises((ValueError, TypeError), setattr, MEClass, 'fuzzyMethod', objc.selector(None, selector=b'fuzzy', signature=b'@@:'))
 
     def testRemovingMethods(self):
         theClass = NSObject

Modified: trunk/pyobjc/pyobjc-core/setup.py
==============================================================================
--- trunk/pyobjc/pyobjc-core/setup.py	(original)
+++ trunk/pyobjc/pyobjc-core/setup.py	Tue Mar 23 16:08:37 2010
@@ -1,6 +1,14 @@
 #!/usr/bin/env python
 
 import sys
+# We need at least Python 2.5
+MIN_PYTHON = (2, 5)
+
+if sys.version_info < MIN_PYTHON:
+    vstr = '.'.join(map(str, MIN_PYTHON))
+    raise SystemExit('PyObjC: Need at least Python ' + vstr)
+
+
 if sys.version_info[:2] < (3, 0):
     import ez_setup
     ez_setup.use_setuptools()
@@ -94,12 +102,6 @@
 # See the news file:
 #os.environ['MACOSX_DEPLOYMENT_TARGET']='10.5'
 
-# We need at least Python 2.5
-MIN_PYTHON = (2, 5)
-
-if sys.version_info < MIN_PYTHON:
-    vstr = '.'.join(map(str, MIN_PYTHON))
-    raise SystemExit('PyObjC: Need at least Python ' + vstr)
 
 # Set USE_SYSTEM_FFI to True to link to the system version
 # of libffi

------------------------------------------------------------------------------
Download Intel&#174; Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev