Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit0f33f71

Browse files
committed
disable implicit conversion from PyFloat to .NET integer types (fixes#1342)
1 parente44aa46 commit0f33f71

File tree

8 files changed

+63
-69
lines changed

8 files changed

+63
-69
lines changed

‎CHANGELOG.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ details about the cause of the failure
2828
to the regular method return value (unless they are passed with`ref` or`out` keyword).
2929
- BREAKING: Drop support for the long-deprecated CLR.* prefix.
3030
-`PyObject` now implements`IEnumerable<PyObject>` in addition to`IEnumerable`
31+
- floating point values passed from Python are no longer silently truncated
32+
when .NET expects an integer[#1342][i1342]
3133

3234
###Fixed
3335

@@ -809,3 +811,4 @@ This version improves performance on benchmarks significantly compared to 2.3.
809811
[i755]:https://github.com/pythonnet/pythonnet/pull/755
810812
[p534]:https://github.com/pythonnet/pythonnet/pull/534
811813
[i449]:https://github.com/pythonnet/pythonnet/issues/449
814+
[i1342]:https://github.com/pythonnet/pythonnet/issues/1342

‎src/runtime/Python.Runtime.csproj‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<Platforms>AnyCPU</Platforms>
55
<RootNamespace>Python.Runtime</RootNamespace>
66
<AssemblyName>Python.Runtime</AssemblyName>
7+
<LangVersion>9.0</LangVersion>
78
<PackageId>pythonnet</PackageId>
89
<PackageLicenseUrl>https://github.com/pythonnet/pythonnet/blob/master/LICENSE</PackageLicenseUrl>
910
<RepositoryUrl>https://github.com/pythonnet/pythonnet</RepositoryUrl>

‎src/runtime/arrayobject.cs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public static IntPtr tp_new(IntPtr tpRaw, IntPtr args, IntPtr kw)
5454
// create single dimensional array
5555
if(Runtime.PyInt_Check(op))
5656
{
57-
dimensions[0]=Runtime.PyLong_AsLongLong(op);
57+
dimensions[0]=Runtime.PyLong_AsSignedSize_t(op);
5858
if(dimensions[0]==-1&&Exceptions.ErrorOccurred())
5959
{
6060
Exceptions.Clear();
@@ -89,7 +89,7 @@ static NewReference CreateMultidimensional(Type elementType, long[] dimensions,
8989
returndefault;
9090
}
9191

92-
dimensions[dimIndex]=Runtime.PyLong_AsLongLong(dimObj);
92+
dimensions[dimIndex]=Runtime.PyLong_AsSignedSize_t(dimObj);
9393
if(dimensions[dimIndex]==-1&&Exceptions.ErrorOccurred())
9494
{
9595
Exceptions.RaiseTypeError("array constructor expects integer dimensions");

‎src/runtime/converter.cs‎

Lines changed: 34 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo
517517
caseTypeCode.Int32:
518518
{
519519
// Python3 always use PyLong API
520-
longnum=Runtime.PyLong_AsLongLong(value);
520+
nintnum=Runtime.PyLong_AsSignedSize_t(value);
521521
if(num==-1&&Exceptions.ErrorOccurred())
522522
{
523523
gotoconvert_error;
@@ -547,7 +547,7 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo
547547
gototype_error;
548548
}
549549

550-
intnum=Runtime.PyLong_AsLong(value);
550+
nintnum=Runtime.PyLong_AsSignedSize_t(value);
551551
if(num==-1&&Exceptions.ErrorOccurred())
552552
{
553553
gotoconvert_error;
@@ -573,7 +573,7 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo
573573
gototype_error;
574574
}
575575

576-
intnum=Runtime.PyLong_AsLong(value);
576+
nintnum=Runtime.PyLong_AsSignedSize_t(value);
577577
if(num==-1&&Exceptions.ErrorOccurred())
578578
{
579579
gotoconvert_error;
@@ -610,7 +610,7 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo
610610
}
611611
gototype_error;
612612
}
613-
intnum=Runtime.PyLong_AsLong(value);
613+
nintnum=Runtime.PyLong_AsSignedSize_t(value);
614614
if(num==-1&&Exceptions.ErrorOccurred())
615615
{
616616
gotoconvert_error;
@@ -625,7 +625,7 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo
625625

626626
caseTypeCode.Int16:
627627
{
628-
intnum=Runtime.PyLong_AsLong(value);
628+
nintnum=Runtime.PyLong_AsSignedSize_t(value);
629629
if(num==-1&&Exceptions.ErrorOccurred())
630630
{
631631
gotoconvert_error;
@@ -640,18 +640,35 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo
640640

641641
caseTypeCode.Int64:
642642
{
643-
longnum=(long)Runtime.PyLong_AsLongLong(value);
644-
if(num==-1&&Exceptions.ErrorOccurred())
643+
if(Runtime.Is32Bit)
645644
{
646-
gotoconvert_error;
645+
if(!Runtime.PyLong_Check(value))
646+
{
647+
gototype_error;
648+
}
649+
longnum=Runtime.PyExplicitlyConvertToInt64(value);
650+
if(num==-1&&Exceptions.ErrorOccurred())
651+
{
652+
gotoconvert_error;
653+
}
654+
result=num;
655+
returntrue;
656+
}
657+
else
658+
{
659+
nintnum=Runtime.PyLong_AsSignedSize_t(value);
660+
if(num==-1&&Exceptions.ErrorOccurred())
661+
{
662+
gotoconvert_error;
663+
}
664+
result=(long)num;
665+
returntrue;
647666
}
648-
result=num;
649-
returntrue;
650667
}
651668

652669
caseTypeCode.UInt16:
653670
{
654-
longnum=Runtime.PyLong_AsLong(value);
671+
nintnum=Runtime.PyLong_AsSignedSize_t(value);
655672
if(num==-1&&Exceptions.ErrorOccurred())
656673
{
657674
gotoconvert_error;
@@ -666,43 +683,16 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo
666683

667684
caseTypeCode.UInt32:
668685
{
669-
op=value;
670-
if(Runtime.PyObject_TYPE(value)!=Runtime.PyLongType)
671-
{
672-
op=Runtime.PyNumber_Long(value);
673-
if(op==IntPtr.Zero)
674-
{
675-
gotoconvert_error;
676-
}
677-
}
678-
if(Runtime.Is32Bit||Runtime.IsWindows)
686+
nuintnum=Runtime.PyLong_AsUnsignedSize_t(value);
687+
if(num==unchecked((nuint)(-1))&&Exceptions.ErrorOccurred())
679688
{
680-
uintnum=Runtime.PyLong_AsUnsignedLong32(op);
681-
if(num==uint.MaxValue&&Exceptions.ErrorOccurred())
682-
{
683-
gotoconvert_error;
684-
}
685-
result=num;
689+
gotoconvert_error;
686690
}
687-
else
691+
if(num>UInt32.MaxValue)
688692
{
689-
ulongnum=Runtime.PyLong_AsUnsignedLong64(op);
690-
if(num==ulong.MaxValue&&Exceptions.ErrorOccurred())
691-
{
692-
gotoconvert_error;
693-
}
694-
try
695-
{
696-
result=Convert.ToUInt32(num);
697-
}
698-
catch(OverflowException)
699-
{
700-
// Probably wasn't an overflow in python but was in C# (e.g. if cpython
701-
// longs are 64 bit then 0xFFFFFFFF + 1 will not overflow in
702-
// PyLong_AsUnsignedLong)
703-
gotooverflow;
704-
}
693+
gotooverflow;
705694
}
695+
result=(uint)num;
706696
returntrue;
707697
}
708698

‎src/runtime/pylong.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ public int ToInt32()
246246
/// </remarks>
247247
publiclongToInt64()
248248
{
249-
returnRuntime.PyLong_AsLongLong(obj);
249+
returnRuntime.PyExplicitlyConvertToInt64(obj);
250250
}
251251
}
252252
}

‎src/runtime/runtime.cs‎

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,30 +1254,27 @@ internal static IntPtr PyLong_FromUnsignedLong(object value)
12541254
[DllImport(_PythonDll, CallingConvention= CallingConvention.Cdecl)]
12551255
internalstaticextern IntPtr PyLong_FromString(string value, IntPtr end,int radix);
12561256

1257-
[DllImport(_PythonDll, CallingConvention= CallingConvention.Cdecl)]
1258-
internalstaticexternint PyLong_AsLong(IntPtr value);
1259-
12601257
[DllImport(_PythonDll, CallingConvention= CallingConvention.Cdecl,
1261-
EntryPoint= "PyLong_AsUnsignedLong")]
1262-
internalstaticexternuint PyLong_AsUnsignedLong32(IntPtr value);
1263-
1258+
EntryPoint= "PyLong_AsSize_t")]
1259+
internalstaticexternnuint PyLong_AsUnsignedSize_t(IntPtr value);
12641260
[DllImport(_PythonDll, CallingConvention= CallingConvention.Cdecl,
1265-
EntryPoint= "PyLong_AsUnsignedLong")]
1266-
internalstaticexternulong PyLong_AsUnsignedLong64(IntPtr value);
1267-
1268-
internalstaticobject PyLong_AsUnsignedLong(IntPtr value)
1269-
{
1270-
if(Is32Bit|| IsWindows)
1271-
return PyLong_AsUnsignedLong32(value);
1272-
else
1273-
return PyLong_AsUnsignedLong64(value);
1274-
}
1275-
1276-
[DllImport(_PythonDll, CallingConvention= CallingConvention.Cdecl)]
1277-
internalstaticexternlong PyLong_AsLongLong(BorrowedReference value);
1278-
[DllImport(_PythonDll, CallingConvention= CallingConvention.Cdecl)]
1279-
internalstaticexternlong PyLong_AsLongLong(IntPtr value);
1261+
EntryPoint= "PyLong_AsSsize_t")]
1262+
internalstaticexternnint PyLong_AsSignedSize_t(IntPtr value);
1263+
[DllImport(_PythonDll, CallingConvention= CallingConvention.Cdecl,
1264+
EntryPoint= "PyLong_AsSsize_t")]
1265+
internalstaticexternnint PyLong_AsSignedSize_t(BorrowedReference value);
12801266

1267+
/// <summary>
1268+
/// This function is a rename of PyLong_AsLongLong, which has a commonly undesired
1269+
/// behavior to convert everything (including floats) to integer type, before returning
1270+
/// the value as <see cref="Int64"/>.
1271+
///
1272+
/// <para>In most cases you need to check that value is an instance of PyLongObject
1273+
/// before using this function using <see cref="PyLong_Check(IntPtr)"/>.</para>
1274+
/// </summary>
1275+
[DllImport(_PythonDll, CallingConvention= CallingConvention.Cdecl,
1276+
EntryPoint= "PyLong_AsLongLong")]
1277+
internalstaticexternlong PyExplicitlyConvertToInt64(IntPtr value);
12811278
[DllImport(_PythonDll, CallingConvention= CallingConvention.Cdecl)]
12821279
internalstaticexternulong PyLong_AsUnsignedLongLong(IntPtr value);
12831280

‎src/tests/test_conversion.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ def test_uint32_conversion():
343343
ob.UInt32Field=System.UInt32(0)
344344
assertob.UInt32Field==0
345345

346-
withpytest.raises(ValueError):
346+
withpytest.raises(TypeError):
347347
ConversionTest().UInt32Field="spam"
348348

349349
withpytest.raises(TypeError):

‎src/tests/test_method.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,9 @@ def test_no_object_in_param():
807807
withpytest.raises(TypeError):
808808
MethodTest.TestOverloadedNoObject("test")
809809

810+
withpytest.raises(TypeError):
811+
MethodTest.TestOverloadedNoObject(5.5)
812+
810813

811814
deftest_object_in_param():
812815
"""Test regression introduced by #151 in which Object method overloads

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp