Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
131 changes: 126 additions & 5 deletions DSPythonNet3/Encoders/ListEncodeDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,39 @@ public bool TryDecode<T>(PyObject pyObj, out T value)
return false;
}

using (var pyList = PyList.AsList(pyObj))
if (typeof(T).IsGenericType)
{
if (typeof(T).IsGenericType)
var genericDef = typeof(T).GetGenericTypeDefinition();
var elementType = typeof(T).GetGenericArguments().FirstOrDefault();

if (elementType != null && (genericDef == typeof(IEnumerable<>) || genericDef == typeof(List<>) || genericDef == typeof(IList<>)))
{
value = pyList.ToList<T>();
using var pyList = PyList.AsList(pyObj);
var listType = typeof(List<>).MakeGenericType(elementType);
var typedList = (IList)Activator.CreateInstance(listType)!;

foreach (PyObject item in pyList)
{
using (item)
{
typedList.Add(ConvertGenericItem(item, elementType));
}
}

value = (T)typedList;
return true;
}
else

using (var pyList = PyList.AsList(pyObj))
{
value = (T)pyList.ToList();
value = pyList.ToList<T>();
}
return true;
}

var converted = ConvertToArrayList(pyObj);
value = (T)converted;
return true;
}

public PyObject TryEncode(object value)
Expand All @@ -57,5 +78,105 @@ bool IPyObjectDecoder.CanDecode(PyType objectType, Type targetType)
}
return decodableTypes.IndexOf(targetType) >= 0;
}

private static IList ConvertToArrayList(PyObject pyObj)
{
using var pyList = PyList.AsList(pyObj);
var result = new ArrayList();
foreach (PyObject item in pyList)
{
using (item)
{
result.Add(ConvertItem(item));
}
}
return result;
}

private static object ConvertItem(PyObject item)
{
if (TryGetClrObject(item, out var clrObject))
{
return clrObject;
}

if (PyInt.IsIntType(item))
{
using var pyLong = PyInt.AsInt(item);
try { return pyLong.ToInt64(); }
catch (PythonException ex) when (ex.Message.StartsWith("int too big"))
{
return pyLong.ToBigInteger();
}
}

if (PyFloat.IsFloatType(item))
{
using var pyFloat = PyFloat.AsFloat(item);
return pyFloat.ToDouble();
}

if (PyString.IsStringType(item))
{
return item.AsManagedObject(typeof(string));
}

if (PyList.IsListType(item) || PyTuple.IsTupleType(item))
{
return ConvertToArrayList(item);
}

return item.AsManagedObject(typeof(object));
}

private static bool TryGetClrObject(PyObject pyObj, out object clrObject)
{
try
{
clrObject = pyObj.GetManagedObject();
if (clrObject is PyObject || clrObject is null)
{
clrObject = null;
return false;
}
return true;
}
catch
{
clrObject = null;
return false;
}
}

private static object ConvertGenericItem(PyObject item, Type elementType)
{
if (elementType == typeof(object))
{
return ConvertItem(item);
}

if (TryGetClrObject(item, out var clrObject) && elementType.IsInstanceOfType(clrObject))
{
return clrObject;
}

if (PyList.IsListType(item) || PyTuple.IsTupleType(item))
{
// recursively decode nested generics
var listType = typeof(List<>).MakeGenericType(elementType);
var nestedList = (IList)Activator.CreateInstance(listType)!;
using var pyList = PyList.AsList(item);
foreach (PyObject child in pyList)
{
using (child)
{
nestedList.Add(ConvertGenericItem(child, elementType));
}
}
return nestedList;
}

return item.AsManagedObject(elementType);
}
}
}
2 changes: 1 addition & 1 deletion pipeline.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: 1.4.5
version: 1.4.6
pipeline_os: windows
create_pr_release_to_master: true

Expand Down
Loading