diff --git a/AUTHORS.md b/AUTHORS.md index 18435671c..f0d9f96ec 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -44,6 +44,7 @@ - Jan Krivanek ([@jakrivan](https://github.com/jakrivan)) - Jeff Reback ([@jreback](https://github.com/jreback)) - Jeff Robbins ([@jeff17robbins](https://github.com/jeff17robbins)) +- João Neves ([@joaompneves](https://github.com/joaompneves)) - Joe Frayne ([@jfrayne](https://github.com/jfrayne)) - Joe Lidbetter ([@jmlidbetter](https://github.com/jmlidbetter)) - Joe Savage ([@s4v4g3](https://github.com/s4v4g3)) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6cc52d72..9103d5a33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. ### Added +- Added `ToPythonAs()` extension method to allow for explicit conversion using a specific type not known at build time. ([#2419][i2419]) + - Added `ToPythonAs()` extension method to allow for explicit conversion using a specific type. ([#2311][i2311]) - Added `IComparable` and `IEquatable` implementations to `PyInt`, `PyFloat`, and `PyString` diff --git a/src/embed_tests/Codecs.cs b/src/embed_tests/Codecs.cs index c8b8ecb6e..90eb26669 100644 --- a/src/embed_tests/Codecs.cs +++ b/src/embed_tests/Codecs.cs @@ -339,6 +339,23 @@ public void ExceptionDecoded() Assert.AreEqual(TestExceptionMessage, error.Message); } + [Test(Description = "Tests encoding of an object that explicitly implements an interface.")] + public void ExplicitObjectInterfaceEncoded() + { + var obj = new ExplicitInterfaceObject(); + using var scope = Py.CreateScope(); + scope.Exec(@" +def call(obj): + return dir(obj) +"); + var callFunc = scope.Get("call"); + // explicitly pass an interface (but not a generic type argument) to simulate a scenario where the type is not know at build time + var callArg = obj.ToPythonAs(typeof(IObjectInterface)); + var members = callFunc.Invoke(callArg).As(); + CollectionAssert.Contains(members, nameof(IObjectInterface.MemberFromInterface)); + CollectionAssert.DoesNotContain(members, nameof(ExplicitInterfaceObject.MemberFromObject)); + } + [Test] public void DateTimeDecoded() { @@ -533,4 +550,16 @@ public bool TryDecode(PyObject pyObj, out T value) return true; } } + + interface IObjectInterface + { + int MemberFromInterface { get; } + } + + class ExplicitInterfaceObject : IObjectInterface + { + int IObjectInterface.MemberFromInterface { get; } + + public int MemberFromObject { get; } + } } diff --git a/src/embed_tests/Python.EmbeddingTest.csproj b/src/embed_tests/Python.EmbeddingTest.csproj index 4993994d3..be36ca787 100644 --- a/src/embed_tests/Python.EmbeddingTest.csproj +++ b/src/embed_tests/Python.EmbeddingTest.csproj @@ -2,6 +2,7 @@ net472;net6.0 + LatestMajor ..\pythonnet.snk true diff --git a/src/runtime/Converter.cs b/src/runtime/Converter.cs index 50b33e60e..d31614067 100644 --- a/src/runtime/Converter.cs +++ b/src/runtime/Converter.cs @@ -983,9 +983,14 @@ public static PyObject ToPython(this object? o) } public static PyObject ToPythonAs(this T? o) + { + return ToPythonAs(o, typeof(T)); + } + + public static PyObject ToPythonAs(this object? o, Type type) { if (o is null) return Runtime.None; - return Converter.ToPython(o, typeof(T)).MoveToPyObject(); + return Converter.ToPython(o, type).MoveToPyObject(); } } }