8000 begin to implement list codec · pythonnet/pythonnet@b500aa1 · GitHub
[go: up one dir, main page]

Skip to content

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

10000
Appearance settings

Commit b500aa1

Browse files
committed
begin to implement list codec
1 parent fb083bb commit b500aa1

File tree

2 files changed

+127
-1
lines changed

2 files changed

+127
-1
lines changed

src/embed_tests/Codecs.cs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
namespace Python.EmbeddingTest {
22
using System;
33
using System.Collections.Generic;
4-
using System.Text;
4+
using System.Linq;
55
using NUnit.Framework;
66
using Python.Runtime;
77
using Python.Runtime.Codecs;
@@ -82,6 +82,31 @@ static void TupleRoundtripGeneric<T, TTuple>() {
8282
Assert.AreEqual(expected: tuple, actual: restored);
8383
}
8484
}
85+
86+
[Test]
87+
public void ListCodecTest()
88+
{
89+
var codec = ListCodec.Instance;
90+
var items = new List<PyObject>() { new PyInt(1), new PyInt(2), new PyInt(3) };
91+
92+
var x = new PyList(items.ToArray());
93+
Assert.IsTrue(codec.CanDecode(x, typeof(List<int>)));
94+
Assert.IsTrue(codec.CanDecode(x, typeof(IList<bool>)));
95+
Assert.IsTrue(codec.CanDecode(x, typeof(System.Collections.IEnumerable)));
96+
Assert.IsTrue(codec.CanDecode(x, typeof(IEnumerable<int>)));
97+
Assert.IsTrue(codec.CanDecode(x, typeof(ICollection<float>)));
98+
Assert.IsFalse(codec.CanDecode(x, typeof(bool)));
99+
100+
System.Collections.IEnumerable plainEnumerable = null;
101+
Assert.DoesNotThrow(() => { codec.TryDecode<System.Collections.IEnumerable>(x, out plainEnumerable); });
102+
Assert.IsNotNull(plainEnumerable);
103+
IList<object> list = null;
104+
list = plainEnumerable.Cast<object>().ToList();
105+
Assert.AreEqual(list.Count, 3);
106+
Assert.AreEqual(list[0], 1);
107+
Assert.AreEqual(list[1], 2);
108+
Assert.AreEqual(list[2], 3);
109+
}
85110
}
86111

87112
/// <summary>

src/runtime/Codecs/ListCodec.cs

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Text;
6+
7+
namespace Python.Runtime.Codecs
8+
{
9+
class ListCodec : IPyObjectDecoder
10+
{
11+
public bool CanDecode(PyObject objectType, Type targetType)
12+
{
13+
//first check if the PyObject is iterable.
14+
IntPtr IterObject = Runtime.PyObject_GetIter(objectType.Handle);
15+
if (IterObject == IntPtr.Zero)
16+
return false;
17+
18+
//if it is a plain IEnumerable, we can decode it using sequence protocol.
19+
if (targetType == typeof(System.Collections.IEnumerable))
20+
return true;
21+
22+
//if its not a plain IEnumerable it must be a generic type
23+
if (!targetType.IsGenericType) return false;
24+
25+
Predicate<Type> IsCLRSequence = (Type type) => {
26+
return (type.GetGenericTypeDefinition() == typeof(IEnumerable<>) ||
27+
type.GetGenericTypeDefinition() == typeof(ICollection<>) ||
28+
type.GetGenericTypeDefinition() == typeof(IList<>));
29+
};
30+
31+
if (IsCLRSequence(targetType))
32+
return true;
33+
34+
//if it implements any of the standard C# collection interfaces, we can decode it.
35+
foreach (Type itf in targetType.GetInterfaces())
36+
{
37+
if (IsCLRSequence(itf))
38+
return true;
39+
}
40+
41+
//TODO objectType should implement the Sequence protocol to be convertible to ICollection
42+
// and the list protocol to be convertible to IList. We should check for list first,
43+
// then collection, then enumerable
44+
45+
46+
//if we get here we cannot decode it.
47+
return false;
48+
}
49+
50+
private class PyEnumerable : System.Collections.IEnumerable
51+
{
52+
PyObject iterObject;
53+
internal PyEnumerable(PyObject pyObj)
54+
{
55+
iterObject = new PyObject(Runtime.PyObject_GetIter(pyObj.Handle));
56+
}
57+
58+
public IEnumerator GetEnumerator()
59+
{
60+
IntPtr item;
61+
while ((item = Runtime.PyIter_Next(iterObject.Handle)) != IntPtr.Zero)
62+
{
63+
object obj = null;
64+
if (!Converter.ToManaged(item, typeof(object), out obj, true))
65+
{
66+
Runtime.XDecref(item);
67+
break;
68+
}
69+
70+
Runtime.XDecref(item);
71+
yield return obj;
72+
}
73+
}
74+
}
75+
76+
private object ToPlainEnumerable(PyObject pyObj)
77+
{
78+
return new PyEnumerable(pyObj);
79+
}
80+
81+
public bool TryDecode<T>(PyObject pyObj, out T value)
82+
{
83+
object var = null;
84+
//first see if T is a plan IEnumerable
85+
if (typeof(T) == typeof(System.Collections.IEnumerable))
86+
{
87+
var = ToPlainEnumerable(pyObj);
88+
}
89+
90+
value = (T)var;
91+
return false;
92+
}
93+
94+
public static ListCodec Instance { get; } = new ListCodec();
95+
96+
public static void Register()
97+
{
98+
PyObjectConversions.RegisterDecoder(Instance);
99+
}
100+
}
101+
}

0 commit comments

Comments
 (0)
0