PythonEngineManager
Singleton class that other class can access and use for query loaded Python Engine info.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
namespace Dynamo.PythonServices
{
public sealed class PythonEngineManager
{
internal static readonly Lazy<PythonEngineManager> lazy = new Lazy<PythonEngineManager>(() => new PythonEngineManager());
public ObservableCollection<PythonEngine> AvailableEngines;
internal static readonly string CPython3EngineName = "CPython3";
internal static readonly string IronPython2EngineName = "IronPython2";
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";
internal static string PythonOutputMarshalerProperty = "OutputMarshaler";
internal static string DummyEvaluatorClass = "DummyPythonEvaluator";
internal static string DummyEvaluatorMethod = "Evaluate";
public static PythonEngineManager Instance => lazy.Value;
private PythonEngineManager()
{
AvailableEngines = new ObservableCollection<PythonEngine>();
LoadDefaultPythonEngine(AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(delegate(Assembly a) {
if (a != (Assembly)null)
return a.GetName().Name == CPythonAssemblyName;
return false;
}));
AppDomain.CurrentDomain.AssemblyLoad += delegate(object sender, AssemblyLoadEventArgs args) {
LoadDefaultPythonEngine(args.LoadedAssembly);
};
}
private void LoadDefaultPythonEngine(Assembly a)
{
if (!(a == (Assembly)null) && !(a.GetName().Name != CPythonAssemblyName))
try {
LoadPythonEngine(a);
} catch (Exception) {
}
}
private PythonEngine GetEngine(string version)
{
return AvailableEngines.FirstOrDefault((PythonEngine x) => x.Name == version);
}
internal void LoadPythonEngine(IEnumerable<Assembly> assemblies)
{
foreach (Assembly assembly in assemblies) {
LoadPythonEngine(assembly);
}
}
private void LoadPythonEngine(Assembly assembly)
{
if (!(assembly == (Assembly)null))
try {
Type type = null;
PropertyInfo propertyInfo = null;
try {
type = assembly.GetTypes().FirstOrDefault(delegate(Type x) {
if (typeof(PythonEngine).IsAssignableFrom(x) && !x.IsInterface)
return !x.IsAbstract;
return false;
});
if (type == (Type)null)
return;
propertyInfo = type?.GetProperty(PythonEvaluatorSingletonInstance, BindingFlags.Static | BindingFlags.NonPublic);
if (propertyInfo == (PropertyInfo)null)
return;
} catch {
return;
}
PythonEngine pythonEngine = (PythonEngine)propertyInfo.GetValue(null);
if (pythonEngine == null)
throw new Exception("Could not get a valid PythonEngine instance by calling the " + type.Name + "." + PythonEvaluatorSingletonInstance + " method");
if (GetEngine(pythonEngine.Name) == null)
AvailableEngines.Add(pythonEngine);
} catch (Exception ex) {
throw new Exception("Failed to add a Python engine from assembly " + assembly.GetName().Name + ".dll with error: " + ex.Message);
}
}
}
}