diff --git a/CHANGELOG.md b/CHANGELOG.md index 069629021..3e6ab3731 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,8 @@ details about the cause of the failure able to access members that are part of the implementation class, but not the interface. Use the new `__implementation__` or `__raw_implementation__` properties to if you need to "downcast" to the implementation class. +- BREAKING: `==` and `!=` operators on `PyObject` instances now use Python comparison + (previously was equivalent to `object.ReferenceEquals(,)`) - BREAKING: Parameters marked with `ParameterAttributes.Out` are no longer returned in addition to the regular method return value (unless they are passed with `ref` or `out` keyword). - BREAKING: Drop support for the long-deprecated CLR.* prefix. diff --git a/src/embed_tests/dynamic.cs b/src/embed_tests/dynamic.cs index 0a181231c..6e3bfc4cb 100644 --- a/src/embed_tests/dynamic.cs +++ b/src/embed_tests/dynamic.cs @@ -128,6 +128,28 @@ public void PassPyObjectInNet() Assert.IsTrue(sys.testattr1.Equals(sys.testattr2)); } + // regression test for https://github.com/pythonnet/pythonnet/issues/1848 + [Test] + public void EnumEquality() + { + using var scope = Py.CreateScope(); + scope.Exec(@" +import enum + +class MyEnum(enum.IntEnum): + OK = 1 + ERROR = 2 + +def get_status(): + return MyEnum.OK +" +); + + dynamic MyEnum = scope.Get("MyEnum"); + dynamic status = scope.Get("get_status").Invoke(); + Assert.IsTrue(status == MyEnum.OK); + } + // regression test for https://github.com/pythonnet/pythonnet/issues/1680 [Test] public void ForEach() diff --git a/src/runtime/PythonTypes/PyObject.cs b/src/runtime/PythonTypes/PyObject.cs index cfd3e7158..3d48e22ed 100644 --- a/src/runtime/PythonTypes/PyObject.cs +++ b/src/runtime/PythonTypes/PyObject.cs @@ -1075,12 +1075,9 @@ public virtual bool Equals(PyObject? other) { return true; } - int r = Runtime.PyObject_Compare(this, other); - if (Exceptions.ErrorOccurred()) - { - throw PythonException.ThrowLastAsClrException(); - } - return r == 0; + int result = Runtime.PyObject_RichCompareBool(obj, other.obj, Runtime.Py_EQ); + if (result < 0) throw PythonException.ThrowLastAsClrException(); + return result != 0; } @@ -1304,6 +1301,18 @@ public override bool TryConvert(ConvertBinder binder, out object? result) return false; } + private bool TryCompare(PyObject arg, int op, out object @out) + { + int result = Runtime.PyObject_RichCompareBool(this.obj, arg.obj, op); + @out = result != 0; + if (result < 0) + { + Exceptions.Clear(); + return false; + } + return true; + } + public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object? result) { using var _ = Py.GIL(); @@ -1352,11 +1361,9 @@ public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg res = Runtime.PyNumber_InPlaceXor(this.obj, ((PyObject)arg).obj); break; case ExpressionType.GreaterThan: - result = Runtime.PyObject_Compare(this.obj, ((PyObject)arg).obj) > 0; - return true; + return this.TryCompare((PyObject)arg, Runtime.Py_GT, out result); case ExpressionType.GreaterThanOrEqual: - result = Runtime.PyObject_Compare(this.obj, ((PyObject)arg).obj) >= 0; - return true; + return this.TryCompare((PyObject)arg, Runtime.Py_GE, out result); case ExpressionType.LeftShift: res = Runtime.PyNumber_Lshift(this.obj, ((PyObject)arg).obj); break; @@ -1364,11 +1371,9 @@ public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg res = Runtime.PyNumber_InPlaceLshift(this.obj, ((PyObject)arg).obj); break; case ExpressionType.LessThan: - result = Runtime.PyObject_Compare(this.obj, ((PyObject)arg).obj) < 0; - return true; + return this.TryCompare((PyObject)arg, Runtime.Py_LT, out result); case ExpressionType.LessThanOrEqual: - result = Runtime.PyObject_Compare(this.obj, ((PyObject)arg).obj) <= 0; - return true; + return this.TryCompare((PyObject)arg, Runtime.Py_LE, out result); case ExpressionType.Modulo: res = Runtime.PyNumber_Remainder(this.obj, ((PyObject)arg).obj); break; @@ -1376,8 +1381,9 @@ public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg res = Runtime.PyNumber_InPlaceRemainder(this.obj, ((PyObject)arg).obj); break; case ExpressionType.NotEqual: - result = Runtime.PyObject_Compare(this.obj, ((PyObject)arg).obj) != 0; - return true; + return this.TryCompare((PyObject)arg, Runtime.Py_NE, out result); + case ExpressionType.Equal: + return this.TryCompare((PyObject)arg, Runtime.Py_EQ, out result); case ExpressionType.Or: res = Runtime.PyNumber_Or(this.obj, ((PyObject)arg).obj); break; @@ -1402,6 +1408,40 @@ public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg return true; } + public static bool operator ==(PyObject? a, PyObject? b) + { + if (a is null && b is null) + { + return true; + } + if (a is null || b is null) + { + return false; + } + + using var _ = Py.GIL(); + int result = Runtime.PyObject_RichCompareBool(a.obj, b.obj, Runtime.Py_EQ); + if (result < 0) throw PythonException.ThrowLastAsClrException(); + return result != 0; + } + + public static bool operator !=(PyObject? a, PyObject? b) + { + if (a is null && b is null) + { + return false; + } + if (a is null || b is null) + { + return true; + } + + using var _ = Py.GIL(); + int result = Runtime.PyObject_RichCompareBool(a.obj, b.obj, Runtime.Py_NE); + if (result < 0) throw PythonException.ThrowLastAsClrException(); + return result != 0; + } + // Workaround for https://bugzilla.xamarin.com/show_bug.cgi?id=41509 // See https://github.com/pythonnet/pythonnet/pull/219 internal static object? CheckNone(PyObject pyObj) @@ -1436,14 +1476,17 @@ public override bool TryUnaryOperation(UnaryOperationBinder binder, out object? case ExpressionType.Not: r = Runtime.PyObject_Not(this.obj); result = r == 1; + if (r == -1) Exceptions.Clear(); return r != -1; case ExpressionType.IsFalse: r = Runtime.PyObject_IsTrue(this.obj); result = r == 0; + if (r == -1) Exceptions.Clear(); return r != -1; case ExpressionType.IsTrue: r = Runtime.PyObject_IsTrue(this.obj); result = r == 1; + if (r == -1) Exceptions.Clear(); return r != -1; case ExpressionType.Decrement: case ExpressionType.Increment: diff --git a/src/runtime/Runtime.cs b/src/runtime/Runtime.cs index 6ad1d459f..1eeb96b54 100644 --- a/src/runtime/Runtime.cs +++ b/src/runtime/Runtime.cs @@ -962,31 +962,6 @@ internal static IntPtr PyObject_CallObject(IntPtr pointer, IntPtr args) internal static int PyObject_RichCompareBool(BorrowedReference value1, BorrowedReference value2, int opid) => Delegates.PyObject_RichCompareBool(value1, value2, opid); - internal static int PyObject_Compare(BorrowedReference value1, BorrowedReference value2) - { - int res; - res = PyObject_RichCompareBool(value1, value2, Py_LT); - if (-1 == res) - return -1; - else if (1 == res) - return -1; - - res = PyObject_RichCompareBool(value1, value2, Py_EQ); - if (-1 == res) - return -1; - else if (1 == res) - return 0; - - res = PyObject_RichCompareBool(value1, value2, Py_GT); - if (-1 == res) - return -1; - else if (1 == res) - return 1; - - Exceptions.SetError(Exceptions.SystemError, "Error comparing objects"); - return -1; - } - internal static int PyObject_IsInstance(BorrowedReference ob, BorrowedReference type) => Delegates.PyObject_IsInstance(ob, type); pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy