-
Notifications
You must be signed in to change notification settings - Fork 636
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
Refactor python engines api #14940
base: master
Are you sure you want to change the base?
Refactor python engines api #14940
Changes from 6 commits
fbcdab5
7d35c36
dac5b25
577c932
a012e57
395f9fa
75016e0
0c393c2
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 |
---|---|---|
|
@@ -111,12 +111,52 @@ | |
public static PythonEngineManager Instance { get { return lazy.Value; } } | ||
#endregion | ||
|
||
//TODO see DYN-6550 when hiding/replacing this obsolete field. | ||
/// <summary> | ||
/// A readonly collection of all the loaded Python engines | ||
/// </summary> | ||
public ReadOnlyCollection<PythonEngine> PythonEngines => new ReadOnlyCollection<PythonEngine>(AvailableEngines); | ||
|
||
/// <summary> | ||
/// An observable collection of all the loaded Python engines | ||
/// </summary> | ||
[Obsolete("AvailableEngines field will be replaced in a future Dynamo release.")] | ||
public ObservableCollection<PythonEngine> AvailableEngines; | ||
internal ObservableCollection<PythonEngine> AvailableEngines; | ||
|
||
public delegate void PythonEngineChangedHandler(PythonEngine engine); | ||
|
||
private Action<PythonEngine> customizeEngine; | ||
|
||
/// <summary> | ||
/// Use this function to customize Python engine initialization. | ||
/// This function will be called only once on all existing or future python engines (on PythonEngineAdded). | ||
/// </summary> | ||
public Action<PythonEngine> CustomizeEngine | ||
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. this seems kind of dangerous, I imagine you want integrations like Revit to use this to setup marshallers and hook up events? But this would also be easily accessible to anyone since this class has a static instance method - it could easily break python integration. |
||
{ | ||
set | ||
{ | ||
customizeEngine = value; | ||
if (customizeEngine != null) | ||
{ | ||
try | ||
{ | ||
foreach (var engine in AvailableEngines) | ||
{ | ||
customizeEngine(engine); | ||
} | ||
} | ||
catch { } | ||
} | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Event that is triggered for every new engine that is added. | ||
/// </summary> | ||
public static PythonEngineChangedHandler PythonEngineAdded; | ||
|
||
/// <summary> | ||
/// Event that is triggered for every engine that is removed. | ||
/// </summary> | ||
public static PythonEngineChangedHandler PythonEngineRemoved; | ||
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. how do you imagine removal will work? Just remove the instance from the list of engines or actually try to unload it? 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. With ALCs, I would imagine completely unloading it (assuming it works for python runtime) |
||
|
||
#region Constant strings | ||
|
||
|
@@ -132,16 +172,11 @@ | |
|
||
internal static string PythonEvaluatorSingletonInstance = "Instance"; | ||
|
||
internal static string IronPythonEvaluatorClass = "IronPythonEvaluator"; | ||
internal static string IronPythonEvaluationMethod = "EvaluateIronPythonScript"; | ||
|
||
internal static string CPythonEvaluatorClass = "CPythonEvaluator"; | ||
internal static string CPythonEvaluationMethod = "EvaluatePythonScript"; | ||
|
||
internal static string IronPythonAssemblyName = "DSIronPython"; | ||
internal static string CPythonAssemblyName = "DSCPython"; | ||
|
||
internal static string IronPythonTypeName = IronPythonAssemblyName + "." + IronPythonEvaluatorClass; | ||
internal static string CPythonTypeName = CPythonAssemblyName + "." + CPythonEvaluatorClass; | ||
|
||
internal static string PythonInputMarshalerProperty = "InputMarshaler"; | ||
|
@@ -157,7 +192,7 @@ | |
private PythonEngineManager() | ||
{ | ||
AvailableEngines = new ObservableCollection<PythonEngine>(); | ||
|
||
AvailableEngines.CollectionChanged += AvailableEngines_CollectionChanged; | ||
// We check only for the default python engine because it is the only one loaded by static references. | ||
// Other engines can only be loaded through package manager | ||
LoadDefaultPythonEngine(AppDomain.CurrentDomain.GetAssemblies(). | ||
|
@@ -166,6 +201,48 @@ | |
AppDomain.CurrentDomain.AssemblyLoad += new AssemblyLoadEventHandler((object sender, AssemblyLoadEventArgs args) => LoadDefaultPythonEngine(args.LoadedAssembly)); | ||
} | ||
|
||
private void AvailableEngines_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) | ||
{ | ||
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add) | ||
{ | ||
for (var ii=0; ii< e.NewItems.Count; ii++) | ||
{ | ||
try | ||
{ | ||
PythonEngineAdded?.Invoke(e.NewItems[ii] as PythonEngine); | ||
} | ||
catch(Exception ex) | ||
{ | ||
Console.WriteLine("PythonEngineAdded event failed with error : " + ex.Message + Environment.NewLine + ex.StackTrace); | ||
} | ||
|
||
try | ||
{ | ||
customizeEngine.Invoke(e.NewItems[ii] as PythonEngine); | ||
} | ||
catch (Exception ex) | ||
{ | ||
Console.WriteLine("CustomizeEngine failed with error : " + ex.Message + Environment.NewLine + ex.StackTrace); | ||
} | ||
} | ||
} | ||
|
||
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove) | ||
{ | ||
for (var ii = 0; ii < e.OldItems.Count; ii++) | ||
{ | ||
try | ||
{ | ||
PythonEngineRemoved?.Invoke(e.OldItems[ii] as PythonEngine); | ||
} | ||
catch (Exception ex) | ||
{ | ||
Console.WriteLine("PythonEngineRemoved event failed with error : " + ex.Message + Environment.NewLine + ex.StackTrace); | ||
} | ||
} | ||
} | ||
} | ||
|
||
private void LoadDefaultPythonEngine(Assembly a) | ||
{ | ||
if (a == null || | ||
|
@@ -180,7 +257,7 @@ | |
} | ||
catch (Exception e) | ||
{ | ||
System.Diagnostics.Debug.WriteLine($"Failed to load {CPythonAssemblyName} with error: {e.Message}"); | ||
Console.WriteLine($"Failed to load {CPythonAssemblyName} with error: {e.Message}"); | ||
} | ||
} | ||
|
||
|
@@ -189,16 +266,32 @@ | |
return AvailableEngines.FirstOrDefault(x => x.Name == name); | ||
} | ||
|
||
// This method can throw exceptions. | ||
internal void LoadPythonEngine(IEnumerable<Assembly> assemblies) | ||
/// <summary> | ||
/// Load Python Engines from an array of assemblies | ||
/// </summary> | ||
/// <param name="assemblies"></param> | ||
internal void LoadPythonEngine(Action<string> logger, IEnumerable<Assembly> assemblies) | ||
{ | ||
foreach (var a in assemblies) | ||
{ | ||
LoadPythonEngine(a); | ||
try | ||
{ | ||
LoadPythonEngine(a); | ||
} | ||
catch(Exception e) | ||
{ | ||
logger?.Invoke("Failed when looking for PythonEngines with error: " + e.Message + Environment.NewLine + e.StackTrace); | ||
} | ||
} | ||
} | ||
|
||
// This method can throw exceptions. | ||
/// <summary> | ||
/// Load Python Engines from an assembly | ||
/// </summary> | ||
/// <param name="assembly"></param> | ||
/// <exception cref="Exception"></exception> | ||
/// Make this public to support custom loading of Python Engines (ex load in isolated alc on the python assembly side) | ||
/// How to transition to Dynamo loading in isolated ALC ? | ||
private void LoadPythonEngine(Assembly assembly) | ||
{ | ||
if (assembly == null) | ||
|
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.
comment is a bit misleading as this setter has the side effect of calling the method...
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.
Yeah, I kind of don't like a setter doing more than just replacing a value,
Still not convinced this is the proper way to go...