[Zope-CVS] CVS: PythonNet/src/runtime - CLRObject.cs:1.4 ClassBase.cs:1.9 ClassManager.cs:1.8 ClassObject.cs:1.9 ConstructorBinder.cs:1.4 Converter.cs:1.7 DebugHelper.cs:1.6 EventBinding.cs:1.5 EventObject.cs:1.6 ExtensionType.cs:1.4 MetaType.cs:1.8 MethodBinder.cs:1.7 MethodBinding.cs:1.3 MethodObject.cs:1.4 Python.cs:1.4 TypeManager.cs:1.10

Brian Lloyd cvs-admin at zope.org
Mon Oct 27 21:07:33 EST 2003


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

Modified Files:
	CLRObject.cs ClassBase.cs ClassManager.cs ClassObject.cs 
	ConstructorBinder.cs Converter.cs DebugHelper.cs 
	EventBinding.cs EventObject.cs ExtensionType.cs MetaType.cs 
	MethodBinder.cs MethodBinding.cs MethodObject.cs Python.cs 
	TypeManager.cs 
Log Message:
Checkin for b1, before the cable bugs out again :(



=== PythonNet/src/runtime/CLRObject.cs 1.3 => 1.4 ===
--- PythonNet/src/runtime/CLRObject.cs:1.3	Mon Oct 20 23:05:14 2003
+++ PythonNet/src/runtime/CLRObject.cs	Mon Oct 27 21:07:00 2003
@@ -22,13 +22,27 @@
 	internal Object inst;
 
 	internal CLRObject(Object ob, IntPtr tp) : base() {
+
 	    IntPtr py = Runtime.PyType_GenericAlloc(tp, 0);
+
+  	    int flags = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_flags);
+  	    if ((flags & TypeFlags.Subclass) != 0) {
+		IntPtr dict = Marshal.ReadIntPtr(py, ObjectOffset.ob_dict);
+		if (dict == IntPtr.Zero) {
+		    dict = Runtime.PyDict_New();
+		    Marshal.WriteIntPtr(py, ObjectOffset.ob_dict, dict);
+		}
+	    }
+
 	    GCHandle gc = GCHandle.Alloc(this);
 	    Marshal.WriteIntPtr(py, ObjectOffset.magic(), (IntPtr)gc);
 	    this.tpHandle = tp;
 	    this.pyHandle = py;
 	    this.gcHandle = gc;
 	    inst = ob;
+
+	    //DebugUtil.DumpInst(py);
+
 	}
 
 


=== PythonNet/src/runtime/ClassBase.cs 1.8 => 1.9 ===
--- PythonNet/src/runtime/ClassBase.cs:1.8	Wed Oct 22 22:53:10 2003
+++ PythonNet/src/runtime/ClassBase.cs	Mon Oct 27 21:07:00 2003
@@ -122,11 +122,13 @@
 
 	[CallConvCdecl()]
 	public static int tp_traverse(IntPtr ob, IntPtr func, IntPtr args) {
+	    //Console.WriteLine("cb traverse");
 	    return 0;
 	}
 
 	[CallConvCdecl()]
 	public static int tp_clear(IntPtr ob) {
+	    //Console.WriteLine("cb clear");
 	    return 0;
 	}
 
@@ -141,6 +143,7 @@
 
 	[CallConvCdecl()]
 	public static void tp_dealloc(IntPtr ob) {
+	    //Console.WriteLine("cb dealloc!");
 	    ManagedType self = GetManagedObject(ob);
 	    IntPtr dict = Marshal.ReadIntPtr(ob, ObjectOffset.ob_dict);
 	    Runtime.Decref(dict);


=== PythonNet/src/runtime/ClassManager.cs 1.7 => 1.8 ===
--- PythonNet/src/runtime/ClassManager.cs:1.7	Wed Oct 22 22:53:10 2003
+++ PythonNet/src/runtime/ClassManager.cs	Mon Oct 27 21:07:00 2003
@@ -131,19 +131,44 @@
 	    String name;
 	    Object item;
 	    Type tp;
+	    int i;
 
+	    // This is complicated because inheritance in Python is name 
+	    // based. We can't just find DeclaredOnly members, because we
+	    // could have a base class A that defines two overloads of a
+	    // method and a class B that defines two more. The name-based
+	    // descriptor Python will find needs to know about inherited
+	    // overloads as well as those declared on the sub class.
 
-	    BindingFlags flags = BindingFlags.DeclaredOnly | 
-		                 BindingFlags.Static | 
+	    BindingFlags flags = BindingFlags.Static | 
 		                 BindingFlags.Instance | 
 	                         BindingFlags.Public | 
                                  BindingFlags.NonPublic;
 
 	    MemberInfo[] info = type.GetMembers(flags);
+	    Hashtable local = new Hashtable();
+	    ArrayList items = new ArrayList();
+	    MemberInfo m;
+
+	    // Loop through once to find out which names are declared
+	    for (i = 0; i < info.Length; i++) {
+		m = info[i];
+		if (m.DeclaringType == type) {
+		    local[m.Name] = 1;
+		}
+	    }
+
+	    // Now again to filter w/o losing overloaded member info
+	    for (i = 0; i < info.Length; i++) {
+		m = info[i];
+		if (local[m.Name] != null) {
+		    items.Add(m);
+		}
+	    }
 
-	    for (int i = 0; i < info.Length; i++) {
+	    for (i = 0; i < items.Count; i++) {
 
-		MemberInfo mi = info[i];
+		MemberInfo mi = (MemberInfo)items[i];
 
 		switch(mi.MemberType) {
 
@@ -248,13 +273,7 @@
 	}
 
 
-
-
-
     }	
-
-
-
 
 
     internal class ClassInfo {


=== PythonNet/src/runtime/ClassObject.cs 1.8 => 1.9 ===
--- PythonNet/src/runtime/ClassObject.cs:1.8	Wed Oct 22 22:53:10 2003
+++ PythonNet/src/runtime/ClassObject.cs	Mon Oct 27 21:07:00 2003
@@ -43,46 +43,6 @@
 	[CallConvCdecl()]
 	public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) {
 
-	    // If this class is a managed subclass (generated by the managed
-	    // metatype), then we just want to call up the __bases__ to get
-	    // the right object created, then fix it up.
-
-	    int flags = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_flags);
-
-	    if ((flags & TypeFlags.Subclass) != 0) {
-		IntPtr base_ = Marshal.ReadIntPtr(tp, TypeOffset.tp_base);
-		if (base_ == IntPtr.Zero) {
-		    return Exceptions.InvalidTypeError(tp);
-		}
-		IntPtr func = Marshal.ReadIntPtr(tp, TypeOffset.tp_new);
-		if (func == IntPtr.Zero) {
-		    return Exceptions.InvalidTypeError(tp);
-		}
-
-		IntPtr obj = NativeCall.Call_3(func, base_, args, kw);
-		if (obj == IntPtr.Zero) {
-		    return IntPtr.Zero;
-		}
-
-		// Set ob_type to the managed subclass rather than the type
-		// that created it, and create the __dict__ of the object if
-		// it hasn't been created already. We can get away with this
-		// because we only allow single inheritance and can depend on
-		// a known in-memory format for the instance object.
-
-		Runtime.Decref(base_);
-		Runtime.Incref(tp);
-		Marshal.WriteIntPtr(obj, ObjectOffset.ob_type, tp);
-
-		IntPtr dict = Marshal.ReadIntPtr(obj, ObjectOffset.ob_dict);
-		if (dict == IntPtr.Zero) {
-		    dict = Runtime.PyDict_New();
-		    Marshal.WriteIntPtr(obj, ObjectOffset.ob_dict, dict);
-		}
-
-		return obj;
-	    }
-
 	    ClassObject self = GetManagedObject(tp) as ClassObject;
 
 	    // Sanity check: this ensures a graceful error if someone does
@@ -131,7 +91,14 @@
 		return IntPtr.Zero;
 	    }
 
-	    return self.binder.Invoke(IntPtr.Zero, args, kw);
+	    Object obj = self.binder.InvokeRaw(IntPtr.Zero, args, kw);
+
+	    if (obj == null) {
+		Runtime.Incref(Runtime.PyNone);
+		return Runtime.PyNone;
+	    }
+
+	    return CLRObject.GetInstHandle(obj, tp);
 	}
 
 


=== PythonNet/src/runtime/ConstructorBinder.cs 1.3 => 1.4 ===
--- PythonNet/src/runtime/ConstructorBinder.cs:1.3	Tue Sep 30 19:54:11 2003
+++ PythonNet/src/runtime/ConstructorBinder.cs	Mon Oct 27 21:07:00 2003
@@ -10,7 +10,6 @@
 // FOR A PARTICULAR PURPOSE.
 
 using System;
-using System.Collections;
 using System.Reflection;
 
 namespace Python.Runtime {
@@ -27,7 +26,16 @@
 
 	internal ConstructorBinder () : base() {}
 
-	internal override IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw) {
+	//====================================================================
+	// Constructors get invoked when an instance of a wrapped managed
+	// class or a subclass of a managed class is created. This differs
+	// from the MethodBinder implementation in that we return the raw
+	// result of the constructor rather than wrapping it as a Python 
+	// object - the reason is that only the caller knows the correct
+	// Python type to use when wrapping the result (may be a subclass).
+	//====================================================================
+
+	internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw) {
 	    Binding binding = this.Bind(inst, args, kw);
 	    Object result;
 
@@ -38,9 +46,10 @@
 		return IntPtr.Zero;
 	    }
 
-	    ConstructorInfo ci = (ConstructorInfo)binding.info;
-	    //	    IntPtr ts = PythonEngine.BeginAllowThreads();
+	    // Object construction is presumed to be non-blocking and fast
+	    // enough that we shouldn't really need to release the GIL.
 
+	    ConstructorInfo ci = (ConstructorInfo)binding.info;
 	    try {
 		result = ci.Invoke(binding.args);
 	    }
@@ -48,14 +57,13 @@
 		if (e.InnerException != null) {
 		    e = e.InnerException;
 		}
-		//PythonEngine.EndAllowThreads(ts);
 		Exceptions.SetError(e);
 		return IntPtr.Zero;
 	    }
 
-	    //PythonEngine.EndAllowThreads(ts);
-	    return Converter.ToPythonImplicit(result);
+	    return result;
 	}
+
 
     }
 


=== PythonNet/src/runtime/Converter.cs 1.6 => 1.7 ===
--- PythonNet/src/runtime/Converter.cs:1.6	Wed Oct 22 22:53:10 2003
+++ PythonNet/src/runtime/Converter.cs	Mon Oct 27 21:07:00 2003
@@ -159,8 +159,15 @@
 
 	    if (mt != null) {
 		if (mt is CLRObject) {
-		    result = ((CLRObject)mt).inst;
-		    return true;
+		    object tmp = ((CLRObject)mt).inst;
+		    if (obType.IsInstanceOfType(tmp)) {
+			result = tmp;
+			return true;
+		    }
+		    string err = "value cannot be converted to {0}";
+		    err = String.Format(err, obType);
+		    Exceptions.SetError(Exceptions.TypeError, err);
+		    return false;
 		}
 		if (mt is ClassBase) {
 		    result = ((ClassBase)mt).type;
@@ -516,8 +523,8 @@
 	    if (size < 0) {
 		if (setError) {
 		    SetConversionError(value, obType);
-		    return false;
 		}
+		return false;
 	    }
 
 	    Array items = Array.CreateInstance(elementType, size);


=== PythonNet/src/runtime/DebugHelper.cs 1.5 => 1.6 ===
--- PythonNet/src/runtime/DebugHelper.cs:1.5	Wed Oct 22 22:53:10 2003
+++ PythonNet/src/runtime/DebugHelper.cs	Mon Oct 27 21:07:00 2003
@@ -58,13 +58,6 @@
 	    //op = Marshal.ReadIntPtr(type, TypeOffset.tp_mro);
 	    //DebugUtil.Print("  mro: ", op);
 
-	    op = Marshal.ReadIntPtr(type, TypeOffset.tp_dict);
-	    if (op == IntPtr.Zero) {
-		Console.WriteLine("  dict: null");
-	    }
-	    else {
-		DebugUtil.Print("  dict: ", op);
-	    }
 
 	    FieldInfo[] slots = typeof(TypeOffset).GetFields();
 	    int size = IntPtr.Size;
@@ -74,6 +67,30 @@
 		name = slots[i].Name;
 		op = Marshal.ReadIntPtr(type, offset);
 		Console.WriteLine("  {0}: {1}", name, op);
+	    }
+
+	    Console.WriteLine("");
+	    Console.WriteLine("");
+
+	    op = Marshal.ReadIntPtr(type, TypeOffset.tp_dict);
+	    if (op == IntPtr.Zero) {
+		Console.WriteLine("  dict: null");
+	    }
+	    else {
+		DebugUtil.Print("  dict: ", op);
+	    }
+
+	}
+
+
+	internal static void DumpInst(IntPtr ob) {
+	    IntPtr tp = Runtime.PyObject_TYPE(ob);
+	    int sz = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_basicsize);
+
+	    for (int i = 0; i < sz; i += IntPtr.Size) {
+		IntPtr pp = new IntPtr(ob.ToInt64() + i);
+		IntPtr v = Marshal.ReadIntPtr(pp);
+		Console.WriteLine("offset {0}: {1}", i, v);
 	    }
 
 	    Console.WriteLine("");


=== PythonNet/src/runtime/EventBinding.cs 1.4 => 1.5 ===
--- PythonNet/src/runtime/EventBinding.cs:1.4	Wed Oct 22 22:53:10 2003
+++ PythonNet/src/runtime/EventBinding.cs	Mon Oct 27 21:07:00 2003
@@ -95,6 +95,26 @@
 	[CallConvCdecl()]
 	public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) {
 	    EventBinding self = (EventBinding)GetManagedObject(ob);
+
+	    // This supports calling an event 'unbound', passing the instance
+	    // as the first argument. Only meaningful for instance events.
+
+	    if ((self.target == IntPtr.Zero) && (!self.e.IsStatic())) {
+		if (Runtime.PyTuple_Size(args) < 1) {
+		    Exceptions.SetError(Exceptions.TypeError, 
+					"not enough arguments"
+					);
+		    return IntPtr.Zero;
+		}
+		int len = Runtime.PyTuple_Size(args);
+		IntPtr uargs = Runtime.PyTuple_GetSlice(args, 1, len);
+		IntPtr inst = Runtime.PyTuple_GetItem(args, 0);
+		Runtime.Incref(inst);
+		IntPtr r = self.e.Invoke(inst, uargs, kw);
+		Runtime.Decref(inst);
+		return r;
+	    }
+
 	    return self.e.Invoke(self.target, args, kw);
 	}
 


=== PythonNet/src/runtime/EventObject.cs 1.5 => 1.6 ===
--- PythonNet/src/runtime/EventObject.cs:1.5	Wed Oct 22 22:53:10 2003
+++ PythonNet/src/runtime/EventObject.cs	Mon Oct 27 21:07:00 2003
@@ -22,9 +22,9 @@
     internal class EventObject : ExtensionType {
 
 	internal string name;
-	EventBinding unbound;
-	EventInfo info;
-	FieldInfo fi;
+	internal EventBinding unbound;
+	internal EventInfo info;
+	internal FieldInfo fi;
 
 	public EventObject(EventInfo info) : base() {
 	    Type t = info.DeclaringType;
@@ -39,6 +39,10 @@
 		                    BindingFlags.Static;
 
 
+	//====================================================================
+	// Register a new Python object event handler with the event.
+	//====================================================================
+
 	internal bool AddEventHandler(IntPtr target, IntPtr handler) {
 	    Object obj = null;
 	    if (target != IntPtr.Zero) {
@@ -53,6 +57,9 @@
 	    Type type = this.info.EventHandlerType;
 	    Delegate d = DelegateManager.GetDelegate(type, handler);
 
+	    // Note that AddEventHandler helper only works for public events, 
+	    // so we have to get the underlying add method explicitly.
+
 	    object[] args = { d };
 	    MethodInfo mi = this.info.GetAddMethod(true);
 	    mi.Invoke(obj, BindingFlags.Default, null, args, null);
@@ -61,6 +68,10 @@
 	}
 
 
+	//====================================================================
+	// Remove the given Python object event handler.
+	//====================================================================
+
 	internal bool RemoveEventHandler(IntPtr target, IntPtr handler) {
 
 	    // Removing a Python event handler is potentially expensive if
@@ -114,8 +125,8 @@
 		return false;
   	    }
 
-	    // RemoveEventHandler doesn't work for non-public events.
-
+	    // Note that RemoveEventHandler only works for public events,
+	    // so we have to get the underlying remove method explicitly.
 
 	    object[] args = { found };
 	    MethodInfo mi = this.info.GetRemoveMethod(true);
@@ -125,6 +136,10 @@
 	}
 
 
+	//====================================================================
+	// Invoke the event and return the result as a Python object.
+	//====================================================================
+
 	internal IntPtr Invoke(IntPtr target, IntPtr args, IntPtr kw) {
 	    CLRObject co = ManagedType.GetManagedObject(target) as CLRObject;
 	    object obj = (co != null) ? co.inst: null;
@@ -168,6 +183,15 @@
 
 
 	//====================================================================
+	// Called by bindings to decide how to handle unbound event calls.
+	//====================================================================
+
+	internal bool IsStatic() {
+	    return fi.IsStatic;
+	}
+
+
+	//====================================================================
 	// Descriptor __get__ implementation. A getattr on an event returns
 	// a "bound" event that keeps a reference to the object instance,
 	// making events first-class Python objects similar to methods.
@@ -252,6 +276,7 @@
 	    }
 	    ExtensionType.FinalizeObject(self);
 	}
+
 
     }
 


=== PythonNet/src/runtime/ExtensionType.cs 1.3 => 1.4 ===
--- PythonNet/src/runtime/ExtensionType.cs:1.3	Wed Oct 22 22:53:10 2003
+++ PythonNet/src/runtime/ExtensionType.cs	Mon Oct 27 21:07:00 2003
@@ -32,6 +32,13 @@
 	    // particular concrete subclass with a hidden CLR gchandle.
 
 	    IntPtr tp = TypeManager.GetTypeHandle(this.GetType());
+
+//  	    int rc = (int)Marshal.ReadIntPtr(tp, TypeOffset.ob_refcnt);
+//  	    if (rc > 1050) {
+//  	    DebugUtil.Print("tp is: ", tp);
+//  	    DebugUtil.DumpType(tp);
+//  	    }
+
 	    IntPtr py = Runtime.PyType_GenericAlloc(tp, 0);
 
 	    GCHandle gc = GCHandle.Alloc(this);


=== PythonNet/src/runtime/MetaType.cs 1.7 => 1.8 ===
--- PythonNet/src/runtime/MetaType.cs:1.7	Wed Oct 22 22:53:10 2003
+++ PythonNet/src/runtime/MetaType.cs	Mon Oct 27 21:07:00 2003
@@ -89,7 +89,6 @@
 		}
 	    }
 
-
 	    IntPtr slots = Runtime.PyDict_GetItemString(dict, "__slots__");
 	    if (slots != IntPtr.Zero) {
 		Exceptions.SetError(Exceptions.TypeError, 
@@ -99,8 +98,51 @@
 
 	    }
 
+	    // hack for now... fix for 1.0
 	    return TypeManager.CreateSubType(args);
 
+	    // Now that we've done sanity checking to make sure that it is
+	    // appropriate to subclass the given class, 
+
+//  	    IntPtr func = Marshal.ReadIntPtr(Runtime.PyTypeType,
+//  					     TypeOffset.tp_new);
+//  	    IntPtr type = NativeCall.Call_3(func, tp, args, kw);
+//  	    if (type == IntPtr.Zero) {
+//  		return IntPtr.Zero;
+//  	    }
+
+//  	    int flags = TypeFlags.Default;
+//  	    flags |= TypeFlags.Managed;
+//  	    flags |= TypeFlags.HeapType;
+//  	    flags |= TypeFlags.BaseType;
+//  	    flags |= TypeFlags.Subclass;
+//  	    flags |= TypeFlags.HaveGC;
+//  	    Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags);
+
+//  	    TypeManager.CopySlot(base_type, type, TypeOffset.tp_dealloc);
+
+//  	    // for now, move up hidden handle...
+//  	    IntPtr gc = Marshal.ReadIntPtr(base_type, TypeOffset.magic());
+//  	    Marshal.WriteIntPtr(type, TypeOffset.magic(), gc);
+
+//  	    //DebugUtil.DumpType(base_type);
+//  	    //DebugUtil.DumpType(type);
+
+//  	    return type;
+	}
+
+
+	[CallConvCdecl()]
+	public static IntPtr tp_alloc(IntPtr mt, int n) {
+	    //Console.WriteLine("alloc: {0}", n);
+	    IntPtr type = Runtime.PyType_GenericAlloc(mt, n);
+	    return type;
+	}
+
+
+	[CallConvCdecl()]
+	public static void tp_free(IntPtr tp) {
+	    Runtime.PyObject_GC_Del(tp);
 	}
 
 
@@ -188,7 +230,6 @@
 
 	[CallConvCdecl()]
 	public static void tp_dealloc(IntPtr tp) {
-	    DebugUtil.Print("mt tp_dealloc: ", tp);
 
 	    // Fix this when we dont cheat on the handle for subclasses!
 
@@ -198,18 +239,21 @@
 		((GCHandle)gc).Free();
 	    }
 
-	    // Delegate the rest of finalization the Python metatype.
-	    IntPtr py_type = Runtime.PyTypeType;
-	    IntPtr op = Marshal.ReadIntPtr(py_type, TypeOffset.tp_dealloc);
-	    NativeCall.Void_Call_1(op, tp);
-	}
+	    IntPtr op = Marshal.ReadIntPtr(tp, TypeOffset.ob_type);
+	    Runtime.Decref(op);
 
+	    // Delegate the rest of finalization the Python metatype. Note
+	    // that the PyType_Type implementation of tp_dealloc will call
+	    // tp_free on the type of the type being deallocated - in this
+	    // case our CLR metatype. That is why we implement tp_free.
+
+	    op = Marshal.ReadIntPtr(Runtime.PyTypeType, TypeOffset.tp_dealloc);
+	    NativeCall.Void_Call_1(op, tp);
 
-	[CallConvCdecl()]
-	public static void tp_free(IntPtr tp) {
-	    Console.WriteLine("mt tp_free");
 	    return;
 	}
+
+
 
 
     }


=== PythonNet/src/runtime/MethodBinder.cs 1.6 => 1.7 ===
--- PythonNet/src/runtime/MethodBinder.cs:1.6	Wed Oct 22 22:53:10 2003
+++ PythonNet/src/runtime/MethodBinder.cs	Mon Oct 27 21:07:00 2003
@@ -24,18 +24,15 @@
 
     internal class MethodBinder {
 
-	// MethodInfo info;
 	public ArrayList list;
 	public MethodBase[] methods;
 	public bool init = false;
 
 	internal MethodBinder () {
-	    // this.info = null;
 	    this.list = new ArrayList();
 	}
 	
 	internal MethodBinder(MethodInfo mi) : base () {
-	    // this.info = null;
 	    this.list = new ArrayList();
 	    this.list.Add(mi);
 	}
@@ -45,22 +42,94 @@
 	}
 
 	internal void AddMethod(MethodBase m) {
-	    // if more than one, use complex ds, else use info
 	    this.list.Add(m);
 	}
 
-	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);
+	//====================================================================
+	// Return the array of MethodInfo for this method. The result array
+	// is arranged in order of precendence (done lazily to avoid doing it
+	// at all for methods that are never called).
+	//====================================================================
+
+	internal MethodBase[] GetMethods() {
 	    if (!init) {
+		// I'm sure this could be made more efficient.
+		list.Sort(new MethodSorter());
 		methods = (MethodBase[])list.ToArray(typeof(MethodBase));
 		init = true;
 	    }
+	    return methods;
+	}
+
+
+	//====================================================================
+	// Precedence algorithm largely lifted from jython - the concerns are
+	// generally the same so we'll start w/this and tweak as necessary.
+	//====================================================================
+
+	internal static int GetPrecedence(MethodBase mi) {
+	    ParameterInfo[] pi = mi.GetParameters();
+	    int num = pi.Length;
+	    int val = 0;
+
+	    for (int i = 0; i < num; i++) {
+		val += ArgPrecedence(pi[i].ParameterType);
+	    }
+
+	    return val;
+	}
+
+
+	//====================================================================
+	// Return a precedence value for a particular Type object.
+	//====================================================================
+
+	internal static int ArgPrecedence(Type t) {
+	    Type objectType = typeof(Object);
+	    if (t == objectType) return 3000;
+
+	    TypeCode tc = Type.GetTypeCode(t);
+	    if (tc == TypeCode.Object) return 1;
+	    if (tc == TypeCode.UInt64) return 10;
+	    if (tc == TypeCode.UInt32) return 11;
+	    if (tc == TypeCode.UInt16) return 12;
+	    if (tc == TypeCode.Int64) return 13;
+	    if (tc == TypeCode.Int32) return 14;
+	    if (tc == TypeCode.Int16) return 15;
+	    if (tc == TypeCode.Char) return 16;
+	    if (tc == TypeCode.SByte) return 17;
+	    if (tc == TypeCode.Byte) return 18;
+	    if (tc == TypeCode.Single) return 20;
+	    if (tc == TypeCode.Double) return 21;
+	    if (tc == TypeCode.String) return 30;
+	    if (tc == TypeCode.Boolean) return 40;
+
+	    if (t.IsArray) {
+		Type e = t.GetElementType();
+		if (e == objectType)
+		    return 2500;
+		return 100 + ArgPrecedence(e);
+	    }
+
+	    return 2000;
+	}
+
+
+	//====================================================================
+	// Bind the given Python instance and arguments to a particular method
+	// overload and return a structure that contains the converted Python
+	// instance, converted arguments and the correct method to call.
+	//====================================================================
+
+	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);
+
+	    MethodBase[] _methods = GetMethods();
 
-	    for (int i = 0; i < methods.Length; i++) {
-		MethodBase mi = methods[i];
+	    for (int i = 0; i < _methods.Length; i++) {
+		MethodBase mi = _methods[i];
 
 		ParameterInfo[] pi = mi.GetParameters();
 
@@ -135,6 +204,24 @@
 
 	    MethodInfo mi = (MethodInfo)binding.info;
 	    return Converter.ToPython(result, mi.ReturnType);
+	}
+
+    }
+
+
+
+    //========================================================================
+    // Utility class to sort method info by parameter type precedence.
+    //========================================================================
+
+    internal class MethodSorter : IComparer {
+
+	int IComparer.Compare(Object m1, Object m2) {
+	    int p1 = MethodBinder.GetPrecedence((MethodBase)m1);
+	    int p2 = MethodBinder.GetPrecedence((MethodBase)m2);
+	    if (p1 < p2) return -1;
+	    if (p1 > p2) return 1;
+	    return 0;
 	}
 
     }


=== PythonNet/src/runtime/MethodBinding.cs 1.2 => 1.3 ===
--- PythonNet/src/runtime/MethodBinding.cs:1.2	Tue Oct  7 22:29:17 2003
+++ PythonNet/src/runtime/MethodBinding.cs	Mon Oct 27 21:07:00 2003
@@ -30,6 +30,31 @@
 	    this.m = m;
 	}
 
+
+	//====================================================================
+	// MethodBinding __getattribute__ implementation. 
+	//====================================================================
+
+	[CallConvCdecl()]
+	public static IntPtr tp_getattro(IntPtr ob, IntPtr key) {
+	    MethodBinding self = (MethodBinding)GetManagedObject(ob);
+
+	    if (!Runtime.PyString_Check(key)) {
+		Exceptions.SetError(Exceptions.TypeError, "string expected");
+		return IntPtr.Zero;
+	    }
+
+	    string name = Runtime.GetManagedString(key);
+	    if (name == "__doc__") {
+		IntPtr doc = self.m.GetDocString();
+		Runtime.Incref(doc);
+		return doc;
+	    }
+
+	    return Runtime.PyObject_GenericGetAttr(ob, key);
+	}
+
+
 	//====================================================================
 	// MethodBinding  __call__ implementation.
 	//====================================================================
@@ -37,6 +62,28 @@
 	[CallConvCdecl()]
 	public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) {
 	    MethodBinding self = (MethodBinding)GetManagedObject(ob);
+
+	    // This supports calling a method 'unbound', passing the instance
+	    // as the first argument. Note that this is not supported if any
+	    // of the overloads are static since we can't know if the intent
+	    // was to call the static method or the unbound instance method.
+
+	    if ((self.target == IntPtr.Zero) && (!self.m.IsStatic())) {
+		if (Runtime.PyTuple_Size(args) < 1) {
+		    Exceptions.SetError(Exceptions.TypeError, 
+					"not enough arguments"
+					);
+		    return IntPtr.Zero;
+		}
+		int len = Runtime.PyTuple_Size(args);
+		IntPtr uargs = Runtime.PyTuple_GetSlice(args, 1, len);
+		IntPtr inst = Runtime.PyTuple_GetItem(args, 0);
+		Runtime.Incref(inst);
+		IntPtr r = self.m.Invoke(inst, uargs, kw);
+		Runtime.Decref(inst);
+		return r;
+	    }
+
 	    return self.m.Invoke(self.target, args, kw);
 	}
 


=== PythonNet/src/runtime/MethodObject.cs 1.3 => 1.4 ===
--- PythonNet/src/runtime/MethodObject.cs:1.3	Wed Oct 22 22:53:10 2003
+++ PythonNet/src/runtime/MethodObject.cs	Mon Oct 27 21:07:00 2003
@@ -23,8 +23,9 @@
 
 	internal MethodInfo[] info;
 	internal string name;
-	MethodBinding unbound;
-	MethodBinder binder;
+	internal MethodBinding unbound;
+	internal MethodBinder binder;
+	internal IntPtr doc;
 
 	public MethodObject(string name, MethodInfo[] info) : base() {
 	    this.name = name;
@@ -35,10 +36,79 @@
 	    }
 	}
 
+
 	public virtual IntPtr Invoke(IntPtr target, IntPtr args, IntPtr kw) {
 	    return binder.Invoke(target, args, kw);
 	}
 
+
+	//====================================================================
+	// Helper to get docstrings from reflected method / param info.
+	//====================================================================
+
+	internal IntPtr GetDocString() {
+	    if (doc != IntPtr.Zero) {
+		return doc;
+	    }
+	    MethodBase[] methods = binder.GetMethods();
+	    string str = "";
+	    for (int i = 0; i < methods.Length; i++) {
+		if (str.Length > 0)
+		    str += Environment.NewLine;
+		str += methods[i].ToString();
+	    }
+	    doc = Runtime.PyString_FromString(str);
+	    return doc;
+	}
+
+
+	//====================================================================
+	// This is a little tricky: a class can actually have a static method
+	// and instance methods all with the same name. That makes it tough
+	// to support calling a method 'unbound' (passing the instance as the
+	// first argument), because in this case we can't know whether to call
+	// the instance method unbound or call the static method. 
+	//
+	// The rule we is that if there are both instance and static methods
+	// with the same name, then we always call the static method. So this
+	// method returns true if any of the methods that are represented by 
+	// the descriptor are static methods (called by MethodBinding).
+	//====================================================================
+
+	internal bool IsStatic() {
+	    MethodBase[] methods = binder.GetMethods();
+	    for (int i = 0; i < methods.Length; i++) {
+		if (methods[i].IsStatic)
+		    return true;
+	    }
+	    return false;
+	}
+
+
+	//====================================================================
+	// Descriptor __getattribute__ implementation. 
+	//====================================================================
+
+	[CallConvCdecl()]
+	public static IntPtr tp_getattro(IntPtr ob, IntPtr key) {
+	    MethodObject self = (MethodObject)GetManagedObject(ob);
+
+	    if (!Runtime.PyString_Check(key)) {
+		Exceptions.SetError(Exceptions.TypeError, "string expected");
+		return IntPtr.Zero;
+	    }
+
+	    string name = Runtime.GetManagedString(key);
+	    if (name == "__doc__") {
+		IntPtr doc = self.GetDocString();
+		Runtime.Incref(doc);
+		return doc;
+	    }
+
+	    return Runtime.PyObject_GenericGetAttr(ob, key);
+	}
+
+
 	//====================================================================
 	// Descriptor __get__ implementation. Accessing a CLR method returns
 	// a "bound" method similar to a Python bound method. 
@@ -89,6 +159,7 @@
 	[CallConvCdecl()]
 	public static new void tp_dealloc(IntPtr ob) {
 	    MethodObject self = (MethodObject)GetManagedObject(ob);
+	    Runtime.Decref(self.doc);
 	    if (self.unbound != null) {
 		Runtime.Decref(self.unbound.pyHandle);
 	    }


=== PythonNet/src/runtime/Python.cs 1.3 => 1.4 ===
--- PythonNet/src/runtime/Python.cs:1.3	Wed Oct 22 22:53:10 2003
+++ PythonNet/src/runtime/Python.cs	Mon Oct 27 21:07:00 2003
@@ -18,8 +18,7 @@
 namespace Python.Runtime {
 
     /// <summary>
-    /// This class represents the public interface of the Python runtime.
-    /// 
+    /// This class provides the public interface of the Python runtime.
     /// </summary>
 
     public class PythonEngine {


=== PythonNet/src/runtime/TypeManager.cs 1.9 => 1.10 ===
--- PythonNet/src/runtime/TypeManager.cs:1.9	Wed Oct 22 22:53:10 2003
+++ PythonNet/src/runtime/TypeManager.cs	Mon Oct 27 21:07:00 2003
@@ -87,7 +87,6 @@
 	internal static IntPtr CreateType(Type impl) {
 
 	    IntPtr type = AllocateTypeObject(impl.Name);
-	    IntPtr py_type = Runtime.PyTypeType;
 
 	    // Set tp_basicsize to the size of our managed instance objects.
 	    Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)obSize);
@@ -97,16 +96,14 @@
 
 	    InitializeSlots(type, impl);
 
-	    int flags = TypeFlags.Default;
-	    flags |= TypeFlags.Managed;
-	    flags |= TypeFlags.HeapType;
-	    flags |= TypeFlags.HaveGC;
+	    int flags = TypeFlags.Default | TypeFlags.Managed |
+		        TypeFlags.HeapType | TypeFlags.HaveGC;
 	    Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags);
 
 	    Runtime.PyType_Ready(type);
 
 	    IntPtr dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict);
-	    IntPtr mod = Runtime.PyString_FromString("(clr)");
+	    IntPtr mod = Runtime.PyString_FromString("CLR");
 	    Runtime.PyDict_SetItemString(dict, "__module__", mod);
 
 	    InitMethods(type, impl);
@@ -201,15 +198,12 @@
 	    IntPtr offset = (IntPtr)ObjectOffset.ob_dict;
 	    Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset);
 
+	    IntPtr dc = Runtime.PyDict_Copy(dict);
+	    Marshal.WriteIntPtr(type, TypeOffset.tp_dict, dc);
+
 	    Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_);
 	    Runtime.Incref(base_);
 
-	    //Marshal.WriteIntPtr(type, TypeOffset.tp_bases, bases);
-	    //Runtime.Incref(bases);
-
-	    dict = Runtime.PyDict_Copy(dict);
-	    Marshal.WriteIntPtr(type, TypeOffset.tp_dict, dict);
-
 	    int flags = TypeFlags.Default;
 	    flags |= TypeFlags.Managed;
 	    flags |= TypeFlags.HeapType;
@@ -224,9 +218,10 @@
 
 	    Runtime.PyType_Ready(type);
 
-	    dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict);
-	    IntPtr mod = Runtime.PyString_FromString("<clr>");
-	    Runtime.PyDict_SetItemString(dict, "__module__", mod);
+
+	    IntPtr tp_dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict);
+	    IntPtr mod = Runtime.PyString_FromString("CLR");
+	    Runtime.PyDict_SetItemString(tp_dict, "__module__", mod);
 
 	    // for now, move up hidden handle...
 	    IntPtr gc = Marshal.ReadIntPtr(base_, TypeOffset.magic());
@@ -253,7 +248,7 @@
 	    // Copy gc and other type slots from the base Python metatype.
 
 	    CopySlot(py_type, type, TypeOffset.tp_basicsize);
-	    Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, (IntPtr)0);
+	    CopySlot(py_type, type, TypeOffset.tp_itemsize);
 
 	    CopySlot(py_type, type, TypeOffset.tp_dictoffset);
 	    CopySlot(py_type, type, TypeOffset.tp_weaklistoffset);
@@ -261,9 +256,6 @@
 	    CopySlot(py_type, type, TypeOffset.tp_traverse);
 	    CopySlot(py_type, type, TypeOffset.tp_clear);
 	    CopySlot(py_type, type, TypeOffset.tp_is_gc);
-	    //CopySlot(py_type, type, TypeOffset.tp_repr);
-
-	    //CopySlot(py_type, type, TypeOffset.tp_free);
 
 	    // Override type slots with those of the managed implementation.
 
@@ -301,8 +293,8 @@
 	    IntPtr temp = Runtime.PyString_FromString(name);
 	    IntPtr raw = Runtime.PyString_AS_STRING(temp);
 
-	    Marshal.WriteIntPtr(type, TypeOffset.tp_name, temp);
-	    Marshal.WriteIntPtr(type, TypeOffset.name, raw);
+	    Marshal.WriteIntPtr(type, TypeOffset.tp_name, raw);
+	    Marshal.WriteIntPtr(type, TypeOffset.name, temp);
 
 	    temp = Runtime.PyString_FromString(name);
 	    Marshal.WriteIntPtr(type, TypeOffset.name, temp);




More information about the Zope-CVS mailing list