8000 Merge pull request #37 from QuantConnect/bug-pylist-to-csharplist-rou… · saaib/pythonnet@b97e38e · GitHub
[go: up one dir, main page]

Skip to content

Commit b97e38e

Browse files
authored
Merge pull request QuantConnect#37 from QuantConnect/bug-pylist-to-csharplist-round-conversion
PyList to C# List round trip conversion
2 parents c5b4baa + 079949a commit b97e38e

File tree

8 files changed

+96
-20
lines changed

8 files changed

+96
-20
lines changed

.bumpversion.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[bumpversion]
2-
current_version = 1.0.5.25
2+
current_version = 1.0.5.26
33
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\.(?P<release>[a-z]+)(?P<dev>\d+))?
44
serialize =
55
{major}.{minor}.{patch}.{release}{dev}

conda.recipe/meta.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package:
22
name: pythonnet
3-
version: "1.0.5.25"
3+
version: "1.0.5.26"
44

55
build:
66
skip: True # [not win]

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,7 @@ def run(self):
485485

486486
setup(
487487
name="pythonnet",
488-
version="1.0.5.25",
488+
version="1.0.5.26",
489489
description=".Net and Mono integration for Python",
490490
url='https://pythonnet.github.io/',
491491
license='MIT',

src/SharedAssemblyInfo.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,4 @@
2525
// Version Information. Keeping it simple. May need to revisit for Nuget
2626
// See: https://codingforsmarties.wordpress.com/2016/01/21/how-to-version-assemblies-destined-for-nuget/
2727
// AssemblyVersion can only be numeric
28-
[assembly: AssemblyVersion("1.0.5.25")]
28+
[assembly: AssemblyVersion("1.0.5.26")]

src/clrmodule/ClrModule.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public static void initclr()
5353
{
5454
#if USE_PYTHON_RUNTIME_VERSION
5555
// Has no effect until SNK works. Keep updated anyways.
56-
Version = new Version("1.0.5.25"),
56+
Version = new Version("1.0.5.26"),
5757
#endif
5858
CultureInfo = CultureInfo.InvariantCulture
5959
};

src/embed_tests/TestConverter.cs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using NUnit.Framework;
1+
using System;
2+
using System.Collections.Generic;
3+
using NUnit.Framework;
24
using Python.Runtime;
35

46
namespace Python.EmbeddingTest
@@ -17,6 +19,30 @@ public void Dispose()
1719
PythonEngine.Shutdown();
1820
}
1921

22+
[Test]
23+
public void ConvertListRoundTrip()
24+
{
25+
var list = new List<Type> { typeof(decimal), typeof(int) };
26+
var py = list.ToPython();
27+
object result;
28+
var converted = Converter.ToManaged(py.Handle, typeof(List<Type>), out result, false);
29+
30+
Assert.IsTrue(converted);
31+
Assert.AreEqual(result, list);
32+
}
33+
34+
[Test]
35+
public void ConvertPyListToArray()
36+
{
37+
var array = new List<Type> { typeof(decimal), typeof(int) };
38+
var py = array.ToPython();
39+
object result;
40+
var converted = Converter.ToManaged(py.Handle, typeof(Type[]), out result, false);
41+
42+
Assert.IsTrue(converted);
43+
Assert.AreEqual(result, array);
44+
}
45+
2046
[Test]
2147
public void TestConvertSingleToManaged(
2248
[Values(float.PositiveInfinity, float.NegativeInfinity, float.MinValue, float.MaxValue, float.NaN,

src/runtime/converter.cs

Lines changed: 63 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections;
3+
using System.Collections.Generic;
34
using System.Globalization;
45
using System.Runtime.InteropServices;
56
using System.Security;
@@ -166,19 +167,20 @@ internal static IntPtr ToPython(object value, Type type)
166167
return result;
167168
}
168169

169-
if (value is IList && value.GetType().IsGenericType)
170+
var list = value as IList;
171+
if (list != null && value.GetType().IsGenericType)
170172
{
171-
using (var resultlist = new PyList())
173+
using (var resultList = new PyList())
172174
{
173-
foreach (object o in (IEnumerable)value)
175+
for (var i = 0; i < list.Count; i++)
174176
{
175-
using (var p = new PyObject(ToPython(o, o?.GetType())))
177+
using (var p = list[i].ToPython())
176178
{
177-
resultlist.Append(p);
179+
resultList.Append(p);
178180
}
179181
}
180-
Runtime.XIncref(resultlist.Handle);
181-
return resultlist.Handle;
182+
Runtime.XIncref(resultList.Handle);
183+
return resultList.Handle;
182184
}
183185
}
184186

@@ -382,6 +384,15 @@ internal static bool ToManagedValue(IntPtr value, Type obType,
382384
return true;
383385
}
384386

387+
if(obType.IsGenericType && Runtime.PyObject_TYPE(value) == Runtime.PyListType)
388+
{
389+
var typeDefinition = obType.GetGenericTypeDefinition();
390+
if (typeDefinition == typeof(List<>))
391+
{
392+
return ToList(value, obType, out result, setError);
393+
}
394+
}
395+
385396
// Common case: if the Python value is a wrapped managed object
386397
// instance, just return the wrapped object.
387398
ManagedType mt = ManagedType.GetManagedObject(value);
@@ -1003,7 +1014,6 @@ private static void SetConversionError(IntPtr value, Type target)
10031014
Exceptions.SetError(Exceptions.TypeError, $"Cannot convert {src} to {target}");
10041015
}
10051016

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

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

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

1029-
// XXX - is there a better way to unwrap this if it is a real array?
1039+
var index = 0;
1040+
result = items;
1041+
return ApplyActionToPySequence(value, obType, setError, size, elementType, o =>
1042+
{
1043+
items.SetValue(o, index++);
1044+
});
1045+
}
1046+
1047+
/// <summary>
1048+
/// Convert a Python value to a correctly typed managed list instance.
1049+
/// The Python value must support the Python sequence protocol and the
1050+
/// items in the sequence must be convertible to the target list type.
1051+
/// </summary>
1052+
private static bool ToList(IntPtr value, Type obType, out object result, bool setError)
1053+
{
1054+
var elementType = obType.GetGenericArguments()[0];
1055+
var size = Runtime.PySequence_Size(value);
1056+
1057+
result = Activator.CreateInstance(obType, args: size);
1058+
var resultList = (IList)result;
1059+
return ApplyActionToPySequence(value, obType, setError, size, elementType, o => resultList.Add(o));
1060+
}
1061+
1062+
/// <summary>
1063+
/// Helper method that will enumerate a Python sequence convert its values to the given
1064+
/// type and send them to the provided action
1065+
/// </summary>
1066+
private static bool ApplyActionToPySequence(IntPtr value,
1067+
Type obType,
1068+
bool setError,
1069+
int size,
1070+
Type elementType,
1071+
Action<object> action)
1072+
{
1073+
if (size < 0)
1074+
{
1075+
if (setError)
1076+
{
1077+
SetConversionError(value, obType);
1078+
}
1079+
return false;
1080+
}
1081+
10301082
for (var i = 0; i < size; i++)
10311083
{
10321084
object obj = null;
@@ -1046,15 +1098,13 @@ private static bool ToArray(IntPtr value, Type obType, out object result, bool s
10461098
return false;
10471099
}
10481100

1049-
items.SetValue(obj, i);
1101+
action(obj);
10501102
Runtime.XDecref(item);
10511103
}
10521104

1053-
result = items;
10541105
return true;
10551106
}
10561107

1057-
10581108
/// <summary>
10591109
/// Convert a Python value to a correctly typed managed enum instance.
10601110
/// </summary>

src/runtime/resources/clr.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Code in this module gets loaded into the main clr module.
33
"""
44

5-
__version__ = "1.0.5.25"
5+
__version__ = "1.0.5.26"
66

77

88
class clrproperty(object):

0 commit comments

Comments
 (0)
0