[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