Skip to content

Commit 2fde197

Browse files
committed
Tighten comments in float-like integer conversion guard and tests
1 parent 1d5bffb commit 2fde197

3 files changed

Lines changed: 11 additions & 27 deletions

File tree

src/embed_tests/TestFloatToIntConversion.cs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,7 @@ public void NonIntegralFloat_IsRejected(string func)
124124
Assert.AreEqual("TypeError", ex.Type.Name);
125125
}
126126

127-
// A float subclass (e.g. numpy.float64) follows the same rule as a plain
128-
// float: integral values convert, fractional ones are rejected instead of
129-
// being silently truncated through __int__.
127+
// Float subclasses (e.g. numpy.float64) follow the plain-float rule.
130128
[TestCase("single_ctor_float_subclass")]
131129
[TestCase("overloaded_ctor_float_subclass")]
132130
public void IntegralFloatSubclass_IsAccepted(string func)
@@ -142,9 +140,7 @@ public void NonIntegralFloatSubclass_IsRejected(string func)
142140
Assert.AreEqual("TypeError", ex.Type.Name);
143141
}
144142

145-
// A number that defines __float__ but no __index__ (e.g. numpy.float32) is
146-
// float-like: integral values convert, fractional ones are rejected instead
147-
// of being silently truncated through __int__.
143+
// __float__-only numbers (e.g. numpy.float32) follow the plain-float rule.
148144
[TestCase("single_ctor_float_like")]
149145
[TestCase("overloaded_ctor_float_like")]
150146
public void IntegralFloatLike_IsAccepted(string func)
@@ -160,8 +156,7 @@ public void NonIntegralFloatLike_IsRejected(string func)
160156
Assert.AreEqual("TypeError", ex.Type.Name);
161157
}
162158

163-
// A true integer type advertising __index__ (e.g. numpy.int64) is not
164-
// float-like and keeps converting even though it also defines __float__.
159+
// __index__ types (e.g. numpy.int64) are integers, not float-like.
165160
[Test]
166161
public void IndexLike_IsAccepted()
167162
{

src/runtime/Converter.cs

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -908,16 +908,13 @@ internal static int ToInt32(BorrowedReference value)
908908
}
909909

910910
/// <summary>
911-
/// Determines whether a Python value is a floating-point number: a Python
912-
/// float (including subclasses such as numpy.float64) or a number that
913-
/// defines a float conversion but no lossless integer conversion
914-
/// (__float__ without __index__, e.g. numpy.float32). Integer values,
915-
/// including bools and types with __index__ such as numpy.int64, are not
916-
/// float-like.
911+
/// True for Python floats (including subclasses like numpy.float64) and for
912+
/// numbers with __float__ but no __index__ (like numpy.float32); __index__
913+
/// marks a type as losslessly int-convertible, so those are not float-like.
917914
/// </summary>
918915
private static bool IsFloatLike(BorrowedReference value)
919916
{
920-
// The common case for integer parameters is an actual int; exit fast.
917+
// fast path for the common case: actual ints
921918
if (Runtime.PyInt_Check(value) || Runtime.PyBool_Check(value))
922919
{
923920
return false;
@@ -943,20 +940,14 @@ internal static bool ToPrimitive(BorrowedReference value, Type obType, out objec
943940

944941
TypeCode tc = Type.GetTypeCode(obType);
945942

946-
// A float-like value with a fractional part must not be silently truncated
947-
// into an integer parameter. Integral-valued ones (e.g. 5.0) are still
948-
// accepted. Besides Python floats this covers float subclasses such as
949-
// numpy.float64 and __float__-only numbers such as numpy.float32, which
950-
// would otherwise be truncated below through PyNumber_Long/__int__.
951-
// This keeps single- and multi-overload binding consistent: MethodBinder
952-
// only treats integral floats as candidates for integer parameters, and
953-
// this guard enforces the same rule at conversion time.
943+
// Reject non-integral float-like values (incl. numpy floats) for integer
944+
// targets; the PyNumber_Long path below would silently truncate them.
954945
if (tc.IsInteger() && IsFloatLike(value))
955946
{
956947
double dbl = Runtime.PyFloat_AsDouble(value);
957948
if (dbl == -1.0 && Exceptions.ErrorOccurred())
958949
{
959-
// __float__ itself failed; don't let the probe error leak
950+
// don't let a failed __float__ probe leak
960951
Exceptions.Clear();
961952
goto type_error;
962953
}

tests/test_conversion.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -268,9 +268,7 @@ def test_int64_conversion():
268268

269269

270270
def test_numpy_float_to_int_conversion():
271-
"""A numpy float with a fractional value is rejected for integer targets
272-
instead of being silently truncated; integral-valued numpy floats convert.
273-
Numpy integer scalars are unaffected."""
271+
"""Non-integral numpy floats are rejected for integer targets, not truncated."""
274272
np = pytest.importorskip("numpy")
275273

276274
ob = ConversionTest()

0 commit comments

Comments
 (0)