diff --git a/setup.py b/setup.py index 05ae35906..7815152b8 100644 --- a/setup.py +++ b/setup.py @@ -160,7 +160,7 @@ def build_extension(self, ext): enable_shared = False if not enable_shared: - defines.append("PYTHON_WITHOUT_ENABLE_SHARED") + pass#defines.append("PYTHON_WITHOUT_ENABLE_SHARED") if hasattr(sys, "abiflags"): if "d" in sys.abiflags: diff --git a/src/runtime/converter.cs b/src/runtime/converter.cs index ef3aa3e18..96803d1e5 100644 --- a/src/runtime/converter.cs +++ b/src/runtime/converter.cs @@ -101,7 +101,8 @@ internal static IntPtr GetPythonTypeByAlias(Type op) return Runtime.PyLongType; } else if ((op == doubleType) || - (op == singleType)) + (op == singleType) || + (op == decimalType)) { return Runtime.PyFloatType; } @@ -126,6 +127,12 @@ internal static IntPtr ToPython(T value) internal static IntPtr ToPython(Object value, Type type) { + if(value is PyObject) + { + IntPtr handle = ((PyObject)value).Handle; + Runtime.XIncref(handle); + return handle; + } IntPtr result = IntPtr.Zero; // Null always converts to None in Python. @@ -208,6 +215,17 @@ internal static IntPtr ToPython(Object value, Type type) case TypeCode.UInt64: return Runtime.PyLong_FromUnsignedLongLong((ulong)value); + case TypeCode.Decimal: + IntPtr mod = Runtime.PyImport_ImportModule("decimal"); + IntPtr ctor = Runtime.PyObject_GetAttrString(mod, "Decimal"); + + string d2s = ((decimal)value).ToString(nfi); + IntPtr d2p = Runtime.PyString_FromString(d2s); + IntPtr args = Runtime.PyTuple_New(1); + Runtime.PyTuple_SetItem(args, 0, d2p); + + return Runtime.PyObject_CallObject(ctor, args); + default: if (value is IEnumerable) { @@ -265,6 +283,13 @@ internal static bool ToManaged(IntPtr value, Type type, internal static bool ToManagedValue(IntPtr value, Type obType, out Object result, bool setError) { + if (obType == typeof(PyObject)) + { + Runtime.XIncref(value); // PyObject() assumes ownership + result = new PyObject(value); + return true; + } + // Common case: if the Python value is a wrapped managed object // instance, just return the wrapped object. ManagedType mt = ManagedType.GetManagedObject(value); @@ -785,6 +810,18 @@ static bool ToPrimitive(IntPtr value, Type obType, out Object result, } result = d; return true; + + case TypeCode.Decimal: + op = Runtime.PyObject_Str(value); + decimal m; + string sm = Runtime.GetManagedString(op); + if (!Decimal.TryParse(sm, NumberStyles.Number, nfi, out m)) + { + goto type_error; + } + Runtime.XDecref(op); + result = m; + return true; } diff --git a/src/runtime/pyobject.cs b/src/runtime/pyobject.cs index 323d50da7..781f6313d 100644 --- a/src/runtime/pyobject.cs +++ b/src/runtime/pyobject.cs @@ -126,7 +126,7 @@ protected virtual void Dispose(bool disposing) disposed = true; } } - + public void Dispose() { Dispose(true); diff --git a/src/testing/callbacktest.cs b/src/testing/callbacktest.cs index 81389289d..70c7bbc9e 100644 --- a/src/testing/callbacktest.cs +++ b/src/testing/callbacktest.cs @@ -28,4 +28,18 @@ public string Call_simpleDefaultArg_WithEmptyArgs(string moduleName) } } } + + //========================================================================== + // Tests calling from Python into C# and back into Python using a PyObject. + // SelfCallbackTest should be inherited by a Python class. + // Used in test_class.py / testCallback + //========================================================================== + public class SelfCallbackTest + { + public void Callback(Runtime.PyObject self) + { + using (Runtime.Py.GIL()) + ((dynamic)self).PyCallback(self); + } + } } diff --git a/src/tests/test_class.py b/src/tests/test_class.py index afb631622..9e2af14da 100644 --- a/src/tests/test_class.py +++ b/src/tests/test_class.py @@ -250,6 +250,21 @@ def testComparisons(self): c2 = ClassTest() self.assertRaises(TypeError, lambda: c1 < c2) + def testSelfCallback(self): + """ Test calling back and forth between this and a c# baseclass.""" + class CallbackUser(Test.SelfCallbackTest): + def DoCallback(self): + self.PyCallbackWasCalled = False + self.SameReference = False + return self.Callback(self) + def PyCallback(self, self2): + self.PyCallbackWasCalled = True + self.SameReference = self == self2 + + testobj = CallbackUser() + testobj.DoCallback() + self.assertTrue(testobj.PyCallbackWasCalled) + self.assertTrue(testobj.SameReference) class ClassicClass: def kind(self):