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

Commit26add1e

Browse files
committed
disabled using __float__ during implicit conversions to .NET floating point types
arbitrary Python objects are no longer implicitly converted to .NET bool typethis is a continuation of#1568
1 parent8d93c39 commit26add1e

File tree

6 files changed

+95
-4
lines changed

6 files changed

+95
-4
lines changed

‎CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ See [Mixins/collections.py](src/runtime/Mixins/collections.py).
7171
- BREAKING: When trying to convert Python`int` to`System.Object`, result will
7272
be of type`PyInt` instead of`System.Int32` due to possible loss of information.
7373
Python`float` will continue to be converted to`System.Double`.
74+
- BREAKING: Python.NET will no longer implicitly convert types like`numpy.float64`, that implement`__float__` to
75+
`System.Single` and`System.Double`. An explicit conversion is required on Python or .NET side.
76+
- BREAKING: Python.NET will no longer implicitly convert any Python object to`System.Boolean`.
7477
- BREAKING:`PyObject.GetAttr(name, default)` now only ignores`AttributeError` (previously ignored all exceptions).
7578
- BREAKING:`PyObject` no longer implements`IEnumerable<PyObject>`.
7679
Instead,`PyIterable` does that.

‎README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ Example
7777
dynamicsin=np.sin;
7878
Console.WriteLine(sin(5));
7979
80-
doublec=np.cos(5)+sin(5);
80+
doublec=(double)(np.cos(5)+sin(5));
8181
Console.WriteLine(c);
8282
8383
dynamica=np.array(newList<float> {1,2,3 });

‎src/embed_tests/NumPyTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public void TestReadme()
4040
dynamicsin=np.sin;
4141
StringAssert.StartsWith("-0.95892",sin(5).ToString());
4242

43-
doublec=np.cos(5)+sin(5);
43+
doublec=(double)(np.cos(5)+sin(5));
4444
Assert.AreEqual(-0.675262,c,0.01);
4545

4646
dynamica=np.array(newList<float>{1,2,3});

‎src/embed_tests/TestConverter.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,13 @@ public void ConvertOverflow()
116116
}
117117
}
118118

119+
[Test]
120+
publicvoidNoImplicitConversionToBool()
121+
{
122+
varpyObj=newPyList(items:new[]{1.ToPython(),2.ToPython()}).ToPython();
123+
Assert.Throws<InvalidCastException>(()=>pyObj.As<bool>());
124+
}
125+
119126
[Test]
120127
publicvoidToNullable()
121128
{

‎src/runtime/converter.cs

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
usingSystem;
33
usingSystem.Collections;
44
usingSystem.Collections.Generic;
5+
usingSystem.Diagnostics;
56
usingSystem.Globalization;
67
usingSystem.Reflection;
78
usingSystem.Runtime.InteropServices;
@@ -501,6 +502,44 @@ internal static bool ToManagedValue(IntPtr value, Type obType,
501502
returnToPrimitive(value,obType,outresult,setError);
502503
}
503504

505+
/// <remarks>
506+
/// Unlike <see cref="ToManaged(BorrowedReference, Type, out object?, bool)"/>,
507+
/// this method does not have a <c>setError</c> parameter, because it should
508+
/// only be called after <see cref="ToManaged(BorrowedReference, Type, out object?, bool)"/>.
509+
/// </remarks>
510+
internalstaticboolToManagedExplicit(BorrowedReferencevalue,TypeobType,
511+
outobject?result)
512+
{
513+
result=null;
514+
515+
// this method would potentially clean any existing error resulting in information loss
516+
Debug.Assert(Runtime.PyErr_Occurred()==null);
517+
518+
string?converterName=
519+
IsInteger(obType)?"__int__"
520+
:IsFloatingNumber(obType)?"__float__"
521+
:null;
522+
523+
if(converterNameisnull)returnfalse;
524+
525+
Debug.Assert(obType.IsPrimitive);
526+
527+
usingvarconverter=Runtime.PyObject_GetAttrString(value,converterName);
528+
if(converter.IsNull())
529+
{
530+
Exceptions.Clear();
531+
returnfalse;
532+
}
533+
534+
usingvarexplicitlyCoerced=Runtime.PyObject_CallObject(converter,BorrowedReference.Null);
535+
if(explicitlyCoerced.IsNull())
536+
{
537+
Exceptions.Clear();
538+
returnfalse;
539+
}
540+
returnToPrimitive(explicitlyCoerced,obType,outresult,false);
541+
}
542+
504543
staticobject?ToPyObjectSubclass(ConstructorInfoctor,PyObjectinstance,boolsetError)
505544
{
506545
try
@@ -544,6 +583,8 @@ internal static int ToInt32(BorrowedReference value)
544583
returnchecked((int)num);
545584
}
546585

586+
privatestaticboolToPrimitive(BorrowedReferencevalue,TypeobType,outobject?result,boolsetError)
587+
=>ToPrimitive(value.DangerousGetAddress(),obType,outresult,setError);
547588
/// <summary>
548589
/// Convert a Python value to an instance of a primitive managed type.
549590
/// </summary>
@@ -590,7 +631,18 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object? result, b
590631
}
591632

592633
caseTypeCode.Boolean:
593-
result=Runtime.PyObject_IsTrue(value)!=0;
634+
if(value==Runtime.PyTrue)
635+
{
636+
result=true;
637+
}
638+
elseif(value==Runtime.PyFalse)
639+
{
640+
result=false;
641+
}
642+
elseif(setError)
643+
{
644+
gototype_error;
645+
}
594646
returntrue;
595647

596648
caseTypeCode.Byte:
@@ -768,6 +820,10 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object? result, b
768820

769821
caseTypeCode.Single:
770822
{
823+
if(!Runtime.PyFloat_Check(value)&&!Runtime.PyInt_Check(value))
824+
{
825+
gototype_error;
826+
}
771827
doublenum=Runtime.PyFloat_AsDouble(value);
772828
if(num==-1.0&&Exceptions.ErrorOccurred())
773829
{
@@ -786,6 +842,10 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object? result, b
786842

787843
caseTypeCode.Double:
788844
{
845+
if(!Runtime.PyFloat_Check(value)&&!Runtime.PyInt_Check(value))
846+
{
847+
gototype_error;
848+
}
789849
doublenum=Runtime.PyFloat_AsDouble(value);
790850
if(num==-1.0&&Exceptions.ErrorOccurred())
791851
{
@@ -933,6 +993,13 @@ private static bool ToArray(IntPtr value, Type obType, out object? result, bool
933993
result=items;
934994
returntrue;
935995
}
996+
997+
internalstaticboolIsFloatingNumber(Typetype)=>type==typeof(float)||type==typeof(double);
998+
internalstaticboolIsInteger(Typetype)
999+
=>type==typeof(Byte)||type==typeof(SByte)
1000+
||type==typeof(Int16)||type==typeof(UInt16)
1001+
||type==typeof(Int32)||type==typeof(UInt32)
1002+
||type==typeof(Int64)||type==typeof(UInt64);
9361003
}
9371004

9381005
publicstaticclassConverterExtension

‎src/runtime/pyobject.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1293,7 +1293,21 @@ public override bool TryInvoke(InvokeBinder binder, object[] args, out object re
12931293

12941294
publicoverrideboolTryConvert(ConvertBinderbinder,outobjectresult)
12951295
{
1296-
returnConverter.ToManaged(this.obj,binder.Type,outresult,false);
1296+
// always try implicit conversion first
1297+
if(Converter.ToManaged(this.obj,binder.Type,outresult,false))
1298+
{
1299+
returntrue;
1300+
}
1301+
1302+
if(binder.Explicit)
1303+
{
1304+
Runtime.PyErr_Fetch(outvarerrType,outvarerrValue,outvartb);
1305+
boolconverted=Converter.ToManagedExplicit(Reference,binder.Type,outresult);
1306+
Runtime.PyErr_Restore(errType.StealNullable(),errValue.StealNullable(),tb.StealNullable());
1307+
returnconverted;
1308+
}
1309+
1310+
returnfalse;
12971311
}
12981312

12991313
publicoverrideboolTryBinaryOperation(BinaryOperationBinderbinder,objectarg,outobjectresult)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp