[Zope-CVS] CVS: PythonNet/src/runtime - ClassManager.cs:1.5 EventBinding.cs:1.2 EventObject.cs:1.2 MethodBinder.cs:1.4 Runtime.cs:1.9

Brian Lloyd brian at zope.com
Thu Oct 2 23:06:50 EDT 2003


Update of /cvs-repository/PythonNet/src/runtime
In directory cvs.zope.org:/tmp/cvs-serv5985/src/runtime

Modified Files:
	ClassManager.cs EventBinding.cs EventObject.cs MethodBinder.cs 
	Runtime.cs 
Log Message:
Checkin partial event fixes and refactoring


=== PythonNet/src/runtime/ClassManager.cs 1.4 => 1.5 ===
--- PythonNet/src/runtime/ClassManager.cs:1.4	Tue Sep 30 19:54:11 2003
+++ PythonNet/src/runtime/ClassManager.cs	Thu Oct  2 23:06:17 2003
@@ -195,21 +195,25 @@
 			continue;
 		    }
 
-		    ob = new PropertyObject((PropertyInfo) mi);
-		    ci.members[mi.Name] = ob;
+		    ob = new PropertyObject(pi);
+		    ci.members[pi.Name] = ob;
 		    continue;
 
 	        case MemberTypes.Field:
 		    FieldInfo fi = (FieldInfo) mi;
 		    if (!(fi.IsPublic || fi.IsFamily || fi.IsFamilyOrAssembly))
 			continue;
-		    ob = new FieldObject((FieldInfo) mi);
+		    ob = new FieldObject(fi);
 		    ci.members[mi.Name] = ob;
 		    continue;
 
 	        case MemberTypes.Event:
-		    ob = new EventObject((EventInfo) mi);
-		    ci.members[mi.Name] = ob;
+		    EventInfo ei = (EventInfo)mi;
+		    MethodInfo me = ei.GetAddMethod(true);
+		    if (!(me.IsPublic || me.IsFamily || me.IsFamilyOrAssembly))
+			continue;
+		    ob = new EventObject(ei);
+		    ci.members[ei.Name] = ob;
 		    continue;
 
 	        case MemberTypes.NestedType:


=== PythonNet/src/runtime/EventBinding.cs 1.1 => 1.2 ===
--- PythonNet/src/runtime/EventBinding.cs:1.1	Mon Jul 14 15:59:51 2003
+++ PythonNet/src/runtime/EventBinding.cs	Thu Oct  2 23:06:17 2003
@@ -77,7 +77,7 @@
 	    EventBinding self = (EventBinding)GetManagedObject(ob);
 	    string type = (self.target == IntPtr.Zero) ? "unbound" : "bound";
 	    string s = String.Format("<{0} event '{1}'>", type, self.e.name);
-	    return Runtime.PyString_FromStringAndSize(s, s.Length);
+	    return Runtime.PyString_FromString(s);
 	}
 
 	//====================================================================


=== PythonNet/src/runtime/EventObject.cs 1.1 => 1.2 ===
--- PythonNet/src/runtime/EventObject.cs:1.1	Mon Jul 14 15:59:51 2003
+++ PythonNet/src/runtime/EventObject.cs	Thu Oct  2 23:06:17 2003
@@ -21,9 +21,8 @@
 
     internal class EventObject : ExtensionType {
 
-	static Hashtable registry;
-
 	internal string name;
+	Hashtable mapping;
 	EventBinding unbound;
 	EventInfo info;
 
@@ -32,10 +31,27 @@
 	    this.info = info;
 	}
 
-	static EventObject() {
-	    registry = new Hashtable();
-	}
 
+	private string GetMethodToken(object ob, IntPtr handler) {
+
+	    // Any callable Python object can be used as an event handler.
+	    // When a Python event handler is added, we generate a delegate
+	    // that hands off to the Python implementation. To support the 
+	    // ability to remove Python event handlers, we need to recognize 
+	    // the Python version of the hander when it is presented for 
+	    // removal and map that to the delegate that we generated.
+	    //
+	    // This is easier said than done, since some callable objects 
+	    // (bound methods in particular) dont have a stable identity.
+	    // This method generates a (hopefully unique) key for mapping.
+
+	    string s = (ob == null) ? "null" : ob.GetHashCode().ToString();
+	    if (Runtime.PyObject_TYPE(handler) == Runtime.PyMethodType) {
+		return s + Runtime.PyMethod_Self(handler).ToString() +
+		       Runtime.PyMethod_Function(handler).ToString();
+	    }
+	    return s + handler.ToString();
+	}
 
 
 	public int AddEventHandler(IntPtr target, IntPtr handler) {
@@ -45,29 +61,89 @@
 		obj = co.inst;
 	    }
 
-	    //try {
-		Type htype = this.info.EventHandlerType;
-		Delegate d = DelegateManager.GetDelegate(htype, handler);
-		this.info.AddEventHandler(obj, d);
-//  	    }
-//  	    catch(Exception e) {
-//  		Exceptions.SetError(Exceptions.TypeError, e.Message);
-//  		return -1;
-//  	    }
+	    Type type = this.info.EventHandlerType;
+	    Delegate d = DelegateManager.GetDelegate(type, handler);
+	    if (mapping == null) {
+		mapping = new Hashtable();
+	    }
+	    mapping[GetMethodToken(obj, handler)] = d;
+
+	    // Note: AddEventHandler doesn't work for non-public events.
+
+	    object[] args = new object[1];
+	    args[0] = d;
+	    MethodInfo mi = this.info.GetAddMethod(true);
+	    mi.Invoke(obj, BindingFlags.Default, null, args, null);
 
 	    return 0;
 	}
 
-	public int RemoveEventHandler(IntPtr target, IntPtr arg) {
-	    return -1;
+
+	public int RemoveEventHandler(IntPtr target, IntPtr handler) {
+	    Object obj = null;
+	    Delegate d = null;
+
+	    if (target != IntPtr.Zero) {
+		CLRObject co = (CLRObject)ManagedType.GetManagedObject(target);
+		obj = co.inst;
+	    }
+
+	    if (mapping != null) {
+		string token = GetMethodToken(obj, handler);
+		d = mapping[token] as Delegate;
+		if (d != null) {
+		    mapping.Remove(token);
+		}
+	    }
+
+	    if (d == null) {
+		Exceptions.SetError(Exceptions.ValueError, "unknown method");
+		return -1;
+	    }
+
+	    // Note: RemoveEventHandler doesn't work for non-public events.
+
+	    object[] args = new object[1];
+	    args[0] = d;
+	    MethodInfo mi = this.info.GetRemoveMethod(true);
+	    mi.Invoke(obj, BindingFlags.Default, null, args, null);
+
+	    return 0;
 	}
 
+
 	public IntPtr Invoke(IntPtr target, IntPtr args, IntPtr kw) {
-	    MethodInfo method = info.GetRaiseMethod();
-	    MethodBinder binder = new MethodBinder(method);
-	    return binder.Invoke(target, args, kw);
+	    CLRObject co = ManagedType.GetManagedObject(target) as CLRObject;
+	    object obj = (co != null) ? co.inst: null;
+
+	    BindingFlags flags = BindingFlags.Public | 
+                                 BindingFlags.NonPublic |
+		                 BindingFlags.Instance |
+		                 BindingFlags.Static;
+
+	    Type type = info.DeclaringType;
+	    FieldInfo fi = type.GetField(name, flags);
+	    Delegate d = fi.GetValue(obj) as Delegate;
+
+  	    if (d == null) {
+  		IntPtr r = Runtime.PyNone;
+  		Runtime.Incref(r);
+  		return r;
+  	    }
+
+	    // The method target in this case is actually the delegate.
+
+	    MethodInfo method = d.GetType().GetMethod("Invoke", flags);
+	    IntPtr wrapped = CLRObject.GetInstHandle(d);
+	    Runtime.Incref(wrapped);
+  	    MethodBinder binder = new MethodBinder(method);
+ 	    IntPtr op = binder.Invoke(wrapped, args, kw);
+	    Runtime.Decref(wrapped);
+
+	    return op;
 	}
 
+
 	//====================================================================
 	// Descriptor __get__ implementation. A getattr on an event returns
 	// a "bound" event that keeps a reference to the object instance,
@@ -81,7 +157,7 @@
 
 	    // If the event is accessed through its type (rather than via
 	    // an instance) we return an 'unbound' EventBinding that will
-	    // cached for future accesses through the type.
+	    // be cached for future accesses through the type.
 
 	    if (ob == IntPtr.Zero) {
 		if (self.unbound == null) {
@@ -103,6 +179,7 @@
 	    return binding.Handle;
 	}
 
+
 	//====================================================================
 	// Descriptor __set__ implementation. This actually never allows you
 	// to set anything; it exists solely to support the '+=' spelling of
@@ -132,9 +209,10 @@
 	[CallConvCdecl()]
 	public static IntPtr tp_repr(IntPtr ob) {
 	    EventObject self = (EventObject)GetManagedObject(ob);
-	    string s = String.Format("<event '{0}'>", self.info.Name);
-	    return Runtime.PyString_FromStringAndSize(s, s.Length);
+	    string s = String.Format("<event '{0}'>", self.name);
+	    return Runtime.PyString_FromString(s);
 	}
+
 
 	//====================================================================
 	// Descriptor dealloc implementation.


=== PythonNet/src/runtime/MethodBinder.cs 1.3 => 1.4 ===
--- PythonNet/src/runtime/MethodBinder.cs:1.3	Tue Sep 30 19:54:11 2003
+++ PythonNet/src/runtime/MethodBinder.cs	Thu Oct  2 23:06:17 2003
@@ -53,13 +53,18 @@
 	internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw) {
 	    // loop to find match, return invoker w/ or /wo error
 	    int nargs = Runtime.PyTuple_Size(args);
+
+	    //DebugUtil.Print("args", args);
 	    if (!init) {
 		methods = (MethodBase[])list.ToArray(typeof(MethodBase));
+		init = true;
 	    }
 
 	    for (int i = 0; i < methods.Length; i++) {
 		MethodBase mi = methods[i];
+
 		ParameterInfo[] pi = mi.GetParameters();
+
 		int count = pi.Length;
 
 		if ( nargs == count ) {
@@ -92,7 +97,6 @@
 		}
 
 	    }
-
 	    return null;
 	}
 


=== PythonNet/src/runtime/Runtime.cs 1.8 => 1.9 ===
--- PythonNet/src/runtime/Runtime.cs:1.8	Tue Sep 30 19:54:11 2003
+++ PythonNet/src/runtime/Runtime.cs	Thu Oct  2 23:06:17 2003
@@ -47,6 +47,10 @@
 	    PyNoneType = Runtime.PyObject_Type(PyNone); 
 	    PyTypeType = Runtime.PyObject_Type(PyNoneType); 
 
+	    op = Runtime.PyObject_GetAttrString(dict, "keys");
+	    PyMethodType = Runtime.PyObject_Type(op);
+	    Runtime.Decref(op);
+
 	    op = Runtime.PyString_FromString("string");
 	    PyStringType = Runtime.PyObject_Type(op); 
 	    Runtime.Decref(op);
@@ -122,6 +126,7 @@
 	internal static IntPtr PyClassType;
 	internal static IntPtr PyInstanceType;
 	internal static IntPtr PyCLRMetaType;
+	internal static IntPtr PyMethodType;
 
 	internal static IntPtr PyUnicodeType;
 	internal static IntPtr PyStringType;
@@ -729,10 +734,9 @@
 	    return PyObject_TYPE(ob) == Runtime.PyStringType;
 	}
 
-	[DllImport("python22", CallingConvention=CallingConvention.Cdecl,
-		    ExactSpelling=true, CharSet=CharSet.Ansi)]
-	internal unsafe static extern IntPtr
-	PyString_FromString(string value);
+	internal static IntPtr PyString_FromString(string value) {
+	    return PyString_FromStringAndSize(value, value.Length);
+	}
 
 	[DllImport("python22", CallingConvention=CallingConvention.Cdecl,
 		    ExactSpelling=true, CharSet=CharSet.Ansi)]
@@ -1190,6 +1194,21 @@
 		    ExactSpelling=true, CharSet=CharSet.Ansi)]
         internal unsafe static extern void
 	PyErr_Clear();
+
+
+	//====================================================================
+	// Miscellaneous
+	//====================================================================
+
+	[DllImport("python22", CallingConvention=CallingConvention.Cdecl,
+		    ExactSpelling=true, CharSet=CharSet.Ansi)]
+        internal unsafe static extern IntPtr
+	PyMethod_Self(IntPtr ob);
+
+	[DllImport("python22", CallingConvention=CallingConvention.Cdecl,
+		    ExactSpelling=true, CharSet=CharSet.Ansi)]
+        internal unsafe static extern IntPtr
+	PyMethod_Function(IntPtr ob);
 
     }
 




More information about the Zope-CVS mailing list