10000 PyList to C# List round trip conversion by Martin-Molinero · Pull Request #37 · QuantConnect/pythonnet · GitHub
[go: up one dir, main page]

Skip to content

PyList to C# List round trip conversion #37

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 2 commits into from
Oct 15, 2019
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
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 1.0.5.25
current_version = 1.0.5.26
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\.(?P<release>[a-z]+)(?P<dev>\d+))?
serialize =
{major}.{minor}.{patch}.{release}{dev}
Expand Down
2 changes: 1 addition & 1 deletion conda.recipe/meta.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package:
name: pythonnet
version: "1.0.5.25"
version: "1.0.5.26"

build:
skip: True # [not win]
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ def run(self):

setup(
name="pythonnet",
version="1.0.5.25",
version="1.0.5.26",
description=".Net and Mono integration for Python",
url='https://pythonnet.github.io/',
license='MIT',
Expand Down
2 changes: 1 addition & 1 deletion src/SharedAssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@
// Version Information. Keeping it simple. May need to revisit for Nuget
// See: https://codingforsmarties.wordpress.com/2016/01/21/how-to-version-assemblies-destined-for-nuget/
// AssemblyVersion can only be numeric
[assembly: AssemblyVersion("1.0.5.25")]
[assembly: AssemblyVersion("1.0.5.26")]
2 changes: 1 addition & 1 deletion src/clrmodule/ClrModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public static void initclr()
{
#if USE_PYTHON_RUNTIME_VERSION
// Has no effect until SNK works. Keep updated anyways.
Version = new Version("1.0.5.25"),
Version = new Version("1.0.5.26"),
#endif
CultureInfo = CultureInfo.InvariantCulture
};
Expand Down
28 changes: 27 additions & 1 deletion src/embed_tests/TestConverter.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using NUnit.Framework;
using System;
using System.Collections.Generic;
using NUnit.Framework;
using Python.Runtime;

namespace Python.EmbeddingTest
Expand All @@ -17,6 +19,30 @@ public void Dispose()
PythonEngine.Shutdown();
}

[Test]
public void ConvertListRoundTrip()
{
var list = new List<Type> { typeof(decimal), typeof(int) };
var py = list.ToPython();
object result;
var converted = Converter.ToManaged(py.Handle, typeof(List<Type>), out result, false);

Assert.IsTrue(converted);
Assert.AreEqual(result, list);
}

[Test]
public void ConvertPyListToArray()
{
var array = new List<Type> { typeof(decimal), typeof(int) };
var py = array.ToPython();
object result;
var converted = Converter.ToManaged(py.Handle, typeof(Type[]), out result, false);

Assert.IsTrue(converted);
Assert.AreEqual(result, array);
}

[Test]
public void TestConvertSingleToManaged(
[Values(float.PositiveInfinity, float.NegativeInfinity, float.MinValue, float.MaxValue, float.NaN,
Expand Down
76 changes: 63 additions & 13 deletions src/runtime/converter.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Security;
Expand Down Expand Up @@ -166,19 +167,20 @@ internal static IntPtr ToPython(object value, Type type)
return result;
}

if (value is IList && value.GetType().IsGenericType)
var list = value as IList;
if (list != null && value.GetType().IsGenericType)
{
using (var resultlist = new PyList())
using (var resultList = new PyList())
{
foreach (object o in (IEnumerable)value)
for (var i = 0; i < list.Count; i++)
{
using (var p = new PyObject(ToPython(o, o?.GetType())))
using (var p = list[i].ToPython())
{
resultlist.Append(p);
resultList.Append(p);
}
}
Runtime.XIncref(resultlist.Handle);
return resultlist.Handle;
Runtime.XIncref(resultList.Handle);
return resultList.Handle;
}
}

Expand Down Expand Up @@ -382,6 +384,15 @@ internal static bool ToManagedValue(IntPtr value, Type obType,
return true;
}

if(obType.IsGenericType && Runtime.PyObject_TYPE(value) == Runtime.PyListType)
{
var typeDefinition = obType.GetGenericTypeDefinition();
if (typeDefinition == typeof(List<>))
{
return ToList(value, obType, out result, setError);
}
}

// Common case: if the Python value is a wrapped managed object
// instance, just return the wrapped object.
ManagedType mt = ManagedType.GetManagedObject(value);
Expand Down Expand Up @@ -1003,7 +1014,6 @@ private static void SetConversionError(IntPtr value, Type target)
Exceptions.SetError(Exceptions.TypeError, $"Cannot convert {src} to {target}");
}


/// <summary>
/// Convert a Python value to a correctly typed managed array instance.
/// The Python value must support the Python sequence protocol and the
Expand All @@ -1015,7 +1025,7 @@ private static bool ToArray(IntPtr value, Type obType, out object result, bool s
int size = Runtime.PySequence_Size(value);
result = null;

if (size < 0 || elementType.IsGenericType)
if (elementType.IsGenericType)
{
if (setError)
{
Expand All @@ -1026,7 +1036,49 @@ private static bool ToArray(IntPtr value, Type obType, out object result, bool s

Array items = Array.CreateInstance(elementType, size);

// XXX - is there a better way to unwrap this if it is a real array?
var index = 0;
result = items;
return ApplyActionToPySequence(value, obType, setError, size, elementType, o =>
{
items.SetValue(o, index++);
});
}

/// <summary>
/// Convert a Python value to a correctly typed managed list instance.
/// The Python value must support the Python sequence protocol and the
/// items in the sequence must be convertible to the target list type.
/// </summary>
private static bool ToList(IntPtr value, Type obType, out object result, bool setError)
{
var elementType = obType.GetGenericArguments()[0];
var size = Runtime.PySequence_Size(value);

result = Activator.CreateInstance(obType, args: size);
var resultList = (IList)result;
return ApplyActionToPySequence(value, obType, setError, size, elementType, o => resultList.Add(o));
}

/// <summary>
/// Helper method that will enumerate a Python sequence convert its values to the given
/// type and send them to the provided action
/// </summary>
private static bool ApplyActionToPySequence(IntPtr value,
Type obType,
bool setError,
int size,
Type elementType,
Action<object> action)
{
if (size < 0)
{
if (setError)
{
SetConversionError(value, obType);
}
return false;
}

for (var i = 0; i < size; i++)
{
object obj = null;
Expand All @@ -1046,15 +1098,13 @@ private static bool ToArray(IntPtr value, Type obType, out object result, bool s
return false;
}

items.SetValue(obj, i);
action(obj);
Runtime.XDecref(item);
}

result = items;
return true;
}


/// <summary>
/// Convert a Python value to a correctly typed managed enum instance.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/resources/clr.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Code in this module gets loaded into the main clr module.
"""

__version__ = "1.0.5.25"
__version__ = "1.0.5.26"


class clrproperty(object):
Expand Down
0