From 68e81c796c08d397e8f573b7401b1e5c0452ac1e Mon Sep 17 00:00:00 2001 From: abessen Date: Wed, 19 Oct 2016 13:10:35 -0400 Subject: [PATCH 1/6] Do not call Decref if self.repr is still IntPtr.Zero --- src/runtime/constructorbinding.cs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/runtime/constructorbinding.cs b/src/runtime/constructorbinding.cs index e2eda0685..59fc8d825 100644 --- a/src/runtime/constructorbinding.cs +++ b/src/runtime/constructorbinding.cs @@ -30,7 +30,7 @@ internal class ConstructorBinding : ExtensionType public ConstructorBinding(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBinder) : base() { this.type = type; - Runtime.XIncref(pyTypeHndl); + Runtime.Incref(pyTypeHndl); this.pyTypeHndl = pyTypeHndl; this.ctorBinder = ctorBinder; repr = IntPtr.Zero; @@ -73,7 +73,7 @@ public static IntPtr tp_descr_get(IntPtr op, IntPtr instance, IntPtr owner) return Exceptions.RaiseTypeError("How in the world could that happen!"); } }*/ - Runtime.XIncref(self.pyHandle); // Decref'd by the interpreter. + Runtime.Incref(self.pyHandle); // Decref'd by the interpreter. return self.pyHandle; } @@ -108,7 +108,7 @@ public static IntPtr mp_subscript(IntPtr op, IntPtr key) BoundContructor boundCtor = new BoundContructor(self.type, self.pyTypeHndl, self.ctorBinder, ci); /* Since nothing's chached, do we need the increment??? - Runtime.XIncref(boundCtor.pyHandle); // Decref'd by the interpreter??? */ + Runtime.Incref(boundCtor.pyHandle); // Decref'd by the interpreter??? */ return boundCtor.pyHandle; } @@ -121,7 +121,7 @@ public static IntPtr tp_repr(IntPtr ob) ConstructorBinding self = (ConstructorBinding)GetManagedObject(ob); if (self.repr != IntPtr.Zero) { - Runtime.XIncref(self.repr); + Runtime.Incref(self.repr); return self.repr; } MethodBase[] methods = self.ctorBinder.GetMethods(); @@ -136,7 +136,7 @@ public static IntPtr tp_repr(IntPtr ob) doc += String.Format("{0}{1}", name, str.Substring(idx)); } self.repr = Runtime.PyString_FromString(doc); - Runtime.XIncref(self.repr); + Runtime.Incref(self.repr); return self.repr; } @@ -147,8 +147,8 @@ public static IntPtr tp_repr(IntPtr ob) public static new void tp_dealloc(IntPtr ob) { ConstructorBinding self = (ConstructorBinding)GetManagedObject(ob); - Runtime.XDecref(self.repr); - Runtime.XDecref(self.pyTypeHndl); + Runtime.Decref(self.repr); + Runtime.Decref(self.pyTypeHndl); ExtensionType.FinalizeObject(self); } } @@ -173,7 +173,7 @@ public BoundContructor(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBinde : base() { this.type = type; - Runtime.XIncref(pyTypeHndl); + Runtime.Incref(pyTypeHndl); this.pyTypeHndl = pyTypeHndl; this.ctorBinder = ctorBinder; ctorInfo = ci; @@ -217,7 +217,7 @@ public static IntPtr tp_repr(IntPtr ob) BoundContructor self = (BoundContructor)GetManagedObject(ob); if (self.repr != IntPtr.Zero) { - Runtime.XIncref(self.repr); + Runtime.Incref(self.repr); return self.repr; } string name = self.type.FullName; @@ -225,7 +225,7 @@ public static IntPtr tp_repr(IntPtr ob) int idx = str.IndexOf("("); str = String.Format("returns a new {0}{1}", name, str.Substring(idx)); self.repr = Runtime.PyString_FromString(str); - Runtime.XIncref(self.repr); + Runtime.Incref(self.repr); return self.repr; } From 60c5a96d780a8d44999dc82f09c6082c37b5eb50 Mon Sep 17 00:00:00 2001 From: abessen Date: Thu, 20 Oct 2016 11:51:37 -0400 Subject: [PATCH 2/6] Same self.repr null check in ConstructorBinding.tp_dealloc --- src/runtime/constructorbinding.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/runtime/constructorbinding.cs b/src/runtime/constructorbinding.cs index 59fc8d825..d425c6030 100644 --- a/src/runtime/constructorbinding.cs +++ b/src/runtime/constructorbinding.cs @@ -147,7 +147,8 @@ public static IntPtr tp_repr(IntPtr ob) public static new void tp_dealloc(IntPtr ob) { ConstructorBinding self = (ConstructorBinding)GetManagedObject(ob); - Runtime.Decref(self.repr); + if (self.repr != IntPtr.Zero) + Runtime.Decref(self.repr); Runtime.Decref(self.pyTypeHndl); ExtensionType.FinalizeObject(self); } From 81958b267e83b44438332c189d59a48d53cf8acc Mon Sep 17 00:00:00 2001 From: abessen Date: Wed, 26 Oct 2016 23:50:52 -0400 Subject: [PATCH 3/6] Rename Runtime.Incref/Decref to XIncref/XDecref to signal that they check for NULL Remove NULL check debug print in Decref Remove added NULL checks for self.repr in constructorbinding.cs --- src/runtime/constructorbinding.cs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/runtime/constructorbinding.cs b/src/runtime/constructorbinding.cs index d425c6030..d53580390 100644 --- a/src/runtime/constructorbinding.cs +++ b/src/runtime/constructorbinding.cs @@ -30,7 +30,7 @@ internal class ConstructorBinding : ExtensionType public ConstructorBinding(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBinder) : base() { this.type = type; - Runtime.Incref(pyTypeHndl); + Runtime.XIncref(pyTypeHndl); this.pyTypeHndl = pyTypeHndl; this.ctorBinder = ctorBinder; repr = IntPtr.Zero; @@ -73,7 +73,7 @@ public static IntPtr tp_descr_get(IntPtr op, IntPtr instance, IntPtr owner) return Exceptions.RaiseTypeError("How in the world could that happen!"); } }*/ - Runtime.Incref(self.pyHandle); // Decref'd by the interpreter. + Runtime.XIncref(self.pyHandle); // Decref'd by the interpreter. return self.pyHandle; } @@ -121,7 +121,7 @@ public static IntPtr tp_repr(IntPtr ob) ConstructorBinding self = (ConstructorBinding)GetManagedObject(ob); if (self.repr != IntPtr.Zero) { - Runtime.Incref(self.repr); + Runtime.XIncref(self.repr); return self.repr; } MethodBase[] methods = self.ctorBinder.GetMethods(); @@ -136,7 +136,7 @@ public static IntPtr tp_repr(IntPtr ob) doc += String.Format("{0}{1}", name, str.Substring(idx)); } self.repr = Runtime.PyString_FromString(doc); - Runtime.Incref(self.repr); + Runtime.XIncref(self.repr); return self.repr; } @@ -147,9 +147,8 @@ public static IntPtr tp_repr(IntPtr ob) public static new void tp_dealloc(IntPtr ob) { ConstructorBinding self = (ConstructorBinding)GetManagedObject(ob); - if (self.repr != IntPtr.Zero) - Runtime.Decref(self.repr); - Runtime.Decref(self.pyTypeHndl); + Runtime.XDecref(self.repr); + Runtime.XDecref(self.pyTypeHndl); ExtensionType.FinalizeObject(self); } } @@ -174,7 +173,7 @@ public BoundContructor(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBinde : base() { this.type = type; - Runtime.Incref(pyTypeHndl); + Runtime.XIncref(pyTypeHndl); this.pyTypeHndl = pyTypeHndl; this.ctorBinder = ctorBinder; ctorInfo = ci; @@ -218,7 +217,7 @@ public static IntPtr tp_repr(IntPtr ob) BoundContructor self = (BoundContructor)GetManagedObject(ob); if (self.repr != IntPtr.Zero) { - Runtime.Incref(self.repr); + Runtime.XIncref(self.repr); return self.repr; } string name = self.type.FullName; @@ -226,7 +225,7 @@ public static IntPtr tp_repr(IntPtr ob) int idx = str.IndexOf("("); str = String.Format("returns a new {0}{1}", name, str.Substring(idx)); self.repr = Runtime.PyString_FromString(str); - Runtime.Incref(self.repr); + Runtime.XIncref(self.repr); return self.repr; } From 1445a79dac67d2d603bd57e3c7f305b8adfb62c9 Mon Sep 17 00:00:00 2001 From: abessen Date: Wed, 26 Oct 2016 23:59:20 -0400 Subject: [PATCH 4/6] Add missing changes for Python 2 --- src/runtime/constructorbinding.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/constructorbinding.cs b/src/runtime/constructorbinding.cs index d53580390..e2eda0685 100644 --- a/src/runtime/constructorbinding.cs +++ b/src/runtime/constructorbinding.cs @@ -108,7 +108,7 @@ public static IntPtr mp_subscript(IntPtr op, IntPtr key) BoundContructor boundCtor = new BoundContructor(self.type, self.pyTypeHndl, self.ctorBinder, ci); /* Since nothing's chached, do we need the increment??? - Runtime.Incref(boundCtor.pyHandle); // Decref'd by the interpreter??? */ + Runtime.XIncref(boundCtor.pyHandle); // Decref'd by the interpreter??? */ return boundCtor.pyHandle; } From c40d859c0dacf9bfbe2fe1ac9c1e3afeb07ef94e Mon Sep 17 00:00:00 2001 From: abessen Date: Wed, 16 Nov 2016 09:47:53 -0500 Subject: [PATCH 5/6] Implement comparison operations --- src/runtime/classbase.cs | 133 ++++++++++++++++++++++++++++----------- src/runtime/runtime.cs | 1 + src/tests/test_class.py | 47 +++++++++++++- 3 files changed, 142 insertions(+), 39 deletions(-) diff --git a/src/runtime/classbase.cs b/src/runtime/classbase.cs index 7214a7ba1..da7c57789 100644 --- a/src/runtime/classbase.cs +++ b/src/runtime/classbase.cs @@ -69,44 +69,105 @@ public virtual IntPtr type_subscript(IntPtr idx) //==================================================================== #if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35) public static IntPtr tp_richcompare(IntPtr ob, IntPtr other, int op) { - if (op != Runtime.Py_EQ && op != Runtime.Py_NE) + CLRObject co1; + CLRObject co2; + switch (op) { - Runtime.XIncref(Runtime.PyNotImplemented); - return Runtime.PyNotImplemented; + case Runtime.Py_EQ: + case Runtime.Py_NE: + IntPtr pytrue = Runtime.PyTrue; + IntPtr pyfalse = Runtime.PyFalse; + + // swap true and false for NE + if (op != Runtime.Py_EQ) + { + pytrue = Runtime.PyFalse; + pyfalse = Runtime.PyTrue; + } + + if (ob == other) + { + Runtime.XIncref(pytrue); + return pytrue; + } + + co1 = GetManagedObject(ob) as CLRObject; + co2 = GetManagedObject(other) as CLRObject; + if (null == co2) + { + Runtime.XIncref(pyfalse); + return pyfalse; + } + + Object o1 = co1.inst; + Object o2 = co2.inst; + + if (Object.Equals(o1, o2)) + { + Runtime.XIncref(pytrue); + return pytrue; + } + + Runtime.XIncref(pyfalse); + return pyfalse; + case Runtime.Py_LT: + case Runtime.Py_LE: + case Runtime.Py_GT: + case Runtime.Py_GE: + co1 = GetManagedObject(ob) as CLRObject; + co2 = GetManagedObject(other) as CLRObject; + if(co1 == null || co2 == null) + return Exceptions.RaiseTypeError("Cannot get managed object"); + var co1Comp = co1.inst as IComparable; + if (co1Comp == null) + return Exceptions.RaiseTypeError("Cannot convert object of type " + co1.GetType() + " to IComparable"); + try + { + var cmp = co1Comp.CompareTo(co2.inst); + + IntPtr pyCmp; + if (cmp < 0) + { + if (op == Runtime.Py_LT || op == Runtime.Py_LE) + { + pyCmp = Runtime.PyTrue; + } + else + { + pyCmp = Runtime.PyFalse; + } + } + else if (cmp == 0) + { + if (op == Runtime.Py_LE || op == Runtime.Py_GE) + { + pyCmp = Runtime.PyTrue; + } + else + { + pyCmp = Runtime.PyFalse; + } + } + else + { + if (op == Runtime.Py_GE || op == Runtime.Py_GT) { + pyCmp = Runtime.PyTrue; + } + else { + pyCmp = Runtime.PyFalse; + } + } + Runtime.XIncref(pyCmp); + return pyCmp; + } + catch (ArgumentException e) + { + return Exceptions.RaiseTypeError(e.Message); + } + default: + Runtime.XIncref(Runtime.PyNotImplemented); + return Runtime.PyNotImplemented; } - - IntPtr pytrue = Runtime.PyTrue; - IntPtr pyfalse = Runtime.PyFalse; - - // swap true and false for NE - if (op != Runtime.Py_EQ) - { - pytrue = Runtime.PyFalse; - pyfalse = Runtime.PyTrue; - } - - if (ob == other) { - Runtime.XIncref(pytrue); - return pytrue; - } - - CLRObject co1 = GetManagedObject(ob) as CLRObject; - CLRObject co2 = GetManagedObject(other) as CLRObject; - if (null == co2) { - Runtime.XIncref(pyfalse); - return pyfalse; - } - - Object o1 = co1.inst; - Object o2 = co2.inst; - - if (Object.Equals(o1, o2)) { - Runtime.XIncref(pytrue); - return pytrue; - } - - Runtime.XIncref(pyfalse); - return pyfalse; } #else public static int tp_compare(IntPtr ob, IntPtr other) diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs index 6c9087169..e83752f9c 100644 --- a/src/runtime/runtime.cs +++ b/src/runtime/runtime.cs @@ -396,6 +396,7 @@ internal static int AtExit() internal const int Py_EQ = 2; internal const int Py_NE = 3; internal const int Py_GT = 4; + internal const int Py_GE = 5; internal static IntPtr _PyObject_NextNotImplemented; #endif diff --git a/src/tests/test_class.py b/src/tests/test_class.py index fe8fc982b..194c61b18 100644 --- a/src/tests/test_class.py +++ b/src/tests/test_class.py @@ -1,9 +1,12 @@ -from System.Collections import Hashtable -from Python.Test import ClassTest -import sys, os, string, unittest, types +import clr +import types +import unittest + import Python.Test as Test import System import six +from Python.Test import ClassTest +from System.Collections import Hashtable if six.PY3: DictProxyType = type(object.__dict__) @@ -198,6 +201,44 @@ def __setitem__(self, key, value): self.assertTrue(table.Count == 3) + def testComparisons(self): + from System import DateTimeOffset + + d1 = DateTimeOffset.Parse("2016-11-14") + d2 = DateTimeOffset.Parse("2016-11-15") + + self.assertEqual(d1 == d2, False) + self.assertEqual(d1 != d2, True) + + self.assertEqual(d1 < d2, True) + self.assertEqual(d1 <= d2, True) + self.assertEqual(d1 >= d2, False) + self.assertEqual(d1 > d2, False) + + self.assertEqual(d1 == d1, True) + self.assertEqual(d1 != d1, False) + + self.assertEqual(d1 < d1, False) + self.assertEqual(d1 <= d1, True) + self.assertEqual(d1 >= d1, True) + self.assertEqual(d1 > d1, False) + + self.assertEqual(d2 == d1, False) + self.assertEqual(d2 != d1, True) + + self.assertEqual(d2 < d1, False) + self.assertEqual(d2 <= d1, False) + self.assertEqual(d2 >= d1, True) + self.assertEqual(d2 > d1, True) + + self.assertRaises(TypeError, lambda: d1 < None) + self.assertRaises(TypeError, lambda: d1 < System.Guid()) + + # ClassTest does not implement IComparable + c1 = ClassTest() + c2 = ClassTest() + self.assertRaises(TypeError, lambda: c1 < c2) + class ClassicClass: def kind(self): From 81e9d61a112feb02145a5f7ffc43f92968b917a0 Mon Sep 17 00:00:00 2001 From: abessen Date: Wed, 16 Nov 2016 10:04:06 -0500 Subject: [PATCH 6/6] Disable tests for Python 2 --- src/tests/test_class.py | 45 +++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/src/tests/test_class.py b/src/tests/test_class.py index 194c61b18..b027ef98a 100644 --- a/src/tests/test_class.py +++ b/src/tests/test_class.py @@ -210,34 +210,39 @@ def testComparisons(self): self.assertEqual(d1 == d2, False) self.assertEqual(d1 != d2, True) - self.assertEqual(d1 < d2, True) - self.assertEqual(d1 <= d2, True) - self.assertEqual(d1 >= d2, False) - self.assertEqual(d1 > d2, False) + if six.PY3: + self.assertEqual(d1 < d2, True) + self.assertEqual(d1 <= d2, True) + self.assertEqual(d1 >= d2, False) + self.assertEqual(d1 > d2, False) self.assertEqual(d1 == d1, True) self.assertEqual(d1 != d1, False) - self.assertEqual(d1 < d1, False) - self.assertEqual(d1 <= d1, True) - self.assertEqual(d1 >= d1, True) - self.assertEqual(d1 > d1, False) + if six.PY3: + self.assertEqual(d1 < d1, False) + self.assertEqual(d1 <= d1, True) + self.assertEqual(d1 >= d1, True) + self.assertEqual(d1 > d1, False) self.assertEqual(d2 == d1, False) self.assertEqual(d2 != d1, True) - self.assertEqual(d2 < d1, False) - self.assertEqual(d2 <= d1, False) - self.assertEqual(d2 >= d1, True) - self.assertEqual(d2 > d1, True) - - self.assertRaises(TypeError, lambda: d1 < None) - self.assertRaises(TypeError, lambda: d1 < System.Guid()) - - # ClassTest does not implement IComparable - c1 = ClassTest() - c2 = ClassTest() - self.assertRaises(TypeError, lambda: c1 < c2) + if six.PY3: + self.assertEqual(d2 < d1, False) + self.assertEqual(d2 <= d1, False) + self.assertEqual(d2 >= d1, True) + self.assertEqual(d2 > d1, True) + + if six.PY3: + self.assertRaises(TypeError, lambda: d1 < None) + self.assertRaises(TypeError, lambda: d1 < System.Guid()) + + if six.PY3: + # ClassTest does not implement IComparable + c1 = ClassTest() + c2 = ClassTest() + self.assertRaises(TypeError, lambda: c1 < c2) class ClassicClass: