From a02799d5d2cafb89f00b3a7a57c0c609914420c2 Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Mon, 19 Sep 2022 18:03:38 +0200 Subject: [PATCH 1/2] Fix implicit float conversion for classes that derive from float --- src/runtime/Runtime.cs | 4 +--- tests/test_method.py | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/runtime/Runtime.cs b/src/runtime/Runtime.cs index 4dc904f43..d09c89e2c 100644 --- a/src/runtime/Runtime.cs +++ b/src/runtime/Runtime.cs @@ -1145,9 +1145,7 @@ internal static NewReference PyLong_FromString(string value, int radix) } internal static bool PyFloat_Check(BorrowedReference ob) - { - return PyObject_TYPE(ob) == PyFloatType; - } + => PyObject_TypeCheck(ob, PyFloatType); /// /// Return value: New reference. diff --git a/tests/test_method.py b/tests/test_method.py index b24b525aa..b86bbd6b4 100644 --- a/tests/test_method.py +++ b/tests/test_method.py @@ -1256,3 +1256,41 @@ def test_method_encoding(): def test_method_with_pointer_array_argument(): with pytest.raises(TypeError): MethodTest.PointerArray([0]) + +def test_method_call_implicit_conversion(): + + class IntAnswerMixin: + # For Python >= 3.8 + def __index__(self): + return 42 + + # For Python < 3.10 + def __int__(self): + return 42 + + class Answer(int, IntAnswerMixin): + pass + + class FloatAnswer(float, IntAnswerMixin): + def __float__(self): + return 42.0 + + # TODO: This should also work for integer types but due to some complexities + # in the C-API functions (some call __int__/__index__, some don't), it's not + # supported, yet. + for v in [Answer(), FloatAnswer()]: + for t in [System.Double, System.Single]: + min_value = t(t.MinValue) + compare_to = min_value.CompareTo.__overloads__[t] + + assert compare_to(v) == -1 + + class SomeNonFloat: + def __float__(self): + return 42.0 + + for t in [System.Double, System.Single]: + with pytest.raises(TypeError): + min_value = t(t.MinValue) + compare_to = min_value.CompareTo.__overloads__[t] + assert compare_to(SomeNonFloat()) == -1 From 2194d6c3ee392b85825c01d134dbd68e7e91fc39 Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Mon, 19 Sep 2022 18:04:14 +0200 Subject: [PATCH 2/2] Drop PyLong_Check (which checked for exact type) in favour of PyInt_Check (which checks for subtype) --- src/runtime/Converter.cs | 2 +- src/runtime/Runtime.cs | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/runtime/Converter.cs b/src/runtime/Converter.cs index 2e0edc3b5..3c46e9034 100644 --- a/src/runtime/Converter.cs +++ b/src/runtime/Converter.cs @@ -710,7 +710,7 @@ internal static bool ToPrimitive(BorrowedReference value, Type obType, out objec { if (Runtime.Is32Bit) { - if (!Runtime.PyLong_Check(value)) + if (!Runtime.PyInt_Check(value)) { goto type_error; } diff --git a/src/runtime/Runtime.cs b/src/runtime/Runtime.cs index d09c89e2c..6238119ff 100644 --- a/src/runtime/Runtime.cs +++ b/src/runtime/Runtime.cs @@ -1101,11 +1101,6 @@ internal static bool PyBool_Check(BorrowedReference ob) internal static NewReference PyInt_FromInt64(long value) => PyLong_FromLongLong(value); - internal static bool PyLong_Check(BorrowedReference ob) - { - return PyObject_TYPE(ob) == PyLongType; - } - internal static NewReference PyLong_FromLongLong(long value) => Delegates.PyLong_FromLongLong(value);