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

Commitefe84c2

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

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
@@ -27,6 +27,8 @@ details about the cause of the failure
2727
to the regular method return value (unless they are passed with`ref` or`out` keyword).
2828
- BREAKING: Drop support for the long-deprecated CLR.* prefix.
2929
-`PyObject` now implements`IEnumerable<PyObject>` in addition to`IEnumerable`
30+
- floating point values passed from Python are no longer silently truncated
31+
when .NET expects an integer[#1342][i1342]
3032

3133
###Fixed
3234

@@ -807,3 +809,4 @@ This version improves performance on benchmarks significantly compared to 2.3.
807809
[i755]:https://github.com/pythonnet/pythonnet/pull/755
808810
[p534]:https://github.com/pythonnet/pythonnet/pull/534
809811
[i449]:https://github.com/pythonnet/pythonnet/issues/449
812+
[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
@@ -49,7 +49,7 @@ public static IntPtr tp_new(IntPtr tpRaw, IntPtr args, IntPtr kw)
4949
// create single dimensional array
5050
if(Runtime.PyInt_Check(op))
5151
{
52-
dimensions[0]=Runtime.PyLong_AsLongLong(op);
52+
dimensions[0]=Runtime.PyLong_AsSignedSize_t(op);
5353
if(dimensions[0]==-1&&Exceptions.ErrorOccurred())
5454
{
5555
Exceptions.Clear();
@@ -84,7 +84,7 @@ static NewReference CreateMultidimensional(Type elementType, long[] dimensions,
8484
returndefault;
8585
}
8686

87-
dimensions[dimIndex]=Runtime.PyLong_AsLongLong(dimObj);
87+
dimensions[dimIndex]=Runtime.PyLong_AsSignedSize_t(dimObj);
8888
if(dimensions[dimIndex]==-1&&Exceptions.ErrorOccurred())
8989
{
9090
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
@@ -511,7 +511,7 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo
511511
caseTypeCode.Int32:
512512
{
513513
// Python3 always use PyLong API
514-
longnum=Runtime.PyLong_AsLongLong(value);
514+
nintnum=Runtime.PyLong_AsSignedSize_t(value);
515515
if(num==-1&&Exceptions.ErrorOccurred())
516516
{
517517
gotoconvert_error;
@@ -541,7 +541,7 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo
541541
gototype_error;
542542
}
543543

544-
intnum=Runtime.PyLong_AsLong(value);
544+
nintnum=Runtime.PyLong_AsSignedSize_t(value);
545545
if(num==-1&&Exceptions.ErrorOccurred())
546546
{
547547
gotoconvert_error;
@@ -567,7 +567,7 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo
567567
gototype_error;
568568
}
569569

570-
intnum=Runtime.PyLong_AsLong(value);
570+
nintnum=Runtime.PyLong_AsSignedSize_t(value);
571571
if(num==-1&&Exceptions.ErrorOccurred())
572572
{
573573
gotoconvert_error;
@@ -604,7 +604,7 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo
604604
}
605605
gototype_error;
606606
}
607-
intnum=Runtime.PyLong_AsLong(value);
607+
nintnum=Runtime.PyLong_AsSignedSize_t(value);
608608
if(num==-1&&Exceptions.ErrorOccurred())
609609
{
610610
gotoconvert_error;
@@ -619,7 +619,7 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo
619619

620620
caseTypeCode.Int16:
621621
{
622-
intnum=Runtime.PyLong_AsLong(value);
622+
nintnum=Runtime.PyLong_AsSignedSize_t(value);
623623
if(num==-1&&Exceptions.ErrorOccurred())
624624
{
625625
gotoconvert_error;
@@ -634,18 +634,35 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo
634634

635635
caseTypeCode.Int64:
636636
{
637-
longnum=(long)Runtime.PyLong_AsLongLong(value);
638-
if(num==-1&&Exceptions.ErrorOccurred())
637+
if(Runtime.Is32Bit)
639638
{
640-
gotoconvert_error;
639+
if(!Runtime.PyLong_Check(value))
640+
{
641+
gototype_error;
642+
}
643+
longnum=Runtime.PyExplicitlyConvertToInt64(value);
644+
if(num==-1&&Exceptions.ErrorOccurred())
645+
{
646+
gotoconvert_error;
647+
}
648+
result=num;
649+
returntrue;
650+
}
651+
else
652+
{
653+
nintnum=Runtime.PyLong_AsSignedSize_t(value);
654+
if(num==-1&&Exceptions.ErrorOccurred())
655+
{
656+
gotoconvert_error;
657+
}
658+
result=(long)num;
659+
returntrue;
641660
}
642-
result=num;
643-
returntrue;
644661
}
645662

646663
caseTypeCode.UInt16:
647664
{
648-
longnum=Runtime.PyLong_AsLong(value);
665+
nintnum=Runtime.PyLong_AsSignedSize_t(value);
649666
if(num==-1&&Exceptions.ErrorOccurred())
650667
{
651668
gotoconvert_error;
@@ -660,43 +677,16 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo
660677

661678
caseTypeCode.UInt32:
662679
{
663-
op=value;
664-
if(Runtime.PyObject_TYPE(value)!=Runtime.PyLongType)
665-
{
666-
op=Runtime.PyNumber_Long(value);
667-
if(op==IntPtr.Zero)
668-
{
669-
gotoconvert_error;
670-
}
671-
}
672-
if(Runtime.Is32Bit||Runtime.IsWindows)
680+
nuintnum=Runtime.PyLong_AsUnsignedSize_t(value);
681+
if(num==unchecked((nuint)(-1))&&Exceptions.ErrorOccurred())
673682
{
674-
uintnum=Runtime.PyLong_AsUnsignedLong32(op);
675-
if(num==uint.MaxValue&&Exceptions.ErrorOccurred())
676-
{
677-
gotoconvert_error;
678-
}
679-
result=num;
683+
gotoconvert_error;
680684
}
681-
else
685+
if(num>UInt32.MaxValue)
682686
{
683-
ulongnum=Runtime.PyLong_AsUnsignedLong64(op);
684-
if(num==ulong.MaxValue&&Exceptions.ErrorOccurred())
685-
{
686-
gotoconvert_error;
687-
}
688-
try
689-
{
690-
result=Convert.ToUInt32(num);
691-
}
692-
catch(OverflowException)
693-
{
694-
// Probably wasn't an overflow in python but was in C# (e.g. if cpython
695-
// longs are 64 bit then 0xFFFFFFFF + 1 will not overflow in
696-
// PyLong_AsUnsignedLong)
697-
gotooverflow;
698-
}
687+
gotooverflow;
699688
}
689+
result=(uint)num;
700690
returntrue;
701691
}
702692

‎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
@@ -1251,30 +1251,27 @@ internal static IntPtr PyLong_FromUnsignedLong(object value)
12511251
[DllImport(_PythonDll, CallingConvention= CallingConvention.Cdecl)]
12521252
internalstaticextern IntPtr PyLong_FromString(string value, IntPtr end,int radix);
12531253

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

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

‎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