Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8ad1062

Browse files
authored
Enable C# parameters of type object accept any argument, passed from Python (#889)
* added a regression test for #881 * when converting to object, wrap values of unknown type into PyObject instead of failing This enables overload resolution with object parameters to behave the same way PyObject parameters behave - e.g. allow any Python object to be passed as PyObject as fallback. Resolves #811 * fixed ObjectField conversion test * fixed test_object_indexer to pass on custom class key * use object() instance in OverloadResolution_UnknownToObject test
1 parent d932176 commit 8ad1062

File tree

6 files changed

+73
-17
lines changed

6 files changed

+73
-17
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
5858
- Reattach python exception traceback information (#545)
5959
- PythonEngine.Intialize will now call `Py_InitializeEx` with a default value of 0, so signals will not be configured by default on embedding. This is different from the previous behaviour, where `Py_Initialize` was called instead, which sets initSigs to 1. ([#449][i449])
6060
- Refactored MethodBinder.Bind in preparation to make it extensible (#829)
61+
- When calling C# from Python, enable passing argument of any type to a parameter of C# type `object` by wrapping it into `PyObject` instance. ([#881][i881])
6162
- Look for installed Windows 10 sdk's during installation instead of relying on specific versions.
6263

6364
### Fixed

src/embed_tests/Python.EmbeddingTest.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
<Compile Include="TestDomainReload.cs" />
9595
<Compile Include="TestExample.cs" />
9696
<Compile Include="TestFinalizer.cs" />
97+
<Compile Include="TestInstanceWrapping.cs" />
9798
<Compile Include="TestPyAnsiString.cs" />
9899
<Compile Include="TestPyFloat.cs" />
99100
<Compile Include="TestPyInt.cs" />
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using System;
2+
using System.Globalization;
3+
using NUnit.Framework;
4+
using Python.Runtime;
5+
6+
namespace Python.EmbeddingTest
7+
{
8+
public class TestInstanceWrapping
9+
{
10+
[OneTimeSetUp]
11+
public void SetUp()
12+
{
13+
PythonEngine.Initialize();
14+
}
15+
16+
[OneTimeTearDown]
17+
public void Dispose()
18+
{
19+
PythonEngine.Shutdown();
20+
}
21+
22+
// regression test for https://github.com/pythonnet/pythonnet/issues/811
23+
[Test]
24+
public void OverloadResolution_UnknownToObject()
25+
{
26+
var overloaded = new Overloaded();
27+
using (Py.GIL())
28+
{
29+
var o = overloaded.ToPython();
30+
31+
dynamic callWithSelf = PythonEngine.Eval("lambda o: o.ObjOrClass(object())");
32+
callWithSelf(o);
33+
Assert.AreEqual(Overloaded.Object, overloaded.Value);
34+
}
35+
}
36+
37+
class Base {}
38+
class Derived: Base { }
39+
40+
class Overloaded: Derived
41+
{
42+
public int Value { get; set; }
43+
public void IntOrStr(int arg) => this.Value = arg;
44+
public void IntOrStr(string arg) =>
45+
this.Value = int.Parse(arg, NumberStyles.Integer, CultureInfo.InvariantCulture);
46+
47+
public const int Object = 1;
48+
public const int ConcreteClass = 2;
49+
public void ObjOrClass(object _) => this.Value = Object;
50+
public void ObjOrClass(Overloaded _) => this.Value = ConcreteClass;
51+
52+
public const int Base = ConcreteClass + 1;
53+
public const int Derived = Base + 1;
54+
public void BaseOrDerived(Base _) => this.Value = Base;
55+
public void BaseOrDerived(Derived _) => this.Value = Derived;
56+
}
57+
}
58+
}

src/runtime/converter.cs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -398,12 +398,9 @@ internal static bool ToManagedValue(IntPtr value, Type obType,
398398
return ToArray(value, typeof(object[]), out result, setError);
399399
}
400400

401-
if (setError)
402-
{
403-
Exceptions.SetError(Exceptions.TypeError, "value cannot be converted to Object");
404-
}
405-
406-
return false;
401+
Runtime.XIncref(value); // PyObject() assumes ownership
402+
result = new PyObject(value);
403+
return true;
407404
}
408405

409406
// Conversion to 'Type' is done using the same mappings as above for objects.

src/tests/test_conversion.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -595,11 +595,10 @@ def test_object_conversion():
595595

596596
# need to test subclass here
597597

598-
with pytest.raises(TypeError):
599-
class Foo(object):
600-
pass
601-
ob = ConversionTest()
602-
ob.ObjectField = Foo
598+
class Foo(object):
599+
pass
600+
ob.ObjectField = Foo
601+
assert ob.ObjectField == Foo
603602

604603

605604
def test_enum_conversion():

src/tests/test_indexer.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -438,13 +438,13 @@ def test_object_indexer():
438438
ob[long(1)] = "long"
439439
assert ob[long(1)] == "long"
440440

441-
with pytest.raises(TypeError):
442-
class Eggs(object):
443-
pass
441+
class Eggs(object):
442+
pass
444443

445-
key = Eggs()
446-
ob = Test.ObjectIndexerTest()
447-
ob[key] = "wrong"
444+
key = Eggs()
445+
ob = Test.ObjectIndexerTest()
446+
ob[key] = "eggs_key"
447+
assert ob[key] == "eggs_key"
448448

449449

450450
def test_interface_indexer():

0 commit comments

Comments
 (0)