/
IronPythonEvaluator.cs
183 lines (159 loc) · 6.91 KB
/
IronPythonEvaluator.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
using System;
using System.Collections;
using System.Linq;
using Autodesk.DesignScript.Runtime;
using Dynamo.Utilities;
using IronPython.Hosting;
using Microsoft.Scripting.Hosting;
namespace DSIronPython
{
[SupressImportIntoVM]
public enum EvaluationState { Begin, Success, Failed }
[SupressImportIntoVM]
public delegate void EvaluationEventHandler(EvaluationState state,
ScriptEngine engine,
ScriptScope scope,
string code,
IList bindingValues);
/// <summary>
/// Evaluates a Python script in the Dynamo context.
/// </summary>
[IsVisibleInDynamoLibrary(false)]
public static class IronPythonEvaluator
{
/// <summary> stores a copy of the previously executed code</summary>
private static string prev_code { get; set; }
/// <summary> stores a copy of the previously compiled engine</summary>
private static ScriptSource prev_script { get; set; }
/// <summary>
/// Executes a Python script with custom variable names. Script may be a string
/// read from a file, for example. Pass a list of names (matching the variable
/// names in the script) to bindingNames and pass a corresponding list of values
/// to bindingValues.
/// </summary>
/// <param name="code">Python script as a string.</param>
/// <param name="bindingNames">Names of values referenced in Python script.</param>
/// <param name="bindingValues">Values referenced in Python script.</param>
public static object EvaluateIronPythonScript(
string code,
IList bindingNames,
[ArbitraryDimensionArrayImport] IList bindingValues)
{
if (code != prev_code)
{
ScriptSource script = Python.CreateEngine().CreateScriptSourceFromString(code);
script.Compile();
prev_script = script;
prev_code = code;
}
ScriptEngine engine = prev_script.Engine;
ScriptScope scope = engine.CreateScope();
int amt = Math.Min(bindingNames.Count, bindingValues.Count);
for (int i = 0; i < amt; i++)
{
scope.SetVariable((string)bindingNames[i], InputMarshaler.Marshal(bindingValues[i]));
}
try
{
OnEvaluationBegin(engine, scope, code, bindingValues);
prev_script.Execute(scope);
}
catch (Exception e)
{
OnEvaluationEnd(false, engine, scope, code, bindingValues);
var eo = engine.GetService<ExceptionOperations>();
string error = eo.FormatException(e);
throw new Exception(error);
}
OnEvaluationEnd(true, engine, scope, code, bindingValues);
var result = scope.ContainsVariable("OUT") ? scope.GetVariable("OUT") : null;
return OutputMarshaler.Marshal(result);
}
#region Marshalling
/// <summary>
/// Data Marshaler for all data coming into a Python node.
/// </summary>
[SupressImportIntoVM]
public static DataMarshaler InputMarshaler
{
get
{
if (inputMarshaler == null)
{
inputMarshaler = new DataMarshaler();
inputMarshaler.RegisterMarshaler(
delegate(IList lst)
{
var pyList = new IronPython.Runtime.List();
foreach (var item in lst.Cast<object>().Select(inputMarshaler.Marshal))
{
pyList.Add(item);
}
return pyList;
});
}
return inputMarshaler;
}
}
/// <summary>
/// Data Marshaler for all data coming out of a Python node.
/// </summary>
[SupressImportIntoVM]
public static DataMarshaler OutputMarshaler
{
get { return outputMarshaler ?? (outputMarshaler = new DataMarshaler()); }
}
private static DataMarshaler inputMarshaler;
private static DataMarshaler outputMarshaler;
#endregion
#region Evaluation events
/// <summary>
/// Emitted immediately before execution begins
/// </summary>
[SupressImportIntoVM]
public static event EvaluationEventHandler EvaluationBegin;
/// <summary>
/// Emitted immediately after execution ends or fails
/// </summary>
[SupressImportIntoVM]
public static event EvaluationEventHandler EvaluationEnd;
/// <summary>
/// Called immediately before evaluation starts
/// </summary>
/// <param name="engine">The engine used to do the evaluation</param>
/// <param name="scope">The scope in which the code is executed</param>
/// <param name="code">The code to be evaluated</param>
/// <param name="bindingValues">The binding values - these are already added to the scope when called</param>
private static void OnEvaluationBegin( ScriptEngine engine,
ScriptScope scope,
string code,
IList bindingValues )
{
if (EvaluationBegin != null)
{
EvaluationBegin(EvaluationState.Begin, engine, scope, code, bindingValues);
}
}
/// <summary>
/// Called when the evaluation has completed successfully or failed
/// </summary>
/// <param name="isSuccessful">Whether the evaluation succeeded or not</param>
/// <param name="engine">The engine used to do the evaluation</param>
/// <param name="scope">The scope in which the code is executed</param>
/// <param name="code">The code to that was evaluated</param>
/// <param name="bindingValues">The binding values - these are already added to the scope when called</param>
private static void OnEvaluationEnd( bool isSuccessful,
ScriptEngine engine,
ScriptScope scope,
string code,
IList bindingValues)
{
if (EvaluationEnd != null)
{
EvaluationEnd( isSuccessful ? EvaluationState.Success : EvaluationState.Failed,
engine, scope, code, bindingValues);
}
}
#endregion
}
}