Skip to content

Commit

Permalink
Add marshaling between Dynamo and Python dictionaries (#9296)
Browse files Browse the repository at this point in the history
* add marshaling between Dynamo and Python dictionaries

* revert assemblysharedinfo file

* add tests

* updated Python-JSON test graph
  • Loading branch information
aparajit-pratap authored Dec 10, 2018
1 parent 615c080 commit f9dab2e
Show file tree
Hide file tree
Showing 9 changed files with 515 additions and 56 deletions.
6 changes: 4 additions & 2 deletions src/DynamoUtilities/DataMarshaler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ public class DataMarshaler

public DataMarshaler()
{
//RegisterMarshaler((IEnumerable e) => e.Cast<object>().Select(Marshal));
RegisterMarshaler((IList e) => e.Cast<object>().Select(Marshal).ToList());
RegisterMarshaler(
(IDictionary dict) =>
dict.Cast<dynamic>().ToDictionary(x => Marshal(x.Key), x => Marshal(x.Value)));
{
// Dictionary<TKey, TValue> and IronPython.Runtime.PythonDictionary both implement IDictionary
return dict.Keys.Cast<object>().ToDictionary(key => Marshal(key), key => Marshal(dict[key]));
});
}

/// <summary>
Expand Down
10 changes: 5 additions & 5 deletions src/Libraries/DSIronPython/DSIronPython.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@
<Name>DynamoServices</Name>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\DesignScriptBuiltin\DesignScriptBuiltin.csproj">
<Project>{c0d6dee5-5532-4345-9c66-4c00d7fdb8be}</Project>
<Name>DesignScriptBuiltin</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
Expand All @@ -107,10 +111,6 @@
<ItemGroup>
<PythonStdLib Include="$(ProjectDir)..\..\packages\IronPython.StdLib.2.7.8.1\contentFiles\any\any\Lib\**\*.*" />
</ItemGroup>
<Copy
SourceFiles="@(PythonStdLib)"
DestinationFiles="@(PythonStdLib->'$(TargetDir)IronPython.StdLib.2.7.8\%(RecursiveDir)%(Filename)%(Extension)')"
SkipUnchangedFiles="true"
/>
<Copy SourceFiles="@(PythonStdLib)" DestinationFiles="@(PythonStdLib->'$(TargetDir)IronPython.StdLib.2.7.8\%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="true" />
</Target>
</Project>
14 changes: 13 additions & 1 deletion src/Libraries/DSIronPython/IronPythonEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using IronPython.Hosting;

using Microsoft.Scripting.Hosting;
using Microsoft.Scripting.Utils;

namespace DSIronPython
{
Expand Down Expand Up @@ -54,7 +55,8 @@ private static string pythonStandardLibPath()
// Return the standard library path
if (!string.IsNullOrEmpty(dynamoCorePath))
{ return dynamoCorePath + @"\IronPython.StdLib.2.7.8"; }
else { return null; }

return null;
}

/// <summary>
Expand Down Expand Up @@ -155,6 +157,16 @@ public static DataMarshaler InputMarshaler
}
return pyList;
});
inputMarshaler.RegisterMarshaler(
delegate (DesignScript.Builtin.Dictionary dict)
{
var pyDict = new IronPython.Runtime.PythonDictionary();
foreach (var key in dict.Keys)
{
pyDict.Add(inputMarshaler.Marshal(key), inputMarshaler.Marshal(dict.ValueAtKey(key)));
}
return pyDict;
});
}
return inputMarshaler;
}
Expand Down
59 changes: 44 additions & 15 deletions test/DynamoCoreTests/DSEvaluationUnitTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ protected void AssertValue(MirrorData data, object value)
{
if (!(value is IEnumerable))
{
Assert.Fail("Data is collection but expected vlaue is not.");
Assert.Fail("Data is collection but expected value is not.");
}
AssertCollection(data, value as IEnumerable);
}
Expand All @@ -180,7 +180,7 @@ protected void AssertValue(MirrorData data, object value)
try
{
double mirrorData = Convert.ToDouble(data.Data);
Assert.AreEqual((double)value, Convert.ToDouble(data.Data), 0.00001);
Assert.AreEqual((double)value, mirrorData, 0.00001);
}
catch (Exception e)
{
Expand All @@ -191,30 +191,59 @@ protected void AssertValue(MirrorData data, object value)
{
Assert.AreEqual(data.Class.ClassName, value);
}
else if (data.IsPointer && value is DesignScript.Builtin.Dictionary)
else if (data.IsDictionary)
{
var thisData = data.Data as DesignScript.Builtin.Dictionary;

if (thisData == null)
if (value is DesignScript.Builtin.Dictionary)
{
Assert.Fail("Data is expected to be DS Dictionary but is not.");
}
var otherVal = (DesignScript.Builtin.Dictionary) value;
var otherVal = (DesignScript.Builtin.Dictionary) value;

if (otherVal.Count != thisData.Count)
{
Assert.Fail("Data and expected value are 2 different dictionaries.");
if (otherVal.Count != thisData.Count)
{
Assert.Fail("Data and expected value are 2 different dictionaries.");
}

foreach (var key in otherVal.Keys)
{
var val = thisData.ValueAtKey(key);
if (val == null)
{
Assert.Fail("Data and expected value are 2 different dictionaries.");
}

if (val.GetType().IsValueType)
{
Assert.AreEqual(val, thisData.ValueAtKey(key));
}
}
}
foreach (var key in otherVal.Keys)
else if (value is IDictionary)
{
var val = thisData.ValueAtKey(key);
if (val == null)
var otherVal = (IDictionary)value;

if (otherVal.Count != thisData.Count)
{
Assert.Fail("Data and expected value are 2 different dictionaries.");
}
if (val.GetType().IsValueType)

foreach (var key in otherVal.Keys)
{
Assert.AreEqual(val, thisData.ValueAtKey(key));
if (!(key is string))
{
Assert.Fail("Expected value is a dictionary with non-string key(s).");
}
var strKey = (string) key;
var val = thisData.ValueAtKey(strKey);
if (val == null)
{
Assert.Fail("Data and expected value are 2 different dictionaries.");
}

if (val.GetType().IsValueType)
{
Assert.AreEqual(val, thisData.ValueAtKey(strKey));
}
}
}
}
Expand Down
40 changes: 39 additions & 1 deletion test/Libraries/DynamoPythonTests/PythonEditTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class PythonEditTests : DynamoViewModelUnitTest
{
protected override void GetLibrariesToPreload(List<string> libraries)
{
libraries.Add("DesignScriptBuiltin.dll");
libraries.Add("DSIronPython.dll");
base.GetLibrariesToPreload(libraries);
}
Expand Down Expand Up @@ -159,7 +160,7 @@ public void VerifyPythonLoadsFromCore()
foreach(NodeModel node in allNodes) {
var guid = node.GUID.ToString();

// if node is a test node, verify truthy value
// if node is a test node, verify truth value
if (testingNodeGUIDS.Contains(guid) ) {
AssertPreviewValue(guid, true);
}
Expand All @@ -169,6 +170,43 @@ public void VerifyPythonLoadsFromCore()
Assert.NotNull(pynode);
}

[Test]
public void ReturnPythonDictionary_AsDynamoDictionary()
{
// open test graph
var examplePath = Path.Combine(TestDirectory, @"core\python", "python_dict.dyn");
ViewModel.OpenCommand.Execute(examplePath);

var guid = "490a8d54d0fa4782ae18c81f6eef8306";

AssertPreviewValue(guid, new Dictionary<string, int> { { "abc", 123 }, { "def", 345 } });
}

[Test]
public void InputDynamoDictionary_AsPythonDictionary()
{
// open test graph
var examplePath = Path.Combine(TestDirectory, @"core\python", "python_dict2.dyn");
ViewModel.OpenCommand.Execute(examplePath);

var guid = "490a8d54d0fa4782ae18c81f6eef8306";

AssertPreviewValue(guid,
new List<object> {new Dictionary<string, int> {{"abcd", 123}}, new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9}});
}

[Test]
public void ReturnIronPythonDictionary_AsDynamoDictionary()
{
// open test graph
var examplePath = Path.Combine(TestDirectory, @"core\python", "netDict_from_python.dyn");
ViewModel.OpenCommand.Execute(examplePath);

var guid = "490a8d54d0fa4782ae18c81f6eef8306";

AssertPreviewValue(guid, new Dictionary<string, int> {{"abc", 123}, {"def", 10}});
}

private void UpdatePythonNodeContent(ModelBase pythonNode, string value)
{
var command = new DynCmd.UpdateModelValueCommand(
Expand Down
Loading

0 comments on commit f9dab2e

Please sign in to comment.