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.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Dynamo.PythonServices
{
public sealed class PythonEngineManager
{
internal static readonly Lazy<PythonEngineManager> lazy = new Lazy<PythonEngineManager>(() => new PythonEngineManager());
private readonly string[] dotNetRuntimePaths;
private readonly IEnumerable<string> dynCorePaths;
[Obsolete("AvailableEngines field will be replaced in a future Dynamo release.")]
public ObservableCollection<PythonEngine> AvailableEngines;
internal static readonly string CPython3EngineName = "CPython3";
internal static readonly string PythonNet3EngineName = "PythonNet3";
internal static readonly string PythonNodeNamespace = "PythonNodeModels.PythonNode";
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 PythonNet3AssemblyName = "DSPythonNet3";
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()
{
dotNetRuntimePaths = Directory.GetFiles(RuntimeEnvironment.GetRuntimeDirectory(), "*.dll");
dynCorePaths = from x in new FileInfo(Assembly.GetExecutingAssembly().Location).get_Directory().GetFiles("*.dll", 1)
select x.get_FullName();
AvailableEngines = new ObservableCollection<PythonEngine>();
}
private PythonEngine GetEngine(string name)
{
return AvailableEngines.FirstOrDefault((PythonEngine x) => x.Name == name);
}
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) {
DefaultInterpolatedStringHandler val = new DefaultInterpolatedStringHandler(67, 2);
val.AppendLiteral("Could not get a valid PythonEngine instance by calling the ");
val.AppendFormatted(type.Name);
val.AppendLiteral(".");
val.AppendFormatted(PythonEvaluatorSingletonInstance);
val.AppendLiteral(" method");
throw new Exception(val.ToStringAndClear());
}
VerifyEngineReferences(assembly, dotNetRuntimePaths.Concat(dynCorePaths));
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);
}
}
private static void VerifyEngineReferences(Assembly assembly, IEnumerable<string> standardPaths)
{
MetadataLoadContext val = null;
IEnumerable<string> second = from x in new FileInfo(assembly.Location).get_Directory().GetFiles("*.dll", 1)
select x.get_FullName();
PathAssemblyResolver val2 = new PathAssemblyResolver(standardPaths.Concat(second));
val = new MetadataLoadContext(val2, (string)null);
try {
AssemblyName[] referencedAssemblies = assembly.GetReferencedAssemblies();
foreach (AssemblyName assemblyName in referencedAssemblies) {
Assembly assembly2 = val.LoadFromAssemblyName(assemblyName);
}
} finally {
if (val != null)
val.Dispose();
}
}
internal bool HasEngine(string engineName)
{
if (string.IsNullOrEmpty(engineName) || AvailableEngines == null)
return false;
return AvailableEngines.Any(delegate(PythonEngine e) {
if (e != null)
return e.Name == engineName;
return false;
});
}
}
}