Commits

Ronald Oussoren committed fe83b87

- Add wrappers for NSDictionary initWithObjects:forKeys:count and
dictionaryWithObjects:forKeys:count:
- Fix some problems with objc.splitSignature. The function used to
cause crashes for some of the signatures used in Cocoa, you can
now call splitSignature on any signature used in Cocoa.
- Object (the implicit base class of all Objective-C classes) doesn't
implement all methods that are used by the bridge, compensate for
this on the one occasion that crashed one of my scripts.

Comments (0)

Files changed (12)

pyobjc/Lib/Foundation/test/test_nsdictionary.py

+# TODO: Tests for calling 
+#   initWithObjects:forKeys:count and dictionaryWithObjects:forKeys:count
 import unittest
 import objc
 import types
 
 from Foundation import *
 
+
+class TestNSDictionarySubclassing(unittest.TestCase):
+    def testExceptionInInit(self):
+        class DictTestExceptionClass (NSDictionary):
+            pass
+
+        # Don't use self.assertRaises here, we once had a bug that 
+        # causes this to fail, while the assertRaises version would
+        # (probably) have worked.
+        try:
+            d = DictTestExceptionClass.alloc().initWithDictionary_({})
+            self.fail()
+        except ValueError:
+            pass
+
+    def testAnotherExceptionInInit(self):
+        class DictTestExceptionClass2 (NSDictionary):
+            def initWithObjects_forKeys_count_(self, o, k, c):
+                return super(DictTestExceptionClass2, self).initWithObjects_forKeys_count_(o, k, c)
+
+        try:
+            d = DictTestExceptionClass2.alloc().initWithDictionary_({})
+            self.fail()
+        except ValueError:
+            pass
+
+    def testExceptionInInitClsMeth(self):
+        class DictTestExceptionClass3 (NSDictionary):
+            def initWithObjects_forKeys_count_(self, o, k, c):
+                return super(DictTestExceptionClass3, self).initWithObjects_forKeys_count_(o, k, c)
+
+        try:
+            d = DictTestExceptionClass3.dictionaryWithDictionary_({})
+            self.fail()
+        except ValueError:
+            pass
+
+
 class TestNSDictionaryInteraction(unittest.TestCase):
     def testMethods(self):
         for nm in dir(types.DictType):

pyobjc/Lib/objc/_convenience.py

     ( 'initWithObjectsAndKeys_', initWithObjectsAndKeys_ ),
 )
 
-# 'dictionaryWithObjects:forKeys:count' is not really a varargs function, but
-# would require a custom wrapper.
-
-def dictionaryWithObjects_forKeys_count_(self, objects, keys, count):
-    return self.dictionaryWithObjects_forKeys_(objects[:count], keys[:count])
-
-CONVENIENCE_METHODS['dictionaryWithObjects:forKeys:count:'] = (
-    ('dictionaryWithObjects_forKeys_count_', 
-      selector(dictionaryWithObjects_forKeys_count_, signature='@@:^@^@i', isClassMethod=1)),
-)
-
-def initWithObjects_forKeys_count_(self, objects, keys, count):
-    return self.initWithObjects_forKeys_(objects[:count], keys[:count])
-
-CONVENIENCE_METHODS['initWithObjects:forKeys:count:'] = (
-    ( 'initWithObjects_forKeys_count_', 
-        selector(initWithObjects_forKeys_count_, signature='@@:^@^@i') ),
-)
-
 def UnsupportedMethod(self, *args):
     raise ValueError, "Unsupported method"
 

pyobjc/Modules/Foundation/_FoundationMapping.m

 /* These are needed to silence GCC */
 void init_FoundationMapping(void);
 int _pyobjc_install_NSCoder(void);
+int _pyobjc_install_NSDictionary(void);
 int _pyobjc_install_NSData(void);
 
+#include "_FoundationMapping_NSCoder.m"
 #include "_FoundationMapping_NSData.m"
-#include "_FoundationMapping_NSCoder.m"
+#include "_FoundationMapping_NSDictionary.m"
 
 
 void init_FoundationMapping(void)
 
 	if (_pyobjc_install_NSCoder()) return;
 	if (_pyobjc_install_NSData()) return;
+	if (_pyobjc_install_NSDictionary()) return;
 }

pyobjc/Modules/Foundation/_FoundationMapping_NSData.m

 
 
 static PyObject* call_NSData_dataWithBytes_length_(
-		PyObject* method __attribute__((__unused__)), PyObject* self, PyObject* arguments)
+		PyObject* method, PyObject* self, PyObject* arguments)
 {
 	char*     bytes;
 	int       bytes_len;
 	}
 
 	NS_DURING
-		PyObjC_InitSuperCls(&super, PyObjCClass_GetClass(self));
+		PyObjC_InitSuperCls(&super, PyObjCClass_GetClass(method), self);
 
 		objc_result = objc_msgSendSuper(&super,
 				@selector(dataWithBytes:length:),

pyobjc/Modules/objc/class-builder.m

 		method_count      += 4;
 	}
 
+	/* Allocate the class as soon as possible, for new selector objects */
+	new_class = calloc(1, sizeof(struct class_wrapper));
+	if (new_class == NULL) {
+		goto error_cleanup;
+	}
+
 	/* First round, count new instance-vars and check for overridden 
 	 * methods.
 	 */
 				method_count ++;
 			}
 
+			/* TODO: If it already has a sel_class, create a copy */
+			((PyObjCSelector*)value)->sel_class =
+				&new_class->class;
+
 		} else if (PyMethod_Check(value) || PyFunction_Check(value)) {
 			PyObject* pyname;
 			char*     ocname;
 					value, 
 					selector, 
 					PyObjCSelector_Signature(super_sel),
-					is_class_method);
+					is_class_method,
+					&new_class->class);
+				new_class->class.name = "TempValue";
 				Py_DECREF(super_sel);
 			} else {
 				char* signature;
 					value, 
 					selector, 
 					signature,
-					0);
+					0,
+					&new_class->class);
 			}
 			if (value == NULL) goto error_cleanup;
 				
 
 	/* And fill the method_lists and ivar_list */
 
+#if 0
 	/* Create new_class here, just in case we are the first python
 	 * generation, in which case we need to use new_class (it must just
 	 * be there, it doesn't have to be initialized)
 	if (new_class == NULL) {
 		goto error_cleanup;
 	}
+#endif
 
 
 	ivar_size = super_class->instance_size;
 	PyObject* result;
 
 
-	pyself = PyObjCObject_New(self);
+	pyself = pythonify_c_value("@", &self);
 	if (pyself == NULL) {
 		PyObjCErr_ToObjC();
 		return NULL;
 	}
-	pymeth = PyObjCObject_FindSelector(pyself, selector);
+	
+	if (PyObjCClass_Check(pyself)) {
+		pymeth = PyObjCClass_FindSelector(pyself, selector);
+	} else {
+		pymeth = PyObjCObject_FindSelector(pyself, selector);
+	}
 	if (pymeth == NULL) {
 		Py_DECREF(pyself);
 		PyObjCErr_ToObjC();

pyobjc/Modules/objc/module.m

 	result = PyList_New(0);
 	if (result == NULL) return NULL;
 	
-	while (*signature != 0) {
+	while (signature && *signature != 0) {
 		PyObject* str;
 
 		end = PyObjCRT_SkipTypeSpec(signature);

pyobjc/Modules/objc/objc-class.m

 	int                i;
 	int                len;
 
+
 	if (!PyObjCClass_Check(cls)) {
 		ObjCErr_Set(ObjCExc_internal_error,
 			"PyObjCClass_GetClass called for non-class");

pyobjc/Modules/objc/objc_support.m

 
 	switch (*type) {
 	/* The following are one character type codes */
+	case _C_UNDEF:
 	case _C_ID:
 	case _C_CLASS:
 	case _C_SEL:
 	case _C_VOID:
 	case _C_LNGLNG:
 	case _C_ULNGLNG:
+	case _C_BFLD: /* Not really 1 character, but close enough  */
 		++type;
 		break;
 
     
 		while (isdigit (*++type));
 		type = PyObjCRT_SkipTypeSpec (type);
-		assert (*type == _C_ARY_E);
-		++type;
+		assert (type == NULL || *type == _C_ARY_E);
+		if (type) type++;
 		break;
       
 	case _C_STRUCT_B:
 		/* skip name, and elements until closing '}'  */
-    
-		while (*type != _C_STRUCT_E && *type++ != '=');
-		while (*type != _C_STRUCT_E)
+   		while (*type != _C_STRUCT_E && *type++ != '='); 
+		while (type && *type != _C_STRUCT_E)
 			type = PyObjCRT_SkipTypeSpec (type);
-		++type;
+		if (type) type++;
 		break;
 
 	case _C_UNION_B:
 		/* skip name, and elements until closing ')'  */
-		type++;
-		while (*type != _C_UNION_E) { type = PyObjCRT_SkipTypeSpec (type); }
-		++type;
+   		while (*type != _C_UNION_E && *type++ != '='); 
+		while (type && *type != _C_UNION_E) { 
+			type = PyObjCRT_SkipTypeSpec (type); 
+		}
+		if (type) type++;
 		break;
       
 	case _C_PTR:
 		return NULL;
 	}
 
-	while (isdigit(*type)) type++;
+	while (type && isdigit(*type)) type++;
 	return type;
 }
 

pyobjc/Modules/objc/pyobjc-api.h

  * This is the *only* header file that should be used to access 
  * functionality in the core bridge.
  *
- * $Id: pyobjc-api.h,v 1.13 2003/06/01 19:06:31 ronaldoussoren Exp $
+ * $Id: pyobjc-api.h,v 1.14 2003/06/05 20:11:52 ronaldoussoren Exp $
  */
 
 #include <Python.h>
 	/* PyObjCBool_FromLong */
 	PyObject*  (*bool_init)(long i);
 
-	/* PyObjC_InitSuper */
+	/* PyObjC_InitSuper */ 	// FIX ME!
 	void	(*fill_super)(struct objc_super*, Class, id);
 
 	/* PyObjC_InitSuperCls */
-	void	(*fill_super_cls)(struct objc_super*, Class);
+	void	(*fill_super_cls)(struct objc_super*, Class, Class);
 };
 
 

pyobjc/Modules/objc/pyobjc-api.m

 	super->class = cls;
 }
 
-static void 	fill_super_cls(struct objc_super* super, Class cls)
+static void 	fill_super_cls(struct objc_super* super, Class cls, Class self)
 {
-	RECEIVER(*super) = cls;
+	RECEIVER(*super) = self;
 	super->class = GETISA(cls);
 }
 

pyobjc/Modules/objc/pyobjc.h

 PyObject* PyObjCSelector_FindNative(PyObject* self, char* name);
 
 PyObject*
-PyObjCSelector_New(PyObject* callable, SEL selector, char* signature, int class_method) ;
+PyObjCSelector_New(PyObject* callable, SEL selector, char* signature, int class_method, Class class) ;
 SEL PyObjCSelector_DefaultSelector(char* methname);
 
 

pyobjc/Modules/objc/selector.m

 #include "compile.h" /* from Python */
 #include "pyobjc.h"
 #include "objc_support.h"
+#include <objc/Object.h>
 
 /*
  * First section deals with registering replacement signatures for methods.
 {
 	PyObjCSelector* self = (PyObjCSelector*)object;	
 
-	/* HACK */
 	if (ObjCNativeSelector_Check(self)) {
 		[((ObjCNativeSelector*)self)->sel_oc_signature release];
 	}
 	result->sel_call_func = meth->sel_call_func;
 
 	if (meth->sel_oc_signature == NULL) {
-		meth->sel_oc_signature = [NSMethodSignature signatureWithObjCTypes:meth->sel_signature];
-		[meth->sel_oc_signature retain];
+		NS_DURING
+			meth->sel_oc_signature = [NSMethodSignature signatureWithObjCTypes:meth->sel_signature];
+			[meth->sel_oc_signature retain];
+		NS_HANDLER
+			meth->sel_oc_signature = nil;
+		NS_ENDHANDLER
 	}
 	result->sel_oc_signature = meth->sel_oc_signature;
 	[result->sel_oc_signature retain];
 
 	return result;
 }
-	
+
+static Class Object_class = nil;
 
 PyObject*
 PyObjCSelector_FindNative(PyObject* self, char* name)
 	NSMethodSignature* methsig;
 	char  buf[1024];
 
+	if (Object_class == nil) {
+		Object_class = [Object class];
+	}
+
 	if (PyObjCClass_Check(self)) {
 		Class cls = PyObjCClass_GetClass(self);
 
 			methsig = [cls instanceMethodSignatureForSelector:sel];
 			return PyObjCSelector_NewNative(cls, sel, 
 				typestr_from_NSMethodSignature(methsig, buf, sizeof(buf)), 0);
-		} else if (nil != (methsig = [cls methodSignatureForSelector:sel])) {
+		} else if ((cls != Object_class) && nil != (methsig = [cls methodSignatureForSelector:sel])) {
 			return PyObjCSelector_NewNative(cls, sel, 
 				typestr_from_NSMethodSignature(methsig, buf, sizeof(buf)), 1);
 		} else {
 }
 
 
-
 PyObject*
 PyObjCSelector_NewNative(Class class, 
 			SEL selector, char* signature, int class_method)
 
 PyObject*
 PyObjCSelector_New(PyObject* callable, 
-	SEL selector, char* signature, int class_method)
+	SEL selector, char* signature, int class_method, Class cls)
 {
 	ObjCPythonSelector* result;
 
+
 	result = PyObject_New(ObjCPythonSelector, &ObjCPythonSelector_Type);
 	if (result == NULL) return NULL;
 
 		}
 	}
 	result->sel_self = NULL;
-	result->sel_class = NULL;
+	result->sel_class = cls;
 	result->sel_flags = 0;
 	result->callable = callable;
 	if (class_method) {
 	if (sel->sel_self == NULL) {
 		if (sel->sel_class) {
 			snprintf(buf, sizeof(buf),
-				"<unbound selector %s of %s>", 
+				"<unbound selector %s of %s at %p>", 
 				SELNAME(sel->sel_selector),
-				sel->sel_class->name);
+				sel->sel_class->name, 
+				sel);
 		} else {
 			snprintf(buf, sizeof(buf),
-				"<unbound selector %s>", 
-				SELNAME(sel->sel_selector));
+				"<unbound selector %s at %p>", 
+				SELNAME(sel->sel_selector),
+				sel);
 		}
 	} else {
 		PyObject* selfrepr = PyObject_Repr(sel->sel_self);
 pysel_dealloc(PyObject* obj)
 {
 	Py_DECREF(((ObjCPythonSelector*)obj)->callable);
+	(((ObjCPythonSelector*)obj)->callable) = NULL;
 	sel_dealloc(obj);
 }
 
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.