[Zope-CVS] CVS: PythonNet/src/runtime - AssemblyManager.cs:1.3 EventBinding.cs:1.6 EventObject.cs:1.7 PropertyObject.cs:1.4

Brian Lloyd cvs-admin at zope.org
Wed Nov 5 22:35:41 EST 2003


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

Modified Files:
	AssemblyManager.cs EventBinding.cs EventObject.cs 
	PropertyObject.cs 
Log Message:
Fixed event support; added keyfile to buildout; fixed exception obsfucation 
in property accessors.


=== PythonNet/src/runtime/AssemblyManager.cs 1.2 => 1.3 ===
--- PythonNet/src/runtime/AssemblyManager.cs:1.2	Tue Aug 12 17:27:16 2003
+++ PythonNet/src/runtime/AssemblyManager.cs	Wed Nov  5 22:35:10 2003
@@ -10,6 +10,7 @@
 // FOR A PARTICULAR PURPOSE.
 
 using System;
+using System.IO;
 using System.Collections;
 using System.Reflection;
 using System.Reflection.Emit;
@@ -25,7 +26,7 @@
     internal class AssemblyManager {
 
 	static Hashtable namespaces;
-	static ArrayList assemblies;
+	static ArrayList assemblies;	
 	static Hashtable probed;
 
 	private AssemblyManager() {}
@@ -39,6 +40,10 @@
 	    domain.AssemblyLoad += new AssemblyLoadEventHandler(
 				       AssemblyLoadHandler
 				       );
+
+//  	    domain.AssemblyResolve += new ResolveEventHandler(
+//  				          ResolveHandler
+//  					  );
 	
 	    Assembly[] items = domain.GetAssemblies();
 	    for (int i = 0; i < items.Length; i++) {
@@ -48,6 +53,7 @@
 	    }
 	}
 
+
 	//===================================================================
 	// Event handler for assembly load events. At the time the Python 
 	// runtime loads, we scan the app domain to map the assemblies that
@@ -62,22 +68,70 @@
 	    ScanAssembly(assembly);
 	}
 
+
+	//===================================================================
+	// Event handler for assembly resolve events. This is needed because
+	// we augment the assembly search path with the PYTHONPATH when we
+	// load an assembly from Python. Because of that, we need to listen
+	// for failed loads, because they might be dependencies of something
+	// we loaded from Python which also needs to be found on PYTHONPATH.
+	//===================================================================
+
+	static Assembly ResolveHandler(Object ob, ResolveEventArgs args){
+	    string name = args.Name.ToLower();
+
+	    for (int i = 0; i < assemblies.Count; i++) {
+		Assembly a = (Assembly)assemblies[i];
+		string full = a.FullName.ToLower();
+		if (full.StartsWith(name)) {
+		    return a;
+		}
+	    }
+
+	    return LoadAssembly(name);
+	}
+
+
+	//===================================================================
+	// Given an assembly name, try to find this assembly file using the
+	// PYTHONPATH. If not found, return null to indicate implicit load
+	// using standard load semantics (app base directory then GAC, etc.)
+	//===================================================================
+
+	internal string FindAssembly(string name) {
+	    // TODO: finish
+	    char sep = Path.DirectorySeparatorChar;
+	    string path = name;
+	    string[] list = {};
+	    
+	    int count = list.Length;
+	    for (int i = 0; i < count; i++) {
+		string temp = list[i] + sep + name;
+		if (File.Exists(temp)) {
+		    return temp;
+		}
+	    }
+
+	    return null;
+	}
+
+
 	//===================================================================
 	// Loads an assembly from the application directory or the GAC
-	// given a simple assembly name. Returns true if an assembly was 
-	// loaded, false if the assembly was not found or already loaded.
+	// given a simple assembly name. Returns the assembly if loaded.
 	//===================================================================
 
-	public static bool LoadAssembly(string name) {
+	public static Assembly LoadAssembly(string name) {
 	    Assembly assembly = null;
 	    try {
 		assembly = Assembly.LoadWithPartialName(name);
 	    }
 	    catch {
 	    }
-	    return (assembly != null);
+	    return assembly;
 	}
 
+
 	//===================================================================
 	// Given a qualified name of the form A.B.C.D, attempt to load 
 	// an assembly named after each of A.B.C.D, A.B.C, A.B, A. This
@@ -92,7 +146,7 @@
 	    for (int i = 0; i < names.Length; i++) {
 		s = (i == 0) ? names[0] : s + "." + names[i];
 		if (probed[s] == null) {
-		    if (LoadAssembly(s)) {
+		    if (LoadAssembly(s) != null) {
 			loaded = true;
 		    }
 		    probed[s] = 1;
@@ -101,6 +155,7 @@
 	    return loaded;
 	}
 
+
 	//===================================================================
 	// Scans an assembly for exported namespaces, adding them to the
 	// mapping of valid namespaces. Note that for a given namespace
@@ -135,6 +190,7 @@
 	    }
 	}
 
+
 	//===================================================================
 	// Returns true if the given qualified name matches a namespace
 	// exported by an assembly loaded in the current app domain.
@@ -143,6 +199,7 @@
 	public static bool IsValidNamespace(string name) {
 	    return namespaces.ContainsKey(name);
 	}
+
 
 	//===================================================================
 	// Returns the System.Type object for a given qualified name,


=== PythonNet/src/runtime/EventBinding.cs 1.5 => 1.6 ===
--- PythonNet/src/runtime/EventBinding.cs:1.5	Mon Oct 27 21:07:00 2003
+++ PythonNet/src/runtime/EventBinding.cs	Wed Nov  5 22:35:10 2003
@@ -63,7 +63,7 @@
 
 	    if (Runtime.PyCallable_Check(arg) < 1) {
 		Exceptions.SetError(Exceptions.TypeError, 
-				    "event handlers must be callable"
+				    "invalid event handler"
 				    );
 		return IntPtr.Zero;
 	    }
@@ -74,48 +74,6 @@
 
 	    Runtime.Incref(self.pyHandle);
 	    return self.pyHandle;
-	}
-
-
-	//====================================================================
-	// EventBinding __nonzero__ implementation.
-	//====================================================================
-
-	[CallConvCdecl()]
-	public static int nb_nonzero(IntPtr ob) {
-	    EventBinding self = (EventBinding)GetManagedObject(ob);
-	    return self.e.IsNonEmpty(self.target);
-	}
-
-
-	//====================================================================
-	// EventBinding __call__ implementation.
-	//====================================================================
-
-	[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.6 => 1.7 ===
--- PythonNet/src/runtime/EventObject.cs:1.6	Mon Oct 27 21:07:00 2003
+++ PythonNet/src/runtime/EventObject.cs	Wed Nov  5 22:35:10 2003
@@ -24,20 +24,13 @@
 	internal string name;
 	internal EventBinding unbound;
 	internal EventInfo info;
-	internal FieldInfo fi;
+	internal Hashtable reg;
 
 	public EventObject(EventInfo info) : base() {
-	    Type t = info.DeclaringType;
-	    this.fi = t.GetField(info.Name, flags);
 	    this.name = info.Name;
 	    this.info = info;
 	}
 
-	static BindingFlags flags = BindingFlags.Public | 
-                                    BindingFlags.NonPublic |
-		                    BindingFlags.Instance |
-		                    BindingFlags.Static;
-
 
 	//====================================================================
 	// Register a new Python object event handler with the event.
@@ -57,6 +50,22 @@
 	    Type type = this.info.EventHandlerType;
 	    Delegate d = DelegateManager.GetDelegate(type, handler);
 
+	    // Now register the handler in a mapping from instance to pairs
+	    // of (handler hash, delegate) so we can lookup to remove later.
+	    // All this is done lazily to avoid overhead until an event is 
+	    // actually subscribed to by a Python event handler.
+
+	    if (reg == null) {
+		reg = new Hashtable();
+	    }
+	    object key = (obj != null) ? obj : this.info.ReflectedType;
+	    ArrayList list = reg[key] as ArrayList;
+	    if (list == null) {
+		list = new ArrayList();
+		reg[key] = list;
+	    }
+	    list.Add(new Handler(Runtime.PyObject_Hash(handler), d));
+
 	    // Note that AddEventHandler helper only works for public events, 
 	    // so we have to get the underlying add method explicitly.
 
@@ -73,128 +82,59 @@
 	//====================================================================
 
 	internal bool RemoveEventHandler(IntPtr target, IntPtr handler) {
-
-	    // Removing a Python event handler is potentially expensive if
-	    // the event has a lot of registered handlers. This is because
-	    // we need to sniff each of the registered handlers to see if
-	    // it is a wrapper for a Python delegate. In practice this is
-	    // probably not really an issue - handlers are rarely removed.
-
 	    Object obj = null;
-	    Delegate d = null;
-
 	    if (target != IntPtr.Zero) {
 		CLRObject co = (CLRObject)ManagedType.GetManagedObject(target);
 		obj = co.inst;
 	    }
 
 	    IntPtr hash = Runtime.PyObject_Hash(handler);
-	    if (Exceptions.ErrorOccurred()) {
+	    if (Exceptions.ErrorOccurred() || (reg == null)) {
 		Exceptions.SetError(Exceptions.ValueError, 
 				    "unknown event handler"
 				    ); 
 		return false;
 	    }
 
-	    d = this.fi.GetValue(obj) as Delegate;
+	    object key = (obj != null) ? obj : this.info.ReflectedType;
+	    ArrayList list = reg[key] as ArrayList;
 
-  	    if (d == null) {
+	    if (list == null) {
 		Exceptions.SetError(Exceptions.ValueError, 
 				    "unknown event handler"
 				    ); 
 		return false;
-  	    }
-
-	    Delegate[] list = d.GetInvocationList();
-	    Delegate found = null;
-
-	    for (int i=0; i < list.Length; i++) {
-		IntPtr py = DelegateManager.GetPythonHandle(list[i]);
-		if (hash == Runtime.PyObject_Hash(py)) {
-		    found = list[i];
-		    break;
-		}
 	    }
 
-	    Exceptions.Clear();
-
-  	    if (found == null) {
-		Exceptions.SetError(Exceptions.ValueError, 
-				    "unknown event handler"
-				    ); 
-		return false;
-  	    }
-
-	    // Note that RemoveEventHandler only works for public events,
-	    // so we have to get the underlying remove method explicitly.
-
-	    object[] args = { found };
+	    object[] args = { null };
 	    MethodInfo mi = this.info.GetRemoveMethod(true);
-	    mi.Invoke(obj, BindingFlags.Default, null, args, null);
-
-	    return true;
-	}
-
-
-	//====================================================================
-	// 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;
-
-	    Delegate d = this.fi.GetValue(obj) as Delegate;
 
-  	    if (d == null) {
-  		IntPtr r = Runtime.PyNone;
-  		Runtime.Incref(r);
-  		return r;
-  	    }
-
-	    MethodInfo method = d.GetType().GetMethod("Invoke", flags);
-	    IntPtr wrapped = CLRObject.GetInstHandle(d);
-
-  	    MethodBinder binder = new MethodBinder(method);
- 	    IntPtr op = binder.Invoke(wrapped, args, kw);
-	    Runtime.Decref(wrapped);
-
-	    return op;
-	}
-
-
-	//====================================================================
-	// Helper to support truth testing on event descriptors in Python.
-	// The standard if(event != null) idiom does not work for Python,
-	// because events never appear to be null / None - the descriptor
-	// always exists even if the actual event (delegate) is null. To
-	// provide help for Python, event descriptors support __nonzero__
-	// so that the Python can use 'if event:' to test events.
-	//====================================================================
-
-	internal int IsNonEmpty(IntPtr target) {
-	    CLRObject co = ManagedType.GetManagedObject(target) as CLRObject;
-	    object obj = (co != null) ? co.inst: null;
-	    Type type = info.DeclaringType;
-	    FieldInfo fi = type.GetField(name, flags);
-	    Delegate d = fi.GetValue(obj) as Delegate;
-	    return (d == null) ? 0 : 1;
-	}
-
-
-	//====================================================================
-	// Called by bindings to decide how to handle unbound event calls.
-	//====================================================================
+	    for (int i = 0; i < list.Count; i++) {
+		Handler item = (Handler)list[i];
+		if (item.hash != hash) {
+		    continue;
+		}
+		args[0] = item.del;
+		try {
+		    mi.Invoke(obj, BindingFlags.Default, null, args, null);
+		}
+		catch {
+		    continue;
+		}
+		list.RemoveAt(i);
+		return true;
+	    }
 
-	internal bool IsStatic() {
-	    return fi.IsStatic;
+	    Exceptions.SetError(Exceptions.ValueError, 
+				"unknown event handler"
+				); 
+	    return false;
 	}
 
 
 	//====================================================================
 	// 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.
+	// a "bound" event that keeps a reference to the object instance.
 	//====================================================================
 
 	[CallConvCdecl()]
@@ -277,6 +217,20 @@
 	    ExtensionType.FinalizeObject(self);
 	}
 
+
+    }
+
+
+
+    internal class Handler {
+
+	public IntPtr hash;
+	public Delegate del;
+
+	public Handler(IntPtr hash, Delegate d) {
+	    this.hash = hash;
+	    this.del = d;
+	}
 
     }
 


=== PythonNet/src/runtime/PropertyObject.cs 1.3 => 1.4 ===
--- PythonNet/src/runtime/PropertyObject.cs:1.3	Mon Oct 20 23:05:14 2003
+++ PythonNet/src/runtime/PropertyObject.cs	Wed Nov  5 22:35:10 2003
@@ -69,31 +69,32 @@
 			       );
 		    return IntPtr.Zero;
 		}
-		//ts = PythonEngine.BeginAllowThreads();
+
 		try {
 		    result = self.info.GetValue(null, null);
-		    //  PythonEngine.EndAllowThreads(ts);
 		    return Converter.ToPython(result, self.info.PropertyType);
 		}
 		catch(Exception e) {
-		    // PythonEngine.EndAllowThreads(ts);
 		    Exceptions.SetError(Exceptions.TypeError, e.Message);
 		    return IntPtr.Zero;
 		}
 	    }
 
+	    CLRObject co = GetManagedObject(ob) as CLRObject;
+	    if (co == null) {
+		Exceptions.SetError(Exceptions.TypeError, "invalid target"); 
+		return IntPtr.Zero;
+	    }
+
 	    try {
-	        CLRObject co = (CLRObject)GetManagedObject(ob);
-		//ts = PythonEngine.BeginAllowThreads();
 		result = self.info.GetValue(co.inst, null);
-		// PythonEngine.EndAllowThreads(ts);
 		return Converter.ToPython(result, self.info.PropertyType);
 	    }
 	    catch(Exception e) {
-		//if (ts != IntPtr.Zero) {
-		//    PythonEngine.EndAllowThreads(ts);
-		//}
-		Exceptions.SetError(Exceptions.TypeError, e.Message);
+		if (e.InnerException != null) {
+		    e = e.InnerException;
+		}
+		Exceptions.SetError(e);
 		return IntPtr.Zero;
 	    }
 	}
@@ -150,23 +151,24 @@
 
 	    try {
 		if (!is_static) {
-		    CLRObject co = (CLRObject)GetManagedObject(ob);
-		    //ts = PythonEngine.BeginAllowThreads();
+		    CLRObject co = GetManagedObject(ob) as CLRObject;
+		    if (co == null) {
+			Exceptions.SetError(Exceptions.TypeError, 
+					    "invalid target"); 
+			return -1;
+		    }
 		    self.info.SetValue(co.inst, newval, null);
-		    //PythonEngine.EndAllowThreads(ts);
 		}
 		else {
-		    //ts = PythonEngine.BeginAllowThreads();
 		    self.info.SetValue(null, newval, null);		    
-		    //PythonEngine.EndAllowThreads(ts);
 		}
 		return 0;
 	    }
 	    catch(Exception e) {
-		//if (ts != IntPtr.Zero) {
-		//    PythonEngine.EndAllowThreads(ts);
-		//}
-		Exceptions.SetError(Exceptions.TypeError, e.Message);
+		if (e.InnerException != null) {
+		    e = e.InnerException;
+		}
+		Exceptions.SetError(e);
 		return -1;
 	    }
 




More information about the Zope-CVS mailing list