[Zope-CVS] CVS: PythonNet/src/runtime - AssemblyManager.cs:1.4 ClassObject.cs:1.10 ConstructorBinder.cs:1.5 Exceptions.cs:1.7 ImportHook.cs:1.7 PropertyObject.cs:1.5 Python.cs:1.5 Runtime.cs:1.13

Brian Lloyd cvs-admin at zope.org
Thu Nov 6 23:05:36 EST 2003


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

Modified Files:
	AssemblyManager.cs ClassObject.cs ConstructorBinder.cs 
	Exceptions.cs ImportHook.cs PropertyObject.cs Python.cs 
	Runtime.cs 
Log Message:
Add assembly load from python path; fix bug in constructors; added some 
better finalization on shutdown.


=== PythonNet/src/runtime/AssemblyManager.cs 1.3 => 1.4 ===
--- PythonNet/src/runtime/AssemblyManager.cs:1.3	Wed Nov  5 22:35:10 2003
+++ PythonNet/src/runtime/AssemblyManager.cs	Thu Nov  6 23:05:05 2003
@@ -25,26 +25,33 @@
 
     internal class AssemblyManager {
 
+	static AssemblyLoadEventHandler lh;
+	static ResolveEventHandler rh;
 	static Hashtable namespaces;
 	static ArrayList assemblies;	
 	static Hashtable probed;
+	static int last;
 
 	private AssemblyManager() {}
 
-	static AssemblyManager() {
+	//===================================================================
+	// Initialization performed on startup of the Python runtime.
+	//===================================================================
+
+	internal static void Initialize() {
+
 	    namespaces = new Hashtable();
 	    assemblies = new ArrayList();
 	    probed = new Hashtable();
 
 	    AppDomain domain = AppDomain.CurrentDomain;
-	    domain.AssemblyLoad += new AssemblyLoadEventHandler(
-				       AssemblyLoadHandler
-				       );
-
-//  	    domain.AssemblyResolve += new ResolveEventHandler(
-//  				          ResolveHandler
-//  					  );
-	
+
+	    lh = new AssemblyLoadEventHandler(AssemblyLoadHandler);
+	    domain.AssemblyLoad += lh;
+
+	    rh = new ResolveEventHandler(ResolveHandler);	
+	    domain.AssemblyResolve += rh;
+
 	    Assembly[] items = domain.GetAssemblies();
 	    for (int i = 0; i < items.Length; i++) {
 		Assembly a = items[i];
@@ -55,6 +62,17 @@
 
 
 	//===================================================================
+	// Cleanup resources upon shutdown of the Python runtime.
+	//===================================================================
+
+	internal static void Finalize() {
+	    AppDomain domain = AppDomain.CurrentDomain;
+	    domain.AssemblyLoad -= lh;
+	    domain.AssemblyResolve -= rh;
+	}
+
+
+	//===================================================================
 	// Event handler for assembly load events. At the time the Python 
 	// runtime loads, we scan the app domain to map the assemblies that
 	// are loaded at the time. We also have to register this event handler
@@ -79,7 +97,6 @@
 
 	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();
@@ -87,8 +104,11 @@
 		    return a;
 		}
 	    }
-
-	    return LoadAssembly(name);
+	    IntPtr ts = PythonEngine.EnsureThread();
+	    IntPtr cs = Runtime.PyThreadState_Swap(ts);
+	    Assembly ao = LoadAssemblyPath(args.Name);
+	    Runtime.PyThreadState_Swap(cs);
+	    return ao;
 	}
 
 
@@ -98,20 +118,24 @@
 	// using standard load semantics (app base directory then GAC, etc.)
 	//===================================================================
 
-	internal string FindAssembly(string name) {
-	    // TODO: finish
+	static string FindAssembly(string name) {
+	    IntPtr list = Runtime.PySys_GetObject("path");
+	    int count = Runtime.PyList_Size(list);
 	    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;
+		IntPtr item = Runtime.PyList_GetItem(list, i);
+		string head = Runtime.GetManagedString(item);
+		string path = head + sep + name;
+		string temp = path + ".dll";
+		if (File.Exists(temp)) {
+		    return temp;
+		}
+		temp = path + ".exe";
 		if (File.Exists(temp)) {
 		    return temp;
 		}
 	    }
-
 	    return null;
 	}
 
@@ -133,6 +157,21 @@
 
 
 	//===================================================================
+	// Loads an assembly using an augmented search path (the python path).
+	//===================================================================
+
+	public static Assembly LoadAssemblyPath(string name) {
+	    string path = FindAssembly(name);
+	    Assembly assembly = null;
+	    if (path != null) {
+		try   { assembly = Assembly.LoadFrom(path); }
+		catch {}
+	    }
+	    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
 	// will only actually probe for the assembly once for each unique
@@ -140,13 +179,26 @@
 	//===================================================================
 
 	public static bool LoadImplicit(string name) {
+	    // We'd like to cache misses to improve import speed, but we also
+	    // want to be able to have an import fail and then succeed later
+	    // after adding something to sys.path. This lets us do both :)
+	    IntPtr list = Runtime.PySys_GetObject("path");
+	    int count = Runtime.PyList_Size(list);
+	    if (count != last) {
+		last = count;
+		probed.Clear();
+	    }
+
 	    string[] names = name.Split('.');
 	    bool loaded = false;
 	    string s = "";
 	    for (int i = 0; i < names.Length; i++) {
 		s = (i == 0) ? names[0] : s + "." + names[i];
 		if (probed[s] == null) {
-		    if (LoadAssembly(s) != null) {
+		    if (LoadAssemblyPath(s) != null){
+			loaded = true;
+		    }
+		    else if (LoadAssembly(s) != null) {
 			loaded = true;
 		    }
 		    probed[s] = 1;


=== PythonNet/src/runtime/ClassObject.cs 1.9 => 1.10 ===
--- PythonNet/src/runtime/ClassObject.cs:1.9	Mon Oct 27 21:07:00 2003
+++ PythonNet/src/runtime/ClassObject.cs	Thu Nov  6 23:05:05 2003
@@ -92,10 +92,8 @@
 	    }
 
 	    Object obj = self.binder.InvokeRaw(IntPtr.Zero, args, kw);
-
 	    if (obj == null) {
-		Runtime.Incref(Runtime.PyNone);
-		return Runtime.PyNone;
+		return IntPtr.Zero;
 	    }
 
 	    return CLRObject.GetInstHandle(obj, tp);


=== PythonNet/src/runtime/ConstructorBinder.cs 1.4 => 1.5 ===
--- PythonNet/src/runtime/ConstructorBinder.cs:1.4	Mon Oct 27 21:07:00 2003
+++ PythonNet/src/runtime/ConstructorBinder.cs	Thu Nov  6 23:05:05 2003
@@ -43,7 +43,7 @@
 		Exceptions.SetError(Exceptions.TypeError, 
 				    "no constructor matches given arguments"
 				    );
-		return IntPtr.Zero;
+		return null;
 	    }
 
 	    // Object construction is presumed to be non-blocking and fast
@@ -58,7 +58,7 @@
 		    e = e.InnerException;
 		}
 		Exceptions.SetError(e);
-		return IntPtr.Zero;
+		return null;
 	    }
 
 	    return result;


=== PythonNet/src/runtime/Exceptions.cs 1.6 => 1.7 ===
--- PythonNet/src/runtime/Exceptions.cs:1.6	Wed Oct 22 22:53:10 2003
+++ PythonNet/src/runtime/Exceptions.cs	Thu Nov  6 23:05:05 2003
@@ -22,26 +22,38 @@
 
 	private Exceptions() {}
 
-	// This is called when the Python runtime is intitialized. It 
-	// uses reflection to populate static fields that expose handles
-	// to the standard Python exception types.
+	//===================================================================
+	// Initialization performed on startup of the Python runtime.
+	//===================================================================
 
 	internal static void Initialize() {
 	    IntPtr module = Runtime.PyImport_ImportModule("exceptions");
 	    Type type = typeof(Exceptions);
-
 	    foreach (FieldInfo fi in type.GetFields(BindingFlags.Public | 
 						    BindingFlags.Static)) {
 		IntPtr op = Runtime.PyObject_GetAttrString(module, fi.Name);
 		if (op != IntPtr.Zero) {
-
-		    // Note we own a reference to each exception class.
 		    fi.SetValue(type, op);
 		}
 	    }
 	    Runtime.Decref(module);
 	    Runtime.PyErr_Clear();
 	}
+
+
+	//===================================================================
+	// Cleanup resources upon shutdown of the Python runtime.
+	//===================================================================
+
+	internal static void Finalize() {
+	    Type type = typeof(Exceptions);
+	    foreach (FieldInfo fi in type.GetFields(BindingFlags.Public | 
+						    BindingFlags.Static)) {
+		IntPtr op = (IntPtr)fi.GetValue(type);
+		Runtime.Decref(op);
+	    }
+	}
+
 
 	/// <summary>
 	/// GetException Method


=== PythonNet/src/runtime/ImportHook.cs 1.6 => 1.7 ===
--- PythonNet/src/runtime/ImportHook.cs:1.6	Wed Oct 22 22:53:10 2003
+++ PythonNet/src/runtime/ImportHook.cs	Thu Nov  6 23:05:05 2003
@@ -24,7 +24,11 @@
 	static ModuleObject root;
 	static StaticMethodWrapper hook;
 
-	public static void Initialize() {
+	//===================================================================
+	// Initialization performed on startup of the Python runtime.
+	//===================================================================
+
+	internal static void Initialize() {
 
 	    // Initialize the Python <--> CLR module hook. We replace the
 	    // built-in Python __import__ with our own. This isn't ideal, 
@@ -48,6 +52,20 @@
 	}
 
 
+	//===================================================================
+	// Cleanup resources upon shutdown of the Python runtime.
+	//===================================================================
+
+	internal static void Finalize() {
+	    Runtime.Decref(root.pyHandle);
+	    Runtime.Decref(py_import);
+	}
+
+
+	//===================================================================
+	// The actual import hook that ties Python to the managed world.
+	//===================================================================
+
 	[CallConvCdecl()]
 	public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) {
 
@@ -114,7 +132,7 @@
 	    // to make sure that each of the steps in the qualified name
 	    // is recognized as a valid namespace. Otherwise the import
 	    // process can encounter unknown namespaces before it gets to
-	    // load the assembly that would them valid.
+	    // load the assembly that would make them valid.
 
 	    if (mod_name.StartsWith("CLR.")) {
 		string real_name = mod_name.Substring(4);


=== PythonNet/src/runtime/PropertyObject.cs 1.4 => 1.5 ===
--- PythonNet/src/runtime/PropertyObject.cs:1.4	Wed Nov  5 22:35:10 2003
+++ PythonNet/src/runtime/PropertyObject.cs	Thu Nov  6 23:05:05 2003
@@ -33,6 +33,7 @@
 	    info = md;
 	}
 
+
 	//====================================================================
 	// Descriptor __get__ implementation. This method returns the 
 	// value of the property on the given object. The returned value
@@ -98,6 +99,7 @@
 		return IntPtr.Zero;
 	    }
 	}
+
 
 	//====================================================================
 	// Descriptor __set__ implementation. This method sets the value of


=== PythonNet/src/runtime/Python.cs 1.4 => 1.5 ===
--- PythonNet/src/runtime/Python.cs:1.4	Mon Oct 27 21:07:00 2003
+++ PythonNet/src/runtime/Python.cs	Thu Nov  6 23:05:05 2003
@@ -70,7 +70,7 @@
 
 	public static void Finalize() {
 	    if (initialized) {
-		Runtime.Py_Finalize();
+		Runtime.Finalize();
 		initialized = false;
 	    }
 	}


=== PythonNet/src/runtime/Runtime.cs 1.12 => 1.13 ===
--- PythonNet/src/runtime/Runtime.cs:1.12	Mon Oct 27 23:00:45 2003
+++ PythonNet/src/runtime/Runtime.cs	Thu Nov  6 23:05:05 2003
@@ -98,6 +98,8 @@
 
 	    Error = new IntPtr(-1);
 
+	    AssemblyManager.Initialize();
+
 	    PyCLRMetaType = MetaType.Initialize();
 
 	    Exceptions.Initialize();
@@ -105,6 +107,13 @@
 	    ImportHook.Initialize();
 
 
+	}
+
+	internal static void Finalize() {
+  	    AssemblyManager.Finalize();
+  	    Exceptions.Finalize();
+  	    ImportHook.Finalize();
+	    Py_Finalize();
 	}
 
 	internal static IntPtr PyBaseObjectType;




More information about the Zope-CVS mailing list