| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
14 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -15,6 +15,11 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. | |||
| 15 | 15 | details about the cause of the failure | |
| 16 | 16 | - `clr.AddReference` no longer adds ".dll" implicitly | |
| 17 | 17 | - `PyIter(PyObject)` constructor replaced with static `PyIter.GetIter(PyObject)` method | |
| 18 | + - Return values from .NET methods that return an interface are now automatically | ||
| 19 | + wrapped in that interface. This is a breaking change for users that rely on being | ||
| 20 | + able to access members that are part of the implementation class, but not the | ||
| 21 | + interface. Use the new __implementation__ or __raw_implementation__ properties to | ||
| 22 | + if you need to "downcast" to the implementation class. | ||
| 18 | 23 | ||
| 19 | 24 | ### Fixed | |
| 20 | 25 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -43,8 +43,9 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) | |||
| 43 | 43 | public static IntPtr mp_subscript(IntPtr ob, IntPtr idx) | |
| 44 | 44 | { | |
| 45 | 45 | var obj = (CLRObject)GetManagedObject(ob); | |
| 46 | + var arrObj = (ArrayObject)GetManagedObjectType(ob); | ||
| 46 | 47 | var items = obj.inst as Array; | |
| 47 | - Type itemType = obj.inst.GetType().GetElementType(); | ||
| 48 | + Type itemType = arrObj.type.GetElementType(); | ||
| 48 | 49 | int rank = items.Rank; | |
| 49 | 50 | int index; | |
| 50 | 51 | object value; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -173,6 +173,21 @@ internal static IntPtr ToPython(object value, Type type) | |||
| 173 | 173 | } | |
| 174 | 174 | } | |
| 175 | 175 | ||
| 176 | + if (type.IsInterface) | ||
| 177 | + { | ||
| 178 | + var ifaceObj = (InterfaceObject)ClassManager.GetClass(type); | ||
| 179 | + return ifaceObj.WrapObject(value); | ||
| 180 | + } | ||
| 181 | + | ||
| 182 | + // We need to special case interface array handling to ensure we | ||
| 183 | + // produce the correct type. Value may be an array of some concrete | ||
| 184 | + // type (FooImpl[]), but we want access to go via the interface type | ||
| 185 | + // (IFoo[]). | ||
| 186 | + if (type.IsArray && type.GetElementType().IsInterface) | ||
| 187 | + { | ||
| 188 | + return CLRObject.GetInstHandle(value, type); | ||
| 189 | + } | ||
| 190 | + | ||
| 176 | 191 | // it the type is a python subclass of a managed type then return the | |
| 177 | 192 | // underlying python object rather than construct a new wrapper object. | |
| 178 | 193 | var pyderived = value as IPythonDerivedType; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -71,7 +71,43 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) | |||
| 71 | 71 | return IntPtr.Zero; | |
| 72 | 72 | } | |
| 73 | 73 | ||
| 74 | - return CLRObject.GetInstHandle(obj, self.pyHandle); | ||
| 74 | + return self.WrapObject(obj); | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + /// <summary> | ||
| 78 | + /// Wrap the given object in an interface object, so that only methods | ||
| 79 | + /// of the interface are available. | ||
| 80 | + /// </summary> | ||
| 81 | + public IntPtr WrapObject(object impl) | ||
| 82 | + { | ||
| 83 | + var objPtr = CLRObject.GetInstHandle(impl, pyHandle); | ||
| 84 | + return objPtr; | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + /// <summary> | ||
| 88 | + /// Expose the wrapped implementation through attributes in both | ||
| 89 | + /// converted/encoded (__implementation__) and raw (__raw_implementation__) form. | ||
| 90 | + /// </summary> | ||
| 91 | + public static IntPtr tp_getattro(IntPtr ob, IntPtr key) | ||
| 92 | + { | ||
| 93 | + var clrObj = (CLRObject)GetManagedObject(ob); | ||
| 94 | + | ||
| 95 | + if (!Runtime.PyString_Check(key)) | ||
| 96 | + { | ||
| 97 | + return Exceptions.RaiseTypeError("string expected"); | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + string name = Runtime.GetManagedString(key); | ||
| 101 | + if (name == "__implementation__") | ||
| 102 | + { | ||
| 103 | + return Converter.ToPython(clrObj.inst); | ||
| 104 | + } | ||
| 105 | + else if (name == "__raw_implementation__") | ||
| 106 | + { | ||
| 107 | + return CLRObject.GetInstHandle(clrObj.inst); | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + return Runtime.PyObject_GenericGetAttr(ob, key); | ||
| 75 | 111 | } | |
| 76 | 112 | } | |
| 77 | 113 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -45,6 +45,25 @@ internal static ManagedType GetManagedObject(IntPtr ob) | |||
| 45 | 45 | return null; | |
| 46 | 46 | } | |
| 47 | 47 | ||
| 48 | + /// <summary> | ||
| 49 | + /// Given a Python object, return the associated managed object type or null. | ||
| 50 | + /// </summary> | ||
| 51 | + internal static ManagedType GetManagedObjectType(IntPtr ob) | ||
| 52 | + { | ||
| 53 | + if (ob != IntPtr.Zero) | ||
| 54 | + { | ||
| 55 | + IntPtr tp = Runtime.PyObject_TYPE(ob); | ||
| 56 | + var flags = Util.ReadCLong(tp, TypeOffset.tp_flags); | ||
| 57 | + if ((flags & TypeFlags.Managed) != 0) | ||
| 58 | + { | ||
| 59 | + tp = Marshal.ReadIntPtr(tp, TypeOffset.magic()); | ||
| 60 | + var gc = (GCHandle)tp; | ||
| 61 | + return (ManagedType)gc.Target; | ||
| 62 | + } | ||
| 63 | + } | ||
| 64 | + return null; | ||
| 65 | + } | ||
| 66 | + | ||
| 48 | 67 | ||
| 49 | 68 | internal static ManagedType GetManagedObjectErr(IntPtr ob) | |
| 50 | 69 | { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -744,7 +744,7 @@ internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, MethodBase i | |||
| 744 | 744 | Type pt = pi[i].ParameterType; | |
| 745 | 745 | if (pi[i].IsOut || pt.IsByRef) | |
| 746 | 746 | { | |
| 747 | - v = Converter.ToPython(binding.args[i], pt); | ||
| 747 | + v = Converter.ToPython(binding.args[i], pt.GetElementType()); | ||
| 748 | 748 | Runtime.PyTuple_SetItem(t, n, v); | |
| 749 | 749 | n++; | |
| 750 | 750 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -164,13 +164,13 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType) | |||
| 164 | 164 | // we want to do this after the slot stuff above in case the class itself implements a slot method | |
| 165 | 165 | InitializeSlots(type, impl.GetType()); | |
| 166 | 166 | ||
| 167 | - if (!clrType.GetInterfaces().Any(ifc => ifc == typeof(IEnumerable) || ifc == typeof(IEnumerator))) | ||
| 167 | + if (!typeof(IEnumerable).IsAssignableFrom(clrType) && | ||
| 168 | + !typeof(IEnumerator).IsAssignableFrom(clrType)) | ||
| 168 | 169 | { | |
| 169 | 170 | // The tp_iter slot should only be set for enumerable types. | |
| 170 | 171 | Marshal.WriteIntPtr(type, TypeOffset.tp_iter, IntPtr.Zero); | |
| 171 | 172 | } | |
| 172 | 173 | ||
| 173 | - | ||
| 174 | 174 | if (base_ != IntPtr.Zero) | |
| 175 | 175 | { | |
| 176 | 176 | Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -11,7 +11,6 @@ internal interface IInternalInterface | |||
| 11 | 11 | { | |
| 12 | 12 | } | |
| 13 | 13 | ||
| 14 | - | ||
| 15 | 14 | public interface ISayHello1 | |
| 16 | 15 | { | |
| 17 | 16 | string SayHello(); | |
@@ -43,6 +42,27 @@ string ISayHello2.SayHello() | |||
| 43 | 42 | return "hello 2"; | |
| 44 | 43 | } | |
| 45 | 44 | ||
| 45 | + public ISayHello1 GetISayHello1() | ||
| 46 | + { | ||
| 47 | + return this; | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + public void GetISayHello2(out ISayHello2 hello2) | ||
| 51 | + { | ||
| 52 | + hello2 = this; | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + public ISayHello1 GetNoSayHello(out ISayHello2 hello2) | ||
| 56 | + { | ||
| 57 | + hello2 = null; | ||
| 58 | + return null; | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + public ISayHello1 [] GetISayHello1Array() | ||
| 62 | + { | ||
| 63 | + return new[] { this }; | ||
| 64 | + } | ||
| 65 | + | ||
| 46 | 66 | public interface IPublic | |
| 47 | 67 | { | |
| 48 | 68 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -89,13 +89,24 @@ public static string test_bar(IInterfaceTest x, string s, int i) | |||
| 89 | 89 | } | |
| 90 | 90 | ||
| 91 | 91 | // test instances can be constructed in managed code | |
| 92 | - public static IInterfaceTest create_instance(Type t) | ||
| 92 | + public static SubClassTest create_instance(Type t) | ||
| 93 | + { | ||
| 94 | + return (SubClassTest)t.GetConstructor(new Type[] { }).Invoke(new object[] { }); | ||
| 95 | + } | ||
| 96 | + | ||
| 97 | + public static IInterfaceTest create_instance_interface(Type t) | ||
| 93 | 98 | { | |
| 94 | 99 | return (IInterfaceTest)t.GetConstructor(new Type[] { }).Invoke(new object[] { }); | |
| 95 | 100 | } | |
| 96 | 101 | ||
| 97 | - // test instances pass through managed code unchanged | ||
| 98 | - public static IInterfaceTest pass_through(IInterfaceTest s) | ||
| 102 | + // test instances pass through managed code unchanged ... | ||
| 103 | + public static SubClassTest pass_through(SubClassTest s) | ||
| 104 | + { | ||
| 105 | + return s; | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + // ... but the return type is an interface type, objects get wrapped | ||
| 109 | + public static IInterfaceTest pass_through_interface(IInterfaceTest s) | ||
| 99 | 110 | { | |
| 100 | 111 | return s; | |
| 101 | 112 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1288,9 +1288,10 @@ def test_special_array_creation(): | |||
| 1288 | 1288 | assert value[1].__class__ == inst.__class__ | |
| 1289 | 1289 | assert value.Length == 2 | |
| 1290 | 1290 | ||
| 1291 | + iface_class = ISayHello1(inst).__class__ | ||
| 1291 | 1292 | value = Array[ISayHello1]([inst, inst]) | |
| 1292 | - assert value[0].__class__ == inst.__class__ | ||
| 1293 | - assert value[1].__class__ == inst.__class__ | ||
| 1293 | + assert value[0].__class__ == iface_class | ||
| 1294 | + assert value[1].__class__ == iface_class | ||
| 1294 | 1295 | assert value.Length == 2 | |
| 1295 | 1296 | ||
| 1296 | 1297 | inst = System.Exception("badness") | |
| Back | FazBrowse Home | New Git URL |
0 commit comments