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

Commitc9626df

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 commitc9626df

File tree

12 files changed

+134
-54
lines changed

12 files changed

+134
-54
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/python_tests_runner/PythonTestRunner.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ public void Dispose()
3333
staticIEnumerable<string[]>PythonTestCases()
3434
{
3535
// Add the test that you want to debug here.
36-
yieldreturnnew[]{"test_enum","test_enum_standard_attrs"};
37-
yieldreturnnew[]{"test_generic","test_missing_generic_type"};
36+
yieldreturnnew[]{"test_indexer","test_boolean_indexer"};
37+
yieldreturnnew[]{"test_delegate","test_bool_delegate"};
3838
}
3939

4040
/// <summary>

‎src/runtime/converter.cs

Lines changed: 71 additions & 2 deletions
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,8 +631,21 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object? result, b
590631
}
591632

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

596650
caseTypeCode.Byte:
597651
{
@@ -768,6 +822,10 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object? result, b
768822

769823
caseTypeCode.Single:
770824
{
825+
if(!Runtime.PyFloat_Check(value)&&!Runtime.PyInt_Check(value))
826+
{
827+
gototype_error;
828+
}
771829
doublenum=Runtime.PyFloat_AsDouble(value);
772830
if(num==-1.0&&Exceptions.ErrorOccurred())
773831
{
@@ -786,6 +844,10 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object? result, b
786844

787845
caseTypeCode.Double:
788846
{
847+
if(!Runtime.PyFloat_Check(value)&&!Runtime.PyInt_Check(value))
848+
{
849+
gototype_error;
850+
}
789851
doublenum=Runtime.PyFloat_AsDouble(value);
790852
if(num==-1.0&&Exceptions.ErrorOccurred())
791853
{
@@ -933,6 +995,13 @@ private static bool ToArray(IntPtr value, Type obType, out object? result, bool
933995
result=items;
934996
returntrue;
935997
}
998+
999+
internalstaticboolIsFloatingNumber(Typetype)=>type==typeof(float)||type==typeof(double);
1000+
internalstaticboolIsInteger(Typetype)
1001+
=>type==typeof(Byte)||type==typeof(SByte)
1002+
||type==typeof(Int16)||type==typeof(UInt16)
1003+
||type==typeof(Int32)||type==typeof(UInt32)
1004+
||type==typeof(Int64)||type==typeof(UInt64);
9361005
}
9371006

9381007
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)

‎tests/test_conversion.py

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,53 +13,36 @@ def test_bool_conversion():
1313
"""Test bool conversion."""
1414
ob=ConversionTest()
1515
assertob.BooleanFieldisFalse
16-
assertob.BooleanFieldisFalse
1716
assertob.BooleanField==0
1817

1918
ob.BooleanField=True
2019
assertob.BooleanFieldisTrue
21-
assertob.BooleanFieldisTrue
2220
assertob.BooleanField==1
2321

2422
ob.BooleanField=False
2523
assertob.BooleanFieldisFalse
26-
assertob.BooleanFieldisFalse
2724
assertob.BooleanField==0
2825

29-
ob.BooleanField=1
30-
assertob.BooleanFieldisTrue
31-
assertob.BooleanFieldisTrue
32-
assertob.BooleanField==1
33-
34-
ob.BooleanField=0
35-
assertob.BooleanFieldisFalse
36-
assertob.BooleanFieldisFalse
37-
assertob.BooleanField==0
26+
withpytest.raises(TypeError):
27+
ob.BooleanField=1
28+
29+
withpytest.raises(TypeError):
30+
ob.BooleanField=0
3831

39-
ob.BooleanField=System.Boolean(None)
40-
assertob.BooleanFieldisFalse
41-
assertob.BooleanFieldisFalse
42-
assertob.BooleanField==0
32+
withpytest.raises(TypeError):
33+
ob.BooleanField=None
4334

44-
ob.BooleanField=System.Boolean('')
45-
assertob.BooleanFieldisFalse
46-
assertob.BooleanFieldisFalse
47-
assertob.BooleanField==0
35+
withpytest.raises(TypeError):
36+
ob.BooleanField=''
4837

49-
ob.BooleanField=System.Boolean(0)
50-
assertob.BooleanFieldisFalse
51-
assertob.BooleanFieldisFalse
52-
assertob.BooleanField==0
38+
withpytest.raises(TypeError):
39+
ob.BooleanField=System.Boolean(0)
5340

54-
ob.BooleanField=System.Boolean(1)
55-
assertob.BooleanFieldisTrue
56-
assertob.BooleanFieldisTrue
57-
assertob.BooleanField==1
41+
withpytest.raises(TypeError):
42+
ob.BooleanField=System.Boolean(1)
5843

59-
ob.BooleanField=System.Boolean('a')
60-
assertob.BooleanFieldisTrue
61-
assertob.BooleanFieldisTrue
62-
assertob.BooleanField==1
44+
withpytest.raises(TypeError):
45+
ob.BooleanField=System.Boolean('a')
6346

6447

6548
deftest_sbyte_conversion():

‎tests/test_delegate.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ def test_bool_delegate():
247247
fromPython.TestimportBoolDelegate
248248

249249
defalways_so_negative():
250-
return0
250+
returnFalse
251251

252252
d=BoolDelegate(always_so_negative)
253253
ob=DelegateTest()
@@ -256,6 +256,12 @@ def always_so_negative():
256256
assertnotd()
257257
assertnotob.CallBoolDelegate(d)
258258

259+
defalways_so_positive():
260+
return1
261+
bad=BoolDelegate(always_so_positive)
262+
withpytest.raises(TypeError):
263+
ob.CallBoolDelegate(bad)
264+
259265
deftest_object_delegate():
260266
"""Test object delegate."""
261267
fromPython.TestimportObjectDelegate

‎tests/test_field.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -200,11 +200,11 @@ def test_boolean_field():
200200
ob.BooleanField=False
201201
assertob.BooleanFieldisFalse
202202

203-
ob.BooleanField=1
204-
assertob.BooleanFieldisTrue
203+
withpytest.raises(TypeError):
204+
ob.BooleanField=1
205205

206-
ob.BooleanField=0
207-
assertob.BooleanFieldisFalse
206+
withpytest.raises(TypeError):
207+
ob.BooleanField=0
208208

209209

210210
deftest_sbyte_field():

‎tests/test_indexer.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,15 @@ def test_boolean_indexer():
6565
ob=Test.BooleanIndexerTest()
6666

6767
assertob[True]isNone
68-
assertob[1]isNone
69-
70-
ob[0]="false"
71-
assertob[0]=="false"
7268

73-
ob[1]="true"
74-
assertob[1]=="true"
69+
withpytest.raises(TypeError):
70+
ob[1]
71+
withpytest.raises(TypeError):
72+
ob[0]
73+
withpytest.raises(TypeError):
74+
ob[1]="true"
75+
withpytest.raises(TypeError):
76+
ob[0]="false"
7577

7678
ob[False]="false"
7779
assertob[False]=="false"

‎tests/test_module.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,6 @@ def test_preload_var():
4141
try:
4242
clr.setPreload(True)
4343
assertclr.getPreload()isTrue,clr.getPreload()
44-
clr.setPreload(0)
45-
assertclr.getPreload()isFalse,clr.getPreload()
46-
clr.setPreload(1)
47-
assertclr.getPreload()isTrue,clr.getPreload()
4844

4945
importSystem.Configuration
5046
content=dir(System.Configuration)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp