Skip to content

Commit 159e0dd

Browse files
committed
Allow implicit safe conversion to System.Double/Single in method calls
Checking the exact type beforehand is unnecessary and `AsDouble` will check whether `__float__` is available and call it. This is not yet supported for integer types, which would use `__int__` or `__index__` (for Python >=3.10), as the respective logic is for some reason only implemented for `AsLongLong` and `AsLong`, not for the unsigned counterparts and also not for the `AsSize_t` variants that we are using.
1 parent bd48dc1 commit 159e0dd

File tree

2 files changed

+27
-10
lines changed

2 files changed

+27
-10
lines changed

src/runtime/Converter.cs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -777,12 +777,8 @@ internal static bool ToPrimitive(BorrowedReference value, Type obType, out objec
777777

778778
case TypeCode.Single:
779779
{
780-
if (!Runtime.PyFloat_Check(value) && !Runtime.PyInt_Check(value))
781-
{
782-
goto type_error;
783-
}
784780
double num = Runtime.PyFloat_AsDouble(value);
785-
if (num == -1.0 && Exceptions.ErrorOccurred())
781+
if (Exceptions.ErrorOccurred())
786782
{
787783
goto convert_error;
788784
}
@@ -799,12 +795,8 @@ internal static bool ToPrimitive(BorrowedReference value, Type obType, out objec
799795

800796
case TypeCode.Double:
801797
{
802-
if (!Runtime.PyFloat_Check(value) && !Runtime.PyInt_Check(value))
803-
{
804-
goto type_error;
805-
}
806798
double num = Runtime.PyFloat_AsDouble(value);
807-
if (num == -1.0 && Exceptions.ErrorOccurred())
799+
if (Exceptions.ErrorOccurred())
808800
{
809801
goto convert_error;
810802
}

tests/test_method.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,3 +1256,28 @@ def test_method_encoding():
12561256
def test_method_with_pointer_array_argument():
12571257
with pytest.raises(TypeError):
12581258
MethodTest.PointerArray([0])
1259+
1260+
def test_method_call_implicit_conversion():
1261+
1262+
class Answer:
1263+
# For Python >= 3.8
1264+
def __index__(self):
1265+
return 42
1266+
1267+
# For Python < 3.10
1268+
def __int__(self):
1269+
return 42
1270+
1271+
class FloatAnswer(Answer):
1272+
def __float__(self):
1273+
return 42.0
1274+
1275+
# TODO: This should also work for integer types but due to some complexities
1276+
# in the C-API functions (some call __int__/__index__, some don't), it's not
1277+
# supported, yet.
1278+
for v in [Answer(), FloatAnswer()]:
1279+
for t in [System.Double, System.Single]:
1280+
min_value = t(t.MinValue)
1281+
compare_to = min_value.CompareTo.__overloads__[t]
1282+
1283+
assert compare_to(v) == -1

0 commit comments

Comments
 (0)