8000 Wrap returned objects in interface if method return type is interface by danabr · Pull Request #1240 · pythonnet/pythonnet · GitHub
[go: up one dir, main page]

Skip to content

Wrap returned objects in interface if method return type is interface #1240

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 1, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Return eleements of interface arrays as interface objects
Even when a method is declared to return an array of interfaces, the CLR
may use an array of the concrete type. Keep track of the intended type
in `ArrayObject` so that elements of the array can be properly wrapped in
`InterfaceObject` when accessed.
  • Loading branch information
danabr committed Oct 1, 2020
commit a74664cc70adf0b2d47afe2811b4afb1b92f052e
3 changes: 2 additions & 1 deletion src/runtime/arrayobject.cs
8000
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw)
public static IntPtr mp_subscript(IntPtr ob, IntPtr idx)
{
var obj = (CLRObject)GetManagedObject(ob);
var arrObj = (ArrayObject)GetManagedObjectType(ob);
var items = obj.inst as Array;
Type itemType = obj.inst.GetType().GetElementType();
Type itemType = arrObj.type.GetElementType();
int rank = items.Rank;
int index;
object value;
Expand Down
10 changes: 9 additions & 1 deletion src/runtime/converter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,15 @@ internal static IntPtr ToPython(object value, Type type)
return CLRObject.GetInstHandle(value, ifaceObj.pyHandle);
}

// We need to special case interface array handling to ensure we
// produce the correct type. Value may be an array of some concrete
// type (FooImpl[]), but we want access to go via the interface type
// (IFoo[]).
if (type.IsArray && type.GetElementType().IsInterface)
{
return CLRObject.GetInstHandle(value, type);
}

// it the type is a python subclass of a managed type then return the
// underlying python object rather than construct a new wrapper object.
var pyderived = value as IPythonDerivedType;
Expand All @@ -188,7 +197,6 @@ internal static IntPtr ToPython(object value, Type type)
return ClassDerivedObject.ToPython(pyderived);
}


// hmm - from Python, we almost never care what the declared
// type is. we'd rather have the object bound to the actual
// implementing class.
Expand Down
19 changes: 19 additions & 0 deletions src/runtime/managedtype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,25 @@ internal static ManagedType GetManagedObject(IntPtr ob)
return null;
}

/// <summary>
/// Given a Python object, return the associated managed object type or null.
/// </summary>
internal static ManagedType GetManagedObjectType(IntPtr ob)
{
if (ob != IntPtr.Zero)
{
IntPtr tp = Runtime.PyObject_TYPE(ob);
var flags = Util.ReadCLong(tp, TypeOffset.tp_flags);
if ((flags & TypeFlags.Managed) != 0)
{
tp = Marshal.ReadIntPtr(tp, TypeOffset.magic());
var gc = (GCHandle)tp;
return (ManagedType)gc.Target;
}
}
return null;
}


internal static ManagedType GetManagedObjectErr(IntPtr ob)
{
Expand Down
5 changes: 5 additions & 0 deletions src/testing/interfacetest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ public ISayHello1 GetNoSayHello(out ISayHello2 hello2)
return null;
}

public ISayHello1 [] GetISayHello1Array()
{
return new[] { this };
}

public interface IPublic
{
}
Expand Down
8 changes: 8 additions & 0 deletions src/tests/test_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,11 @@ def test_null_interface_object_returned():
hello1, hello2 = ob.GetNoSayHello(None)
assert hello1 is None
assert hello2 is None

def test_interface_array_returned():
"""Test interface type used for methods returning interface arrays"""
from Python.Test import InterfaceTest

ob = InterfaceTest()
hellos = ob.GetISayHello1Array()
assert type(hellos[0]).__name__ == 'ISayHello1'
0