[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