-
Notifications
You must be signed in to change notification settings - Fork 634
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
Add tests for conversions in Python method calls #10840
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ public class PythonEvalTestsWithLibraries : DynamoModelTestBase | |
protected override void GetLibrariesToPreload(List<string> libraries) | ||
{ | ||
libraries.Add("FFITarget.dll"); | ||
libraries.Add("DSCoreNodes.dll"); | ||
} | ||
|
||
public IEnumerable<PythonEvaluatorDelegate> Evaluators = new List<PythonEvaluatorDelegate> { | ||
|
@@ -43,5 +44,164 @@ from FFITarget import DummyMath | |
Assert.AreEqual(expected, result); | ||
} | ||
} | ||
|
||
[Test] | ||
[Category("Failure")] | ||
public void TestListEncoding() | ||
{ | ||
string code = @" | ||
import sys | ||
import clr | ||
clr.AddReference('DSCoreNodes') | ||
from DSCore import List | ||
|
||
l = ['a'] | ||
# Python list => .NET IList - Does not work in CPython | ||
l = List.AddItemToEnd('b',l) | ||
# .NET IList => Python list - Does not work in IronPython. Couldn't test CPython because of previous bug | ||
# l.append('c') | ||
l.Add(c) | ||
|
||
OUT = l | ||
"; | ||
var empty = new ArrayList(); | ||
var expected = new ArrayList { "a", "b", "c" }; | ||
foreach (var pythonEvaluator in Evaluators) | ||
{ | ||
var result = pythonEvaluator(code, empty, empty); | ||
Assert.IsTrue(result is IEnumerable); | ||
CollectionAssert.AreEqual(expected, result as IEnumerable); | ||
} | ||
} | ||
|
||
[Test] | ||
public void TestArrayEncoding() | ||
{ | ||
string code = @" | ||
import sys | ||
import clr | ||
clr.AddReference('FFITarget') | ||
clr.AddReference('DSCoreNodes') | ||
from FFITarget import DummyCollection | ||
from DSCore import List | ||
from array import array | ||
|
||
# Python array => .NET IList - array is in a builtin library. This does not work in either engine | ||
# native = array('l', [1,2]) | ||
# native = List.AddItemToEnd(3, native) | ||
|
||
# .NET array => Python list - Works in both engines | ||
a = DummyCollection.MakeArray(1,2) | ||
a[0] = a[1] + 1 | ||
b = len(a) | ||
a[1] = b | ||
a = List.AddItemToEnd(1, a) | ||
|
||
OUT = a | ||
"; | ||
var empty = new ArrayList(); | ||
var expected = new ArrayList { 3, 2, 1 }; | ||
foreach (var pythonEvaluator in Evaluators) | ||
{ | ||
var result = pythonEvaluator(code, empty, empty); | ||
Assert.IsTrue(result is IEnumerable); | ||
CollectionAssert.AreEqual(expected, result as IEnumerable); | ||
} | ||
} | ||
|
||
[Test] | ||
[Category("Failure")] | ||
public void TestTupleEncoding() | ||
{ | ||
string code = @" | ||
import sys | ||
import clr | ||
clr.AddReference('FFITarget') | ||
clr.AddReference('DSCoreNodes') | ||
from FFITarget import DummyCollection | ||
from DSCore import List | ||
|
||
t = (1,2,3) | ||
# Python tuple => .NET array - Works in both | ||
a = DummyCollection.MakeArray(t) | ||
# Python tuple => .NET IList - Does not work in CPython | ||
l = List.AddItemToEnd(4, t) | ||
|
||
OUT = a, l | ||
"; | ||
var empty = new ArrayList(); | ||
var expected = new ArrayList { new ArrayList { 1, 2, 3 }, new ArrayList { 1, 2, 3, 4 } }; | ||
foreach (var pythonEvaluator in Evaluators) | ||
{ | ||
var result = pythonEvaluator(code, empty, empty); | ||
Assert.IsTrue(result is IEnumerable); | ||
CollectionAssert.AreEqual(expected, result as IEnumerable); | ||
} | ||
} | ||
|
||
[Test] | ||
[Category("Failure")] | ||
public void TestRangeEncoding() | ||
{ | ||
string code = @" | ||
import sys | ||
import clr | ||
clr.AddReference('FFITarget') | ||
clr.AddReference('DSCoreNodes') | ||
from FFITarget import DummyCollection | ||
from DSCore import List | ||
|
||
r = range(0, 10, 2) | ||
# Python range => .NET array - Works in both | ||
a = DummyCollection.MakeArray(r) | ||
# Python range => .NET IList - Does not work in CPython | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are Python ranges mutable? Do they result in lists or arrays? Please bear with the ignorant questions - I'm not a Python expert. Could there by differences in IronPython vs. CPython in the way that tuples, ranges, etc. behave in terms of mutability? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not problem at all. These are very good questions @aparajit-pratap .
What happens when a Python primitive gets passed to a .NET function call, is that the primitive gets converted to a .NET object. This means that in practice they are not mutable because what we get is not even in the Python world.
This will depend on the declared type in the function call. Support for arrays was already built into Python.NET. For lists, a few minor changes were needed, but most of the logic can be reused.
I don't think I have tested that. That's a very good point. I'll take a look at IronPython and see if I'm able to mutate a list for instance. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just checked and mutability can be achieved in IronPython for a List. You need to use a Zero Touch node to test it though, because List methods always make a copy. |
||
l = List.AddItemToEnd(10, r) | ||
|
||
OUT = a, l | ||
"; | ||
var empty = new ArrayList(); | ||
var expected = new ArrayList { new ArrayList { 0, 2, 4, 6, 8 }, new ArrayList { 0, 2, 4, 6, 8, 10 } }; | ||
foreach (var pythonEvaluator in Evaluators) | ||
{ | ||
var result = pythonEvaluator(code, empty, empty); | ||
Assert.IsTrue(result is IEnumerable); | ||
CollectionAssert.AreEqual(expected, result as IEnumerable); | ||
} | ||
} | ||
|
||
[Test] | ||
[Category("Failure")] | ||
public void TestDictionaryEncoding() | ||
{ | ||
string code = @" | ||
import sys | ||
import clr | ||
clr.AddReference('FFITarget') | ||
clr.AddReference('DesignScriptBuiltin') | ||
from DesignScript.Builtin import Dictionary | ||
from FFITarget import DummyCollection | ||
|
||
d = {'one': 1, 'two': 2, 'three': 3} | ||
# Python dict => DS Dictionary - Does not work in either engine | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure if this is intended. It would be good to have but if it were to be supported, we would most likely need to make custom changes in pythonnet for interop with DS that would not be accepted by the main repo for back-porting and we would need to continue to maintain our own custom fork. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We didn't do it for IronPython either. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the feedback. I thought of a way to do this without referencing DS Dictionary in Python.NET. What we would do is a two step conversion:
|
||
# d2 = Dictionary.SetValueAtKeys(d, ['four'], [4]) | ||
|
||
# Python dict => .NET IDictionary - Does not work in CPython | ||
d = DummyCollection.AcceptIDictionary(d) | ||
# .NET IDictionary => Python dict - Works in IronPython. Could not test in CPython due to previous bug | ||
d['five'] = 5 | ||
|
||
OUT = d | ||
"; | ||
var empty = new ArrayList(); | ||
var expected = new Dictionary<string, int> { | ||
{ "one", 1 }, { "two", 2 }, { "three", 3 }, { "five", 5 } | ||
}; | ||
foreach (var pythonEvaluator in Evaluators) | ||
{ | ||
var result = pythonEvaluator(code, empty, empty); | ||
Assert.IsTrue(result is IDictionary); | ||
CollectionAssert.AreEquivalent(expected, result as IDictionary); | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are Python tuples mutable?