From 21528ee2fd3cbda2c9c7a9d7d884b71fb181ff2e Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Mon, 21 Oct 2019 17:35:53 -0500 Subject: [PATCH 01/11] Add test for ienumerable method --- src/testing/methodtest.cs | 5 +++++ src/tests/test_method.py | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/testing/methodtest.cs b/src/testing/methodtest.cs index 91836b727..3b34dd40e 100644 --- a/src/testing/methodtest.cs +++ b/src/testing/methodtest.cs @@ -117,6 +117,11 @@ public static int[] TestOverloadedParams(int v, int[] args) return args; } + public static int TestIEnumerable(System.Collections.Generic.IEnumerable arg) + { + return 1; + } + public static string TestOverloadedNoObject(int i) { return "Got int"; diff --git a/src/tests/test_method.py b/src/tests/test_method.py index 34f460d59..57304688e 100644 --- a/src/tests/test_method.py +++ b/src/tests/test_method.py @@ -204,6 +204,11 @@ def test_null_array_conversion(): r = ob.TestNullArrayConversion(None) assert r is None +def test_ienumerable_args(): + """Test conversion of python lists and tuples to IEnumerable""" + ob = MethodTest() + x = ob.TestIEnumerable([1,2,3]) + y = ob.TestIEnumerable((1,2,3)) def test_string_params_args(): """Test use of string params.""" From b4d60c6ca6495f3e529f94f2983859f4439d021e Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Sun, 1 Dec 2019 16:13:37 -0600 Subject: [PATCH 02/11] Add tests for collection & task/action from function change enumerable method to non-static add tuple test for ienumerable --- src/testing/methodtest.cs | 24 +++++++++++++++++++++++- src/tests/test_method.py | 21 +++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/testing/methodtest.cs b/src/testing/methodtest.cs index 3b34dd40e..8fff85346 100644 --- a/src/testing/methodtest.cs +++ b/src/testing/methodtest.cs @@ -117,7 +117,29 @@ public static int[] TestOverloadedParams(int v, int[] args) return args; } - public static int TestIEnumerable(System.Collections.Generic.IEnumerable arg) + public static int TestIList(System.Collections.Generic.IList arg) + { + return 1; + } + + public static int TestICollection(System.Collections.Generic.ICollection arg) + { + return 1; + } + + public int TestAction(System.Action action) + { + action(); + return 1; + } + + public int TestTask(System.Threading.Tasks.Task task) + { + task.RunSynchronously(); + return task.Result; + } + + public int TestIEnumerable(System.Collections.Generic.IEnumerable arg) { return 1; } diff --git a/src/tests/test_method.py b/src/tests/test_method.py index 57304688e..4c821422e 100644 --- a/src/tests/test_method.py +++ b/src/tests/test_method.py @@ -204,12 +204,33 @@ def test_null_array_conversion(): r = ob.TestNullArrayConversion(None) assert r is None +def test_action(): + """Test python lambda as an action""" + ob = MethodTest() + def func(): + return + r = ob.TestAction(func) + assert r == 1 + +def test_task(): + """Test python lambda as an action""" + ob = MethodTest() + def func(): + return 1 + r = ob.TestTask(func) + assert r == 1 + def test_ienumerable_args(): """Test conversion of python lists and tuples to IEnumerable""" ob = MethodTest() x = ob.TestIEnumerable([1,2,3]) y = ob.TestIEnumerable((1,2,3)) +def test_icollection_args(): + """Test conversion of python lists and tuples to ICollection""" + ob = MethodTest() + x = ob.TestICollection([1,2,3]) + def test_string_params_args(): """Test use of string params.""" result = MethodTest.TestStringParamsArg('one', 'two', 'three') From 3f02abf9fbba66c0f44ce5a831aef95db804c52c Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Sun, 1 Dec 2019 17:04:24 -0600 Subject: [PATCH 03/11] Add more tests --- src/testing/methodtest.cs | 6 ++++++ src/tests/test_method.py | 12 ++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/testing/methodtest.cs b/src/testing/methodtest.cs index 8fff85346..3a61a017c 100644 --- a/src/testing/methodtest.cs +++ b/src/testing/methodtest.cs @@ -133,6 +133,12 @@ public int TestAction(System.Action action) return 1; } + public int TestFuncObj(System.Func func, object arg) + { + return func.Invoke(arg); + + } + public int TestTask(System.Threading.Tasks.Task task) { task.RunSynchronously(); diff --git a/src/tests/test_method.py b/src/tests/test_method.py index 4c821422e..2a6352d74 100644 --- a/src/tests/test_method.py +++ b/src/tests/test_method.py @@ -205,15 +205,23 @@ def test_null_array_conversion(): assert r is None def test_action(): - """Test python lambda as an action""" + """Test python lambda as an Action""" ob = MethodTest() def func(): return r = ob.TestAction(func) assert r == 1 +def test_func_object(): + """Test python lambda as a Func""" + ob = MethodTest() + def func(arg): + return arg + 1 + r = ob.TestFunc(func, 0) + assert r == 1 + def test_task(): - """Test python lambda as an action""" + """Test python lambda as a Task""" ob = MethodTest() def func(): return 1 From 9c3e1c51ff38d92ae15c45304b04e03a68616a5c Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Sun, 1 Dec 2019 17:04:54 -0600 Subject: [PATCH 04/11] Implement list converter --- src/runtime/converter.cs | 53 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/runtime/converter.cs b/src/runtime/converter.cs index e7e047419..8970652fe 100644 --- a/src/runtime/converter.cs +++ b/src/runtime/converter.cs @@ -343,6 +343,17 @@ internal static bool ToManagedValue(IntPtr value, Type obType, return ToArray(value, obType, out result, setError); } + if (obType.IsGenericType) + { + if (obType.GetGenericTypeDefinition() == typeof(IEnumerable<>) || + obType.GetGenericTypeDefinition() == typeof(ICollection<>) || + obType.GetGenericTypeDefinition() == typeof(IList<>)) + { + //We could probably convert to a thin IEnumerable/IList/ICollection implementation around a python array + //but for simplicity right now convert to a List which is a copy of the python iterable. + return ToList(value, obType, out result, setError); + } + } if (obType.IsEnum) { return ToEnum(value, obType, out result, setError); @@ -901,6 +912,48 @@ private static bool ToArray(IntPtr value, Type obType, out object result, bool s return true; } + /// + /// Convert a Python value to a correctly typed managed list instance. + /// The Python value must support the Python iterator protocol or and the + /// items in the sequence must be convertible to the target array type. + /// + private static bool ToList(IntPtr value, Type obType, out object result, bool setError) { + Type elementType = obType.GetGenericArguments()[0]; + result = null; + + bool IsSeqObj = Runtime.PySequence_Check(value); + var len = IsSeqObj ? Runtime.PySequence_Size(value) : -1; + + IntPtr IterObject = Runtime.PyObject_GetIter(value); + + if (IterObject == IntPtr.Zero) { + if (setError) { + SetConversionError(value, obType); + } + return false; + } + + var listType = typeof(List<>); + var constructedListType = listType.MakeGenericType(elementType); + IList list = IsSeqObj ? (IList)Activator.CreateInstance(constructedListType, new Object[] { (int)len }) : + (IList)Activator.CreateInstance(constructedListType); + IntPtr item; + + while ((item = Runtime.PyIter_Next(IterObject)) != IntPtr.Zero) { + object obj = null; + + if (!Converter.ToManaged(item, elementType, out obj, true)) { + Runtime.XDecref(item); + return false; + } + + list.Add(obj); + Runtime.XDecref(item); + } + Runtime.XDecref(IterObject); + result = list; + return true; + } /// /// Convert a Python value to a correctly typed managed enum instance. From b9db0f638694b096110cc3a5e3bdfbe036a25868 Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Sun, 1 Dec 2019 17:05:44 -0600 Subject: [PATCH 05/11] Implement action converter --- src/runtime/converter.cs | 44 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/runtime/converter.cs b/src/runtime/converter.cs index 8970652fe..d3df2dfe6 100644 --- a/src/runtime/converter.cs +++ b/src/runtime/converter.cs @@ -354,6 +354,12 @@ internal static bool ToManagedValue(IntPtr value, Type obType, return ToList(value, obType, out result, setError); } } + + if (obType.FullName == "System.Action") + { + return ToAction(value, obType, out result, setError); + } + if (obType.IsEnum) { return ToEnum(value, obType, out result, setError); @@ -912,6 +918,43 @@ private static bool ToArray(IntPtr value, Type obType, out object result, bool s return true; } + /// + /// Convert a Python function to a System.Action. + /// The Python value must support the Python "BLAH" protocol. + /// + private static bool ToAction(IntPtr value, Type obType, out object result, bool setError) { + + result = null; + + PyObject obj = new PyObject(value); + + var args = obType.GetGenericArguments(); + + //Temporarily only deal with non-generic actions! + if (!obj.IsCallable() || args.Length != 0) { + if (setError) { + SetConversionError(value, obType); + } + obj.Dispose(); + return false; + } + + Action action = () => { + PyObject py_action = new PyObject(value); + var py_args = new PyObject[0]; + var py_result = py_action.Invoke(py_args); + + //Discard the result since this is being converted to an Action + py_result.Dispose(); + py_action.Dispose(); + }; + + result = action; + obj.Dispose(); + return true; + } + + /// /// Convert a Python value to a correctly typed managed list instance. /// The Python value must support the Python iterator protocol or and the @@ -955,6 +998,7 @@ private static bool ToList(IntPtr value, Type obType, out object result, bool se return true; } + /// /// Convert a Python value to a correctly typed managed enum instance. /// From 4b0a1ad1f28368f31b9da286bd8cc5da5417c1ca Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Sun, 1 Dec 2019 17:10:27 -0600 Subject: [PATCH 06/11] add TODO --- src/runtime/converter.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/runtime/converter.cs b/src/runtime/converter.cs index d3df2dfe6..0afa80830 100644 --- a/src/runtime/converter.cs +++ b/src/runtime/converter.cs @@ -959,6 +959,7 @@ private static bool ToAction(IntPtr value, Type obType, out object result, bool /// Convert a Python value to a correctly typed managed list instance. /// The Python value must support the Python iterator protocol or and the /// items in the sequence must be convertible to the target array type. + /// TODO - remove duplication with ToArray! /// private static bool ToList(IntPtr value, Type obType, out object result, bool setError) { Type elementType = obType.GetGenericArguments()[0]; From 8bed1bb70229cad5d1d0884c6890c598733d0f23 Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Sun, 1 Dec 2019 17:12:08 -0600 Subject: [PATCH 07/11] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c999d668..c22ac2f16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. - Added automatic NuGet package generation in appveyor and local builds - Added function that sets Py_NoSiteFlag to 1. - Added support for Jetson Nano. +- Added support for methodbinding to IEnumerable, ICollection, IList, Task, Action, Func ### Changed From a4599d922bf0742f35e76f720ba0fefcdadf86af Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Mon, 2 Dec 2019 17:29:14 -0600 Subject: [PATCH 08/11] share common code between ToArray and ToList --- src/runtime/converter.cs | 88 ++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 54 deletions(-) diff --git a/src/runtime/converter.cs b/src/runtime/converter.cs index 0afa80830..c699088fc 100644 --- a/src/runtime/converter.cs +++ b/src/runtime/converter.cs @@ -864,15 +864,8 @@ private static void SetConversionError(IntPtr value, Type target) Exceptions.SetError(Exceptions.TypeError, $"Cannot convert {src} to {target}"); } - - /// - /// Convert a Python value to a correctly typed managed array instance. - /// The Python value must support the Python iterator protocol or and the - /// items in the sequence must be convertible to the target array type. - /// - private static bool ToArray(IntPtr value, Type obType, out object result, bool setError) + private static bool ToListOfT(IntPtr value, Type elementType, out object result) { - Type elementType = obType.GetElementType(); result = null; bool IsSeqObj = Runtime.PySequence_Check(value); @@ -880,28 +873,19 @@ private static bool ToArray(IntPtr value, Type obType, out object result, bool s IntPtr IterObject = Runtime.PyObject_GetIter(value); - if(IterObject==IntPtr.Zero) { - if (setError) - { - SetConversionError(value, obType); - } + if (IterObject == IntPtr.Zero) return false; - } - - Array items; var listType = typeof(List<>); var constructedListType = listType.MakeGenericType(elementType); - IList list = IsSeqObj ? (IList) Activator.CreateInstance(constructedListType, new Object[] {(int) len}) : - (IList) Activator.CreateInstance(constructedListType); + IList list = IsSeqObj ? (IList)Activator.CreateInstance(constructedListType, new Object[] { (int)len }) : + (IList)Activator.CreateInstance(constructedListType); IntPtr item; - while ((item = Runtime.PyIter_Next(IterObject)) != IntPtr.Zero) - { + while ((item = Runtime.PyIter_Next(IterObject)) != IntPtr.Zero) { object obj = null; - if (!Converter.ToManaged(item, elementType, out obj, true)) - { + if (!Converter.ToManaged(item, elementType, out obj, true)) { Runtime.XDecref(item); return false; } @@ -910,12 +894,34 @@ private static bool ToArray(IntPtr value, Type obType, out object result, bool s Runtime.XDecref(item); } Runtime.XDecref(IterObject); + result = list; + return true; + } + + /// + /// Convert a Python value to a correctly typed managed array instance. + /// The Python value must support the Python iterator protocol or and the + /// items in the sequence must be convertible to the target array type. + /// + private static bool ToArray(IntPtr value, Type obType, out object result, bool setError) + { + Type elementType = obType.GetElementType(); + result = null; + bool success = ToListOfT(value, elementType, out result); + if (!success) + { + if (setError) + SetConversionError(value, obType); + return false; + } - items = Array.CreateInstance(elementType, list.Count); + IList list = (IList)result; + Array items = Array.CreateInstance(elementType, list.Count); list.CopyTo(items, 0); - + result = items; return true; + } /// @@ -963,39 +969,13 @@ private static bool ToAction(IntPtr value, Type obType, out object result, bool /// private static bool ToList(IntPtr value, Type obType, out object result, bool setError) { Type elementType = obType.GetGenericArguments()[0]; - result = null; - - bool IsSeqObj = Runtime.PySequence_Check(value); - var len = IsSeqObj ? Runtime.PySequence_Size(value) : -1; - - IntPtr IterObject = Runtime.PyObject_GetIter(value); - - if (IterObject == IntPtr.Zero) { - if (setError) { + var success = ToListOfT(value, elementType, out result); + if (!success) + { + if (setError) SetConversionError(value, obType); - } return false; } - - var listType = typeof(List<>); - var constructedListType = listType.MakeGenericType(elementType); - IList list = IsSeqObj ? (IList)Activator.CreateInstance(constructedListType, new Object[] { (int)len }) : - (IList)Activator.CreateInstance(constructedListType); - IntPtr item; - - while ((item = Runtime.PyIter_Next(IterObject)) != IntPtr.Zero) { - object obj = null; - - if (!Converter.ToManaged(item, elementType, out obj, true)) { - Runtime.XDecref(item); - return false; - } - - list.Add(obj); - Runtime.XDecref(item); - } - Runtime.XDecref(IterObject); - result = list; return true; } From 96fd89692a7ce74213e08fa6e70163f1dcc4530d Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Mon, 2 Dec 2019 20:46:18 -0600 Subject: [PATCH 09/11] improve ref counting --- src/runtime/converter.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/runtime/converter.cs b/src/runtime/converter.cs index c699088fc..96d02cd47 100644 --- a/src/runtime/converter.cs +++ b/src/runtime/converter.cs @@ -941,7 +941,6 @@ private static bool ToAction(IntPtr value, Type obType, out object result, bool if (setError) { SetConversionError(value, obType); } - obj.Dispose(); return false; } @@ -949,14 +948,11 @@ private static bool ToAction(IntPtr value, Type obType, out object result, bool PyObject py_action = new PyObject(value); var py_args = new PyObject[0]; var py_result = py_action.Invoke(py_args); - - //Discard the result since this is being converted to an Action - py_result.Dispose(); - py_action.Dispose(); + Runtime.XDecref(value); }; + Runtime.XIncref(value); result = action; - obj.Dispose(); return true; } From c6fd7686935f5d20d41ca1f14202514dbb7cb9f2 Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Wed, 4 Dec 2019 17:48:14 -0600 Subject: [PATCH 10/11] revert whitespace --- src/runtime/converter.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/runtime/converter.cs b/src/runtime/converter.cs index 96d02cd47..c6b87ee16 100644 --- a/src/runtime/converter.cs +++ b/src/runtime/converter.cs @@ -878,14 +878,16 @@ private static bool ToListOfT(IntPtr value, Type elementType, out object result) var listType = typeof(List<>); var constructedListType = listType.MakeGenericType(elementType); - IList list = IsSeqObj ? (IList)Activator.CreateInstance(constructedListType, new Object[] { (int)len }) : - (IList)Activator.CreateInstance(constructedListType); + IList list = IsSeqObj ? (IList) Activator.CreateInstance(constructedListType, new Object[] { (int)len }) : + (IList) Activator.CreateInstance(constructedListType); IntPtr item; - while ((item = Runtime.PyIter_Next(IterObject)) != IntPtr.Zero) { + while ((item = Runtime.PyIter_Next(IterObject)) != IntPtr.Zero) + { object obj = null; - if (!Converter.ToManaged(item, elementType, out obj, true)) { + if (!Converter.ToManaged(item, elementType, out obj, true)) + { Runtime.XDecref(item); return false; } From e63d11edc73f7fa197e76681e0316124d53b77c2 Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Sat, 7 Dec 2019 18:51:46 -0600 Subject: [PATCH 11/11] list wrapper --- src/runtime/ListWrapper.cs | 201 +++++++++++++++++++++++++++++++++++++ src/runtime/converter.cs | 63 +++++++----- 2 files changed, 237 insertions(+), 27 deletions(-) create mode 100644 src/runtime/ListWrapper.cs diff --git a/src/runtime/ListWrapper.cs b/src/runtime/ListWrapper.cs new file mode 100644 index 000000000..5173be4b0 --- /dev/null +++ b/src/runtime/ListWrapper.cs @@ -0,0 +1,201 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Python.Runtime { + /// + /// Implements IEnumerable for any python iterable. + /// + internal class IterableWrapper : IEnumerable { + private IntPtr iterObject; + + public IterableWrapper(IntPtr value) { + iterObject = Runtime.PyObject_GetIter(value); + if (iterObject == IntPtr.Zero) + Exceptions.RaiseTypeError("not an iterator"); + Runtime.XIncref(iterObject); + } + ~IterableWrapper() { + Runtime.XDecref(iterObject); + } + + public IEnumerator GetEnumerator() { + return GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() { + IntPtr item; + while ((item = Runtime.PyIter_Next(iterObject)) != IntPtr.Zero) { + object obj = null; + if (!Converter.ToManaged(item, typeof(T), out obj, true)) { + Runtime.XDecref(item); + Runtime.XDecref(iterObject); + Exceptions.RaiseTypeError("wrong type in sequence"); + } + + Runtime.XDecref(item); + yield return obj; + } + } + } + + /// + /// Implements IList for any python sequence. + /// Some methods/properties are only available on certaintypes of sequences, like list + /// + internal class ListWrapper : IterableWrapper, IList + { + private IntPtr seq; + public ListWrapper(IntPtr value) : base(value) + { + this.seq = value; + Runtime.XIncref(value); + bool IsSeqObj = Runtime.PySequence_Check(value); + if (!IsSeqObj) + Exceptions.RaiseTypeError("not a sequence"); + + } + ~ListWrapper() + { + Runtime.XDecref(seq); + } + public T this[int index] + { + get + { + IntPtr item = Runtime.PySequence_GetItem(seq, index); + object obj; + + if (!Converter.ToManaged(item, typeof(T), out obj, true)) { + Runtime.XDecref(item); + Exceptions.RaiseTypeError("wrong type in sequence"); + } + + return (T)obj; + } + set + { + IntPtr pyItem = Converter.ToPython(value, typeof(T)); + if (pyItem == IntPtr.Zero) + throw new Exception("failed to set item"); + + var result = Runtime.PySequence_SetItem(seq, index, pyItem); + Runtime.XDecref(pyItem); + if (result == -1) + throw new Exception("failed to set item"); + } + } + + public int Count + { + get + { + var len = Runtime.PySequence_Size(seq); + return (int)len; + } + } + + public bool IsReadOnly + { + get + { + return Runtime.PyTuple_Check(seq); //python tuples are immutable + } + + } + + public void Add(T item) { + if (IsReadOnly) + throw new NotImplementedException(); + + //only implemented if this is a list! + if (!Runtime.PyList_Check(seq)) + throw new NotImplementedException(); + + IntPtr pyItem = Converter.ToPython(item, typeof(T)); + if (pyItem == IntPtr.Zero) + throw new Exception("failed to add item"); + + var result = Runtime.PyList_Append(seq, pyItem); + Runtime.XDecref(pyItem); + if (result == -1) + throw new Exception("failed to add item"); + } + + public void Clear() { + if (IsReadOnly) + throw new NotImplementedException(); + var result = Runtime.PySequence_DelSlice(seq, 0, Count); + if (result == -1) + throw new Exception("failed to clear sequence"); + } + + public bool Contains(T item) + { + //not sure if IEquatable is implemented and this will work! + foreach (var element in this) + if (element.Equals(item)) return true; + + return false; + } + + public void CopyTo(T[] array, int arrayIndex) + { + for (int index = 0; index < Count; index++) + { + array[index + arrayIndex] = this[index]; + } + } + + public int IndexOf(T item) { + var index = 0; + foreach (var element in this) { + if (element.Equals(item)) return index; + index++; + } + + return -1; + } + + public void Insert(int index, T item) + { + if (IsReadOnly) + throw new NotImplementedException(); + + //only implemented if this is a list! + if (!Runtime.PyList_Check(seq)) + throw new NotImplementedException(); + + IntPtr pyItem = Converter.ToPython(item, typeof(T)); + if (pyItem == IntPtr.Zero) + throw new Exception("failed to insert item"); + + var result = Runtime.PyList_Insert(seq, index, pyItem); + Runtime.XDecref(pyItem); + if (result == -1) + throw new Exception("failed to insert item"); + } + + public bool InternalRemoveAt(int index) + { + if (IsReadOnly) + throw new NotImplementedException(); + if (index >= Count || index < 0) + throw new IndexOutOfRangeException(); + + return Runtime.PySequence_DelItem(seq, index) != 0; + } + + public bool Remove(T item) + { + return InternalRemoveAt(IndexOf(item)); + } + + public void RemoveAt(int index) + { + InternalRemoveAt(index); + } + } +} diff --git a/src/runtime/converter.cs b/src/runtime/converter.cs index c6b87ee16..c96270b81 100644 --- a/src/runtime/converter.cs +++ b/src/runtime/converter.cs @@ -6,6 +6,7 @@ using System.Runtime.InteropServices; using System.Security; using System.ComponentModel; +using System.Linq; namespace Python.Runtime { @@ -268,7 +269,6 @@ internal static IntPtr ToPythonImplicit(object value) return ToPython(value, objectType); } - /// /// Return a managed object for the given Python object, taking funny /// byref types into account. @@ -868,35 +868,34 @@ private static bool ToListOfT(IntPtr value, Type elementType, out object result) { result = null; - bool IsSeqObj = Runtime.PySequence_Check(value); - var len = IsSeqObj ? Runtime.PySequence_Size(value) : -1; - - IntPtr IterObject = Runtime.PyObject_GetIter(value); - - if (IterObject == IntPtr.Zero) + IntPtr iterObject = Runtime.PyObject_GetIter(value); + if (iterObject == IntPtr.Zero) return false; - var listType = typeof(List<>); - var constructedListType = listType.MakeGenericType(elementType); - IList list = IsSeqObj ? (IList) Activator.CreateInstance(constructedListType, new Object[] { (int)len }) : - (IList) Activator.CreateInstance(constructedListType); - IntPtr item; - - while ((item = Runtime.PyIter_Next(IterObject)) != IntPtr.Zero) - { - object obj = null; + bool IsSeqObj = Runtime.PySequence_Check(value); - if (!Converter.ToManaged(item, elementType, out obj, true)) - { - Runtime.XDecref(item); - return false; + try { + Type[] typeArgs = { elementType }; + if (IsSeqObj) { + var listType = typeof(ListWrapper<>); + object listObj = Activator.CreateInstance(listType.MakeGenericType(typeArgs), new Object[] { value }); + //IList list = (IList)Activator.CreateInstance(fullListType, new Object[] { value }); + + result = listObj; } + else { + var listType = typeof(IterableWrapper<>); + IEnumerable list = (IEnumerable)Activator.CreateInstance(listType.MakeGenericType(typeArgs), new Object[] { value }); + result = list; + } + } + catch (Exception) { + return false; - list.Add(obj); - Runtime.XDecref(item); } - Runtime.XDecref(IterObject); - result = list; + finally { + Runtime.XDecref(iterObject); + } return true; } @@ -917,10 +916,18 @@ private static bool ToArray(IntPtr value, Type obType, out object result, bool s return false; } - IList list = (IList)result; + IList list = result as IList; + if (list == null) { + IEnumerable enumerable = (IEnumerable)result; + var listType = typeof(List<>); + var constructedListType = listType.MakeGenericType(elementType); + list = (IList)Activator.CreateInstance(constructedListType); + foreach (var item in enumerable) { + list.Add(item); + } + } Array items = Array.CreateInstance(elementType, list.Count); list.CopyTo(items, 0); - result = items; return true; @@ -947,14 +954,16 @@ private static bool ToAction(IntPtr value, Type obType, out object result, bool } Action action = () => { + var y = Runtime.Refcount(value); PyObject py_action = new PyObject(value); var py_args = new PyObject[0]; var py_result = py_action.Invoke(py_args); Runtime.XDecref(value); }; - + var x = Runtime.Refcount(value); Runtime.XIncref(value); result = action; + return true; } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy