[Zope-CVS] CVS: PythonNet/src/runtime - Python.cs:1.1 ArrayObject.cs:1.2 CallbackThunks.cs:1.2 ClassManager.cs:1.3 ClassObject.cs:1.2 ConstructorBinder.cs:1.2 Converter.cs:1.2 DebugHelper.cs:1.2 DelegateManager.cs:1.2 DelegateObject.cs:1.2 Exceptions.cs:1.2 Indexer.cs:1.2 MethodBinder.cs:1.2 PropertyObject.cs:1.2 PythonException.cs:1.2 Runtime.cs:1.2 TypeManager.cs:1.3 PythonInterpreter.cs:NONE

Brian Lloyd brian@zope.com
Mon, 28 Jul 2003 22:28:58 -0400


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

Modified Files:
	ArrayObject.cs CallbackThunks.cs ClassManager.cs 
	ClassObject.cs ConstructorBinder.cs Converter.cs 
	DebugHelper.cs DelegateManager.cs DelegateObject.cs 
	Exceptions.cs Indexer.cs MethodBinder.cs PropertyObject.cs 
	PythonException.cs Runtime.cs TypeManager.cs 
Added Files:
	Python.cs 
Removed Files:
	PythonInterpreter.cs 
Log Message:
added indexer support, array support and preliminary thread primitives

=== Added File PythonNet/src/runtime/Python.cs ===
// Copyright (c) 2001, 2002 Zope Corporation and Contributors.
//
// All Rights Reserved.
//
// This software is subject to the provisions of the Zope Public License,
// Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
// FOR A PARTICULAR PURPOSE.

using System;
using System.Threading;
using System.Collections;
using System.Runtime.InteropServices;


namespace Python.Runtime {

    /// <summary>
    /// This class represents the public interface of the Python runtime.
    /// 
    /// </summary>

    public class PythonEngine {

	private static Hashtable threads;
	private static bool initialized;
	private static IntPtr istate;


	//====================================================================
	// Initialize the Python runtime. It is safe to call this method more
	// than once, though initialization will only happen on the first call.
	//====================================================================

	public static void Initialize() {
	    if (!initialized) {
		Runtime.Initialize();

		threads = new Hashtable();
		IntPtr ts = Runtime.PyThreadState_Get();
		threads[Thread.CurrentThread] = ts;

		// bleah - fix this!
		istate = Marshal.ReadIntPtr(ts, 1 * IntPtr.Size);

		initialized = true;
	    }
	}


	//====================================================================
	// Shutdown and clean up the Python runtime. After calling this method,
	// the Python runtime can no longer be used in the current process.
	//====================================================================

	public static void Finalize() {
	    if (initialized) {
		Runtime.Py_Finalize();
		initialized = false;
	    }
	}


	/*
	// Note that the semantics of these thread management APIs are fairly
	// different from those of the C Python APIs. The managed integration
	// layer has to support nearly arbitrarily reentrant code since Python
	// can call managed code which calls back into Python, etc.
	*/


	//====================================================================
	// Ensure that the currently executing thread is known to the Python
	// interpreter. This is mainly called by async support code that may
	// be called on system thread pool threads.
	//====================================================================

	public static IntPtr EnsureThread() {
	    Thread t = Thread.CurrentThread;
	    Object v = threads[t];
	    if (v == null) {
		IntPtr ts = Runtime.PyThreadState_New(istate);
		threads[t] = ts;
		return ts;
	    }
	    return (IntPtr) v;
	}


	//====================================================================
	// Acquire the Python interpreter lock unconditionally. It is safe to
	// call this even if the calling thread already owns the interpreter 
	// lock (in which case it doesn't change the lock state).
	//====================================================================

	public static void AcquireThreadLock() {
	    IntPtr current = Runtime.PyThreadState_Swap(IntPtr.Zero);
	    Runtime.PyThreadState_Swap(current);
	    IntPtr ts = EnsureThread(); // should inline
	    if (ts != current) {
		Runtime.PyEval_RestoreThread(ts);
	    }
	}


	//====================================================================
	// Release the Python interpreter lock unconditionally. It is safe to
	// call this even if the calling thread does not own the interpreter 
	// lock (in which case it doesn't change the lock state).
	//====================================================================

	public static void ReleaseThreadLock() {
	    IntPtr current = Runtime.PyThreadState_Swap(IntPtr.Zero);
	    Runtime.PyThreadState_Swap(current);
	    IntPtr ts = EnsureThread();
	    if (ts == current) {
		ts = Runtime.PyEval_SaveThread();
	    }
	}





	//====================================================================
	// Interpreter properties
	//====================================================================

	public static bool IsInitialized {
	    get {
		return initialized;
	    }
	}

	public static string ProgramName {
	    get {
		string result = Runtime.Py_GetProgramName();
		if (result == null) {
		    return "";
		}
		return result;
	    }
	    set {
		Runtime.Py_SetProgramName(value);
	    }
	}

	public static string PythonHome {
	    get {
		string result = Runtime.Py_GetPythonHome();
		if (result == null) {
		    return "";
		}
		return result;
	    }
	    set {
		Runtime.Py_SetPythonHome(value);
	    }
	}

	public static string Version {
	    get { 
		return Runtime.Py_GetVersion(); 
	    }
	}

	public static string BuildInfo {
	    get { 
		return Runtime.Py_GetBuildInfo(); 
	    }
	}

	public static string Platform {
	    get { 
		return Runtime.Py_GetPlatform(); 
	    }
	}

	public static string Copyright {
	    get { 
		return Runtime.Py_GetCopyright(); 
	    }
	}

	public static int RunSimpleString(string code) {
	    return Runtime.PyRun_SimpleString(code);
	}

//  	public static PyModule ImportModule(string name) {
//  	    PyString moduleName = new PyString(name);
//  	    IntPtr pointer = Runtime.PyImport_Import(moduleName.Handle);
//  	    return new PyModule(pointer);
//  	}

//  	public static PyModule ReloadModule(PyModule module) {
//  	    IntPtr pointer = Runtime.PyImport_ReloadModule(module.Handle);
//  	    return new PyModule(pointer);
//  	}

//  	public static PyModule AddModule(string name) {
//  	    IntPtr result = Runtime.PyImport_AddModule(name);
//  	    if (result == IntPtr.Zero) {
//  		throw new PythonException();
//  	    }
//  	    Runtime.Incref(result);
//  	    return new PyModule(result);
//  	}

    }


}


=== PythonNet/src/runtime/ArrayObject.cs 1.1 => 1.2 ===
--- PythonNet/src/runtime/ArrayObject.cs:1.1	Mon Jul 14 15:59:51 2003
+++ PythonNet/src/runtime/ArrayObject.cs	Mon Jul 28 22:28:15 2003
@@ -39,21 +39,236 @@
 	}
 
 	[CallConvCdecl()]
-	public static IntPtr tp_init(IntPtr ob, IntPtr args, IntPtr kw) {
+	public static int tp_init(IntPtr ob, IntPtr args, IntPtr kw) {
 	    Exceptions.SetError(Exceptions.TypeError,
 				"cannot instantiate array wrapper"
 				);
-	    return IntPtr.Zero;
+	    return -1;
 	}
 
-	/*
+
+	//====================================================================
+	// Implements __getitem__ for array types.
+	//====================================================================
+
+	[CallConvCdecl()]
+	public static IntPtr mp_subscript(IntPtr ob, IntPtr idx) {
+	    CLRObject obj = (CLRObject)ManagedType.GetManagedObject(ob);
+	    Array items = obj.inst as Array;
+	    Type itemType = obj.inst.GetType().GetElementType();
+	    int rank = items.Rank;
+	    int index = 0;
+	    object value;
+
+	    // Note that CLR 1.0 only supports int indexes - methods to
+	    // support long indices were introduced in 1.1. We could
+	    // support long indices automatically, but given that long
+	    // indices are not backward compatible and a relative edge 
+	    // case, we won't bother for now.
+
+	    // Single-dimensional arrays are the most common case and are
+	    // cheaper to deal with than multi-dimensional, so check first.
+
+	    if (rank == 1) {
+		index = (int)Runtime.PyInt_AsLong(idx);
+
+		if (Exceptions.ErrorOccurred()) {
+		    Exceptions.SetError(Exceptions.TypeError,
+					"invalid index value"
+					);
+		    return IntPtr.Zero;
+		}
+
+		if (index < 0) {
+		    index = items.Length + index;
+		}
+
+		try {
+		    value = items.GetValue(index);
+		}
+		catch (IndexOutOfRangeException) {
+		    Exceptions.SetError(Exceptions.IndexError,
+					"array index out of range"
+					);
+		    return IntPtr.Zero; 
+		}
+
+		return Converter.ToPython(items.GetValue(index), itemType);
+	    }
+
+	    // Multi-dimensional arrays can be indexed a la: list[1, 2, 3].
+
+	    if (!Runtime.PyTuple_Check(idx)) {
+		Exceptions.SetError(Exceptions.TypeError,
+				    "invalid index value"
+				    );
+		return IntPtr.Zero;
+	    }
+
+	    int count = Runtime.PyTuple_Size(idx);
+
+	    Array args = Array.CreateInstance(typeof(Int32), count);
+
+	    for (int i = 0; i < count; i++) {
+		IntPtr op = Runtime.PyTuple_GetItem(idx, i);
+		index = (int)Runtime.PyInt_AsLong(op);
+
+		if (Exceptions.ErrorOccurred()) {
+		    Exceptions.SetError(Exceptions.TypeError,
+					"invalid index value"
+					);
+		    return IntPtr.Zero;
+		}
+
+		if (index < 0) {
+		    index = items.GetLength(i) + index;
+		}
+
+		args.SetValue(index, i);
+	    }
+
+	    try {
+		value = items.GetValue((int[]) args);
+	    }
+	    catch (IndexOutOfRangeException) {
+		Exceptions.SetError(Exceptions.IndexError,
+				    "array index out of range"
+				    );
+		return IntPtr.Zero; 
+	    }
+
+	    return Converter.ToPython(value, itemType);
+	}
+
+
+	//====================================================================
+	// Implements __setitem__ for array types.
+	//====================================================================
+
+	[CallConvCdecl()]
+	public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) {
+	    CLRObject obj = (CLRObject)ManagedType.GetManagedObject(ob);
+	    Array items = obj.inst as Array;
+	    Type itemType = obj.inst.GetType().GetElementType();
+	    int rank = items.Rank;
+	    int index = 0;
+	    object value;
+
+	    if (items.IsReadOnly) {
+		Exceptions.SetError(Exceptions.TypeError,
+				    "array is read-only"
+				    );
+		return -1;
+	    }
+
+	    if (!Converter.ToManaged(v, itemType, out value, true)) {
+		return -1;
+	    }
+
+	    if (rank == 1) {
+		index = (int)Runtime.PyInt_AsLong(idx);
+
+		if (Exceptions.ErrorOccurred()) {
+		    Exceptions.SetError(Exceptions.TypeError,
+					"invalid index value"
+					);
+		    return -1;
+		}
+
+		if (index < 0) {
+		    index = items.Length + index;
+		}
+
+		try {
+		    items.SetValue(value, index);
+		}
+		catch (IndexOutOfRangeException) {
+		    Exceptions.SetError(Exceptions.IndexError,
+					"array index out of range"
+					);
+		    return -1; 
+		}
+
+		return 0;
+	    }
+
+	    if (!Runtime.PyTuple_Check(idx)) {
+		Exceptions.SetError(Exceptions.TypeError,
+				    "invalid index value"
+				    );
+		return -1;
+	    }
+
+	    int count = Runtime.PyTuple_Size(idx);
+
+	    Array args = Array.CreateInstance(typeof(Int32), count);
+
+	    for (int i = 0; i < count; i++) {
+		IntPtr op = Runtime.PyTuple_GetItem(idx, i);
+		index = (int)Runtime.PyInt_AsLong(op);
+
+		if (Exceptions.ErrorOccurred()) {
+		    Exceptions.SetError(Exceptions.TypeError,
+					"invalid index value"
+					);
+		    return -1;
+		}
+
+		if (index < 0) {
+		    index = items.GetLength(i) + index;
+		}
+
+		args.SetValue(index, i);
+	    }
+
+	    try {
+		items.SetValue(value, (int[])args);
+	    }
+	    catch (IndexOutOfRangeException) {
+		Exceptions.SetError(Exceptions.IndexError,
+				    "array index out of range"
+				    );
+		return -1;
+	    }
+
+	    return 0;
+	}
+
+
+	//====================================================================
+	// Implements __contains__ for array types.
+	//====================================================================
+
 	[CallConvCdecl()]
-	public static IntPtr tp_repr(IntPtr ob) {
-	    ArrayObject self = (ArrayObject)GetManagedObject(ob);
-	    string s = String.Format("<array '{0}'>", self.type.Name);
-	    return Runtime.PyString_FromStringAndSize(s, s.Length);
+	public static int sq_contains(IntPtr ob, IntPtr v) {
+	    CLRObject obj = (CLRObject)ManagedType.GetManagedObject(ob);
+	    Type itemType = obj.inst.GetType().GetElementType();
+	    IList items = obj.inst as IList;
+	    object value;
+
+	    if (!Converter.ToManaged(v, itemType, out value, false)) {
+		return 0;
+	    }
+
+	    if (items.Contains(value)) {
+		return 1;
+	    }
+
+	    return 0;
 	}
-	*/
+
+
+	//====================================================================
+	// Implements __len__ for array types.
+	//====================================================================
+
+	[CallConvCdecl()]
+	public static int mp_length(IntPtr ob) {
+	    CLRObject self = (CLRObject)ManagedType.GetManagedObject(ob);
+	    Array items = self.inst as Array;
+	    return items.Length;
+	}
+
 
     }	
 


=== PythonNet/src/runtime/CallbackThunks.cs 1.1 => 1.2 ===
--- PythonNet/src/runtime/CallbackThunks.cs:1.1	Mon Jul 14 15:59:51 2003
+++ PythonNet/src/runtime/CallbackThunks.cs	Mon Jul 28 22:28:15 2003
@@ -318,7 +318,6 @@
 
 	internal static IntPtr GetThunk(MethodInfo method) {
 	    // WARNING: this probably needs a thread lock!
-	    //Type dt = typeof(CallbackThunks).GetNestedType(method.Name);
 	    Type dt = Prototypes.GetPrototype(method.Name);
 	    if (dt != null) {
 		Delegate d = Delegate.CreateDelegate(dt, method);


=== PythonNet/src/runtime/ClassManager.cs 1.2 => 1.3 ===
--- PythonNet/src/runtime/ClassManager.cs:1.2	Thu Jul 24 19:55:00 2003
+++ PythonNet/src/runtime/ClassManager.cs	Mon Jul 28 22:28:15 2003
@@ -100,7 +100,6 @@
 
 	    impl.tpHandle = TypeManager.GetTypeHandle(impl, type);
 
-
 	    // Finally, initialize the class __dict__ and return the object.
 
 	    IntPtr pp = Runtime._PyObject_GetDictPtr(impl.tpHandle);


=== PythonNet/src/runtime/ClassObject.cs 1.1 => 1.2 ===
--- PythonNet/src/runtime/ClassObject.cs:1.1	Mon Jul 14 15:59:51 2003
+++ PythonNet/src/runtime/ClassObject.cs	Mon Jul 28 22:28:15 2003
@@ -93,6 +93,100 @@
 	}
 
 
+	//====================================================================
+	// Implements __getitem__ for reflected classes and value types.
+	//====================================================================
+
+	[CallConvCdecl()]
+	public static IntPtr mp_subscript(IntPtr ob, IntPtr idx) {
+	    ManagedType self = GetManagedObject(ob);
+	    IntPtr tp = Runtime.PyObject_Type(ob);
+	    ClassBase cls = (ClassBase)GetManagedObject(tp);
+
+	    if (cls.indexer == null || !cls.indexer.CanGet) {
+		Exceptions.SetError(Exceptions.TypeError, 
+				    "unindexable object"
+				    );
+		return IntPtr.Zero;
+	    }
+
+	    // Arg may be a tuple in the case of an indexer with multiple
+	    // parameters. If so, use it directly, else make a new tuple
+	    // with the index arg (method binders expect arg tuples).
+
+	    IntPtr args = idx;
+	    bool free = false;
+
+	    if (!Runtime.PyTuple_Check(idx)) {
+		args = Runtime.PyTuple_New(1);
+		Runtime.PyTuple_SetItem(args, 0, idx);
+		free = true;
+	    }
+
+	    IntPtr value = cls.indexer.GetItem(ob, args);
+
+	    if (free) {
+		Runtime.Decref(args);
+	    }
+
+	    return value;
+	}
+
+
+	//====================================================================
+	// Implements __setitem__ for reflected classes and value types.
+	//====================================================================
+
+	[CallConvCdecl()]
+	public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) {
+	    ManagedType self = GetManagedObject(ob);
+	    IntPtr tp = Runtime.PyObject_Type(ob);
+	    ClassBase cls = (ClassBase)GetManagedObject(tp);
+
+	    if (cls.indexer == null || !cls.indexer.CanSet) {
+		Exceptions.SetError(Exceptions.TypeError, 
+				    "object doesn't support item assignment x"
+				    );
+		return -1;
+	    }
+
+	    // Arg may be a tuple in the case of an indexer with multiple
+	    // parameters. If so, use it directly, else make a new tuple
+	    // with the index arg (method binders expect arg tuples).
+
+	    IntPtr args = idx;
+	    bool free = false;
+
+	    if (!Runtime.PyTuple_Check(idx)) {
+		args = Runtime.PyTuple_New(1);
+		Runtime.PyTuple_SetItem(args, 0, idx);
+		free = true;
+	    }
+
+	    int i = Runtime.PyTuple_Size(args);
+	    IntPtr real = Runtime.PyTuple_New(i + 1);
+	    for (int n = 0; n < i; n++) {
+		IntPtr item = Runtime.PyTuple_GetItem(args, n);
+		Runtime.PyTuple_SetItem(real, n, item);
+	    }
+	    Runtime.PyTuple_SetItem(real, i, v);
+
+	    IntPtr value = cls.indexer.SetItem(ob, real);
+
+	    Runtime.Decref(real);
+
+	    if (free) {
+		Runtime.Decref(args);
+	    }
+
+	    if (Exceptions.ErrorOccurred()) {
+		return -1;
+	    }
+
+	    return 0;
+	}
+
+
     }	
 
 }


=== PythonNet/src/runtime/ConstructorBinder.cs 1.1 => 1.2 ===
--- PythonNet/src/runtime/ConstructorBinder.cs:1.1	Mon Jul 14 15:59:51 2003
+++ PythonNet/src/runtime/ConstructorBinder.cs	Mon Jul 28 22:28:15 2003
@@ -39,6 +39,8 @@
 	    }
 
 	    ConstructorInfo ci = (ConstructorInfo)binding.info;
+	    //	    IntPtr ts = PythonEngine.BeginAllowThreads();
+
 	    try {
 		result = ci.Invoke(binding.args);
 	    }
@@ -46,10 +48,12 @@
 		if (e.InnerException != null) {
 		    e = e.InnerException;
 		}
+		//PythonEngine.EndAllowThreads(ts);
 		Exceptions.SetError(e);
 		return IntPtr.Zero;
 	    }
 
+	    //PythonEngine.EndAllowThreads(ts);
 	    return Converter.ToPython(result, result.GetType());
 	}
 


=== PythonNet/src/runtime/Converter.cs 1.1 => 1.2 ===
--- PythonNet/src/runtime/Converter.cs:1.1	Mon Jul 14 15:59:51 2003
+++ PythonNet/src/runtime/Converter.cs	Mon Jul 28 22:28:15 2003
@@ -27,10 +27,16 @@
 	private Converter() {}
 
 	static Type objectType;
+	static Type stringType;
+	static Type int32Type;
+	static Type int64Type;
 	static Type flagsType;
 
 	static Converter () {
 	    objectType = typeof(Object);
+	    stringType = typeof(String);
+	    int32Type = typeof(Int32);
+	    int64Type = typeof(Int64);
 	    flagsType = typeof(FlagsAttribute);
 	}
 
@@ -152,11 +158,38 @@
 		return ToEnum(value, obType, out result, setError);
 	    }
 
-	    if (value == Runtime.PyNone && !obType.IsPrimitive) {
+	    if (value == Runtime.PyNone && !obType.IsValueType) {
 		result = null;
 		return true;
 	    }
 
+	    // Conversion to 'Object' is done based on some reasonable
+	    // default conversions (Python string -> managed string, 
+	    // Python int -> Int32 etc.).
+
+	    if (obType == objectType) {
+		if (Runtime.IsStringType(value)) {
+		    return ToPrimitive(value, stringType, out result, 
+				       setError);
+		}
+
+		else if (Runtime.PyInt_Check(value)) {
+		    return ToPrimitive(value, int32Type, out result, setError);
+		}
+
+		else if (Runtime.PyLong_Check(value)) {
+		    return ToPrimitive(value, int64Type, out result, setError);
+		}
+
+		if (setError) {
+		    Exceptions.SetError(Exceptions.TypeError,
+					"value cannot be converted to Object"
+					);
+		}
+
+		return false;
+	    }
+
 	    return ToPrimitive(value, obType, out result, setError);
 
 	}
@@ -460,6 +493,8 @@
 	    return false;
 
 	}
+
+
 
     }
 


=== PythonNet/src/runtime/DebugHelper.cs 1.1 => 1.2 ===
--- PythonNet/src/runtime/DebugHelper.cs:1.1	Mon Jul 14 15:59:51 2003
+++ PythonNet/src/runtime/DebugHelper.cs	Mon Jul 28 22:28:15 2003
@@ -36,7 +36,6 @@
 	}
 
 
-
     }
 
 


=== PythonNet/src/runtime/DelegateManager.cs 1.1 => 1.2 ===
--- PythonNet/src/runtime/DelegateManager.cs:1.1	Mon Jul 14 15:59:51 2003
+++ PythonNet/src/runtime/DelegateManager.cs	Mon Jul 28 22:28:15 2003
@@ -194,7 +194,6 @@
        too "special" for this to work. It would be more work, so for now
        the 80/20 rule applies :)
 
-       TODO: how does async invokation of a delegate work w/Python?
     */
 
     public class Dispatcher {
@@ -203,18 +202,23 @@
 	public Type dtype;
 
 	public Dispatcher(IntPtr target, Type dtype) {
-
-	    // method / target object. 
 	    Runtime.Incref(target);
 	    this.target = target;
 	    this.dtype = dtype;
 	}
 
+	public void Finalize() {
+	    Runtime.Decref(target);
+	}
+
 	public object Dispatch(ArrayList args) {
 	    // check refs
 
-	    // TODO: Should probably check here to see if we are being called 
-	    // on an async thread. If so, need to register with Python.
+	    // Delegates with Python implementations may be invoked on a 
+	    // thread from the system thread pool, so we need to ensure
+	    // that Python knows about this thread.
+
+	    PythonEngine.AcquireThreadLock();
 
 	    MethodInfo method = dtype.GetMethod("Invoke");
 	    ParameterInfo[] pi = method.GetParameters();
@@ -250,21 +254,6 @@
 	    return result;
 	}
 
-	public void Finalize() {
-	    // The dispatcher instance owns the reference to the Python
-	    // method. When the true delegate dies, we die and can decref.
-	    Runtime.Decref(target);
-	}
-
-	/*
-	public object InvokeTemplate(int a1, int a2, int a3) {
-	    ArrayList args = new ArrayList();
-	    args.Add(a1);
-	    args.Add(a2);
-	    args.Add(a3);
-	    return this.Dispatch(args);
-	}
-	*/
 	
     }
 


=== PythonNet/src/runtime/DelegateObject.cs 1.1 => 1.2 ===
--- PythonNet/src/runtime/DelegateObject.cs:1.1	Mon Jul 14 15:59:51 2003
+++ PythonNet/src/runtime/DelegateObject.cs	Mon Jul 28 22:28:15 2003
@@ -27,6 +27,7 @@
 
 	internal DelegateObject(Type tp) : base(tp) {
 	    binder = new MethodBinder(tp.GetMethod("Invoke"));
+	    binder.FreeThreaded = false;
 	}
 
 	//====================================================================


=== PythonNet/src/runtime/Exceptions.cs 1.1 => 1.2 ===
--- PythonNet/src/runtime/Exceptions.cs:1.1	Mon Jul 14 15:59:51 2003
+++ PythonNet/src/runtime/Exceptions.cs	Mon Jul 28 22:28:15 2003
@@ -120,6 +120,25 @@
 	/// </remarks>
 
 	public static void SetError(Exception e) {
+
+	    // Because delegates allow arbitrary nestings of Python calling
+	    // managed calling Python calling... etc. it is possible that we
+	    // might get a managed exception raised that is a wrapper for a
+	    // Python exception. In that case we'd rather have the real thing.
+
+	    PythonException err = e as PythonException;
+	    if (err != null) {
+		if (err.Type == IntPtr.Zero) {
+		    Console.WriteLine("null!");
+		}
+		if (err.Value == IntPtr.Zero) {
+		    Console.WriteLine("null!");
+		}
+
+		Runtime.PyErr_SetObject(err.Type, err.Value);
+		return;
+	    }
+
 	    Runtime.PyErr_Clear();
 	    IntPtr op = CLRObject.GetInstHandle(e);
 	    Runtime.Incref(op);


=== PythonNet/src/runtime/Indexer.cs 1.1 => 1.2 ===
--- PythonNet/src/runtime/Indexer.cs:1.1	Thu Jul 24 19:55:00 2003
+++ PythonNet/src/runtime/Indexer.cs	Mon Jul 28 22:28:15 2003
@@ -30,6 +30,20 @@
 	    SetterBinder = new MethodBinder();
 	}
 
+
+	public bool CanGet {
+	    get { 
+		return GetterBinder.Count > 0; 
+	    }
+	}
+
+	public bool CanSet {
+	    get { 
+		return SetterBinder.Count > 0; 
+	    }
+	}
+
+
 	public void AddProperty(PropertyInfo pi) {
 	    MethodInfo getter = pi.GetGetMethod(true);
 	    MethodInfo setter = pi.GetSetMethod(true);
@@ -39,6 +53,15 @@
 	    if (setter != null) {
 		SetterBinder.AddMethod(setter);
 	    }
+	}
+
+	internal IntPtr GetItem(IntPtr inst, IntPtr args) {
+	    return GetterBinder.Invoke(inst, args, IntPtr.Zero);
+	}
+
+
+	internal IntPtr SetItem(IntPtr inst, IntPtr args) {
+	    return SetterBinder.Invoke(inst, args, IntPtr.Zero);
 	}
 
     }


=== PythonNet/src/runtime/MethodBinder.cs 1.1 => 1.2 ===
--- PythonNet/src/runtime/MethodBinder.cs:1.1	Mon Jul 14 15:59:51 2003
+++ PythonNet/src/runtime/MethodBinder.cs	Mon Jul 28 22:28:15 2003
@@ -25,7 +25,8 @@
     internal class MethodBinder {
 
 	// MethodInfo info;
-	ArrayList list;
+	public ArrayList list;
+	public bool FreeThreaded = true;
 
 	internal MethodBinder () {
 	    // this.info = null;
@@ -38,6 +39,10 @@
 	    this.list.Add(mi);
 	}
 
+	public int Count {
+	    get { return this.list.Count; }
+	}
+
 	internal void AddMethod(MethodBase m) {
 	    // if more than one, use complex ds, else use info
 	    this.list.Add(m);
@@ -98,6 +103,9 @@
 		return IntPtr.Zero;
 	    }
 
+	    //Console.WriteLine("\nrelease: {0}", binding.info);
+	    PythonEngine.ReleaseThreadLock();
+
 	    try {
 		result = binding.info.Invoke(binding.inst, 
 					     BindingFlags.Default, 
@@ -109,9 +117,16 @@
 		if (e.InnerException != null) {
 		    e = e.InnerException;
 		}
+
+		//Console.WriteLine("\nacquire: {0}", binding.info);
+		PythonEngine.AcquireThreadLock();
+
 		Exceptions.SetError(e);
 		return IntPtr.Zero;
 	    }
+
+	    //Console.WriteLine("\nacquire: {0}", binding.info);
+	    PythonEngine.AcquireThreadLock();
 
 	    MethodInfo mi = (MethodInfo)binding.info;
 	    return Converter.ToPython(result, mi.ReturnType);


=== PythonNet/src/runtime/PropertyObject.cs 1.1 => 1.2 ===
--- PythonNet/src/runtime/PropertyObject.cs:1.1	Mon Jul 14 15:59:51 2003
+++ PythonNet/src/runtime/PropertyObject.cs	Mon Jul 28 22:28:15 2003
@@ -43,8 +43,10 @@
 	public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) {
 	    PropertyObject self = (PropertyObject)GetManagedObject(ds);
 	    MethodInfo getter = self.getter;
+	    IntPtr ts = IntPtr.Zero;
 	    Object result;
 
+
 	    if (getter == null) {
 		Exceptions.SetError(Exceptions.TypeError, 
 				    "property cannot be read"
@@ -67,11 +69,14 @@
 			       );
 		    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;
 		}
@@ -79,10 +84,15 @@
 
 	    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);
 		return IntPtr.Zero;
 	    }
@@ -98,6 +108,7 @@
 	public static int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) {
 	    PropertyObject self = (PropertyObject)GetManagedObject(ds);
 	    MethodInfo setter = self.setter;
+	    IntPtr ts = IntPtr.Zero;
 	    Object newval;
 
 	    if (val == IntPtr.Zero) {
@@ -140,14 +151,21 @@
 	    try {
 		if (!is_static) {
 		    CLRObject co = (CLRObject)GetManagedObject(ob);
+		    //ts = PythonEngine.BeginAllowThreads();
 		    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);
 		return -1;
 	    }


=== PythonNet/src/runtime/PythonException.cs 1.1 => 1.2 ===
--- PythonNet/src/runtime/PythonException.cs:1.1	Mon Jul 14 15:59:51 2003
+++ PythonNet/src/runtime/PythonException.cs	Mon Jul 28 22:28:15 2003
@@ -14,11 +14,8 @@
 namespace Python.Runtime {
 
     /// <summary>
-    /// Provides an interface to exceptions thrown by the Python runtime.
-    ///
-    /// Managed wrappers for the Python APIs will propagate exceptions
-    /// thrown in the Python runtime by throwing a PythonException that
-    /// wraps and provides access to the Python exception information.
+    /// Provides a managed interface to exceptions thrown by the Python 
+    /// runtime.
     /// </summary>
 
     public class PythonException : System.Exception {
@@ -28,31 +25,12 @@
 	private IntPtr excTb = IntPtr.Zero;
 
 	public PythonException() : base() {
-	    // According to the SDK docs, because IntPtr is blittable the
-	    // interop marshaller will pin automatically for byref calls.
 	    Runtime.PyErr_Fetch(ref excType, ref excValue, ref excTb);
+	    Runtime.Incref(excType);
+	    Runtime.Incref(excValue);
+	    Runtime.Incref(excTb);
 	}
 
-	/// <summary>
-	/// Traceback Property
-	/// </summary>
-	///
-	/// <remarks>
-	/// Returns the message associated with the exception.
-	/// </remarks>
-
-	string _message;
-
-	public override string Message {
-	    get {
-		if (_message != null) {
-		    return _message;
-		}
-		IntPtr ob = Runtime.PyObject_Str(excValue);
-		_message = Runtime.PyString_AsString(ob);
-		return _message;
-	    }
-	}
 
 	/// <summary>
 	/// Type Property
@@ -64,7 +42,7 @@
 
 	public IntPtr Type {
 	    get {
-		return IntPtr.Zero;
+		return excType;
 	    }
 	}
 
@@ -78,7 +56,7 @@
 
 	public IntPtr Value {
 	    get {
-		return IntPtr.Zero;
+		return excValue;
 	    }
 	}
 
@@ -92,7 +70,7 @@
 
 	public IntPtr Traceback {
 	    get {
-		return IntPtr.Zero;
+		return excTb;
 	    }
 	}
 


=== PythonNet/src/runtime/Runtime.cs 1.1 => 1.2 ===
--- PythonNet/src/runtime/Runtime.cs:1.1	Mon Jul 14 15:59:51 2003
+++ PythonNet/src/runtime/Runtime.cs	Mon Jul 28 22:28:15 2003
@@ -98,17 +98,20 @@
 
 	    // TODO: get rid of this! This works around the gc crash
 	    // until I have time to dig into it.
+	    bool hack = true;
 
-	    IntPtr nm = Runtime.PyString_FromString("gc");
-	    IntPtr md = Runtime.PyImport_Import(nm);
-	    IntPtr fn = Runtime.PyObject_GetAttrString(md, "disable");
-	    IntPtr aa = Runtime.PyTuple_New(0);
-	    IntPtr rr = Runtime.PyObject_Call(fn, aa, IntPtr.Zero);
-	    Runtime.Decref(rr);
-	    Runtime.Decref(aa);
-	    Runtime.Decref(fn);
-	    Runtime.Decref(nm);
-	    Runtime.Decref(md);
+	    if (hack) {
+		IntPtr nm = Runtime.PyString_FromString("gc");
+		IntPtr md = Runtime.PyImport_Import(nm);
+		IntPtr fn = Runtime.PyObject_GetAttrString(md, "disable");
+		IntPtr aa = Runtime.PyTuple_New(0);
+		IntPtr rr = Runtime.PyObject_Call(fn, aa, IntPtr.Zero);
+		Runtime.Decref(rr);
+		Runtime.Decref(aa);
+		Runtime.Decref(fn);
+		Runtime.Decref(nm);
+		Runtime.Decref(md);
+	    }
 	}
 
 	internal unsafe static void Incref(IntPtr op) {
@@ -227,10 +230,20 @@
 	[DllImport("python22", CallingConvention=CallingConvention.Cdecl,
 		    ExactSpelling=true, CharSet=CharSet.Ansi)]
 	internal unsafe static extern IntPtr
+	PyThreadState_New(IntPtr istate);
+
+	[DllImport("python22", CallingConvention=CallingConvention.Cdecl,
+		    ExactSpelling=true, CharSet=CharSet.Ansi)]
+	internal unsafe static extern IntPtr
 	PyThreadState_Get();
 
 	[DllImport("python22", CallingConvention=CallingConvention.Cdecl,
 		    ExactSpelling=true, CharSet=CharSet.Ansi)]
+	internal unsafe static extern IntPtr
+	PyThreadState_Swap(IntPtr tstate);
+
+	[DllImport("python22", CallingConvention=CallingConvention.Cdecl,
+		    ExactSpelling=true, CharSet=CharSet.Ansi)]
 	public unsafe static extern int
 	Py_Main(int argc, string[] argv);
 
@@ -455,6 +468,10 @@
 
 
 
+	internal static bool PyInt_Check(IntPtr ob) {
+	    return PyObject_Type(ob) == Runtime.PyIntType;
+	}
+
 	[DllImport("python22", CallingConvention=CallingConvention.Cdecl,
 		    ExactSpelling=true, CharSet=CharSet.Ansi)]
 	internal unsafe static extern IntPtr
@@ -476,6 +493,10 @@
 	PyInt_GetMax();
 
 
+	internal static bool PyLong_Check(IntPtr ob) {
+	    return PyObject_Type(ob) == Runtime.PyLongType;
+	}
+
 	[DllImport("python22", CallingConvention=CallingConvention.Cdecl,
 		    ExactSpelling=true, CharSet=CharSet.Ansi)]
 	internal unsafe static extern IntPtr
@@ -689,8 +710,8 @@
 
 	[DllImport("python22", CallingConvention=CallingConvention.Cdecl,
 		   EntryPoint="PyUnicodeUCS2_AsUnicode",
-		   ExactSpelling=true, CharSet=CharSet.Unicode)]
-	internal unsafe static extern string
+		   ExactSpelling=true)]
+	internal unsafe static extern char *
 	PyUnicode_AsUnicode(IntPtr ob);
 
 	[DllImport("python22", CallingConvention=CallingConvention.Cdecl,
@@ -704,15 +725,18 @@
 	internal unsafe static extern IntPtr 
 	PyUnicode_FromOrdinal(int c);
 
-	internal static string GetManagedString(IntPtr op) {
+	internal unsafe static string GetManagedString(IntPtr op) {
 	    IntPtr type = PyObject_Type(op);
 	    if (type == Runtime.PyStringType) {
 		return Runtime.PyString_AsString(op);
 	    }
 	    if (type == Runtime.PyUnicodeType) {
-		return Runtime.PyUnicode_AsUnicode(op);
+		char *p = Runtime.PyUnicode_AsUnicode(op);
+		int size = Runtime.PyUnicode_GetSize(op);
+		return new String(p, 0, size);
 	    }
 	    return null;
+
 	}
 
 
@@ -861,6 +885,10 @@
 
 
 	// Python tuple methods
+
+	internal static bool PyTuple_Check(IntPtr ob) {
+	    return PyObject_Type(ob) == Runtime.PyTupleType;
+	}
 
 	[DllImport("python22", CallingConvention=CallingConvention.Cdecl,
 		    ExactSpelling=true, CharSet=CharSet.Ansi)]


=== PythonNet/src/runtime/TypeManager.cs 1.2 => 1.3 ===
--- PythonNet/src/runtime/TypeManager.cs:1.2	Thu Jul 24 19:55:00 2003
+++ PythonNet/src/runtime/TypeManager.cs	Mon Jul 28 22:28:15 2003
@@ -89,6 +89,7 @@
 		    if (! (name.StartsWith("tp_") ||
 			   name.StartsWith("nb_") ||
 			   name.StartsWith("sq_") ||
+			   name.StartsWith("mp_") ||
 			   name.StartsWith("bf_")
 			   ) ) {
 			continue;
@@ -200,6 +201,7 @@
 	    if (i > -1) {
 		name = name.Substring(i + 1);
 	    }
+
 
 	    // todo - can blit this after first time!
 	    PyTypeObject pyTypeObj = new PyTypeObject();

=== Removed File PythonNet/src/runtime/PythonInterpreter.cs ===