我正在从数据库加载IronPython脚本并执行它.这适用于简单的脚本,但导入是一个问题.如何拦截这些导入调用,然后从数据库加载适当的脚本?
编辑:我的主要应用程序是用C#编写的,我想在不编辑Python脚本的情况下拦截C#端的调用.
编辑:从我已经完成的研究来看,创建自己的PlatformAdaptationLayer看起来就像你应该实现它的方式,但它在这种情况下不起作用.我已经创建了自己的PAL,在我的测试中,我的FileExsists方法会在脚本中的每次导入时被调用.但由于某种原因,它永远不会调用该OpenInputFileStream方法的任何重载.通过IronPython源,一旦FileExists返回true,它就会尝试在路径上找到文件本身.所以这看起来像死路一条.
Dan*_*Dan 10
经过大量的反复试验,我找到了解决方案.我从未设法让PlatformAdaptationLayer方法正常工作.尝试加载模块时,它从未回调过PAL.
所以我决定要做的是使用SetVariable方法替换内置的import函数,如下所示(Engine和Scope是受保护的成员,公开ScriptEngine和ScriptScope为父脚本):
delegate object ImportDelegate(CodeContext context, string moduleName, PythonDictionary globals, PythonDictionary locals, PythonTuple tuple);
protected void OverrideImport()
{
ScriptScope scope = IronPython.Hosting.Python.GetBuiltinModule(Engine);
scope.SetVariable("__import__", new ImportDelegate(DoDatabaseImport));
}
protected object DoDatabaseImport(CodeContext context, string moduleName, PythonDictionary globals, PythonDictionary locals, PythonTuple tuple)
{
if (ScriptExistsInDb(moduleName))
{
string rawScript = GetScriptFromDb(moduleName);
ScriptSource source = Engine.CreateScriptSourceFromString(rawScript);
ScriptScope scope = Engine.CreateScope();
Engine.Execute(rawScript, scope);
Microsoft.Scripting.Runtime.Scope ret = Microsoft.Scripting.Hosting.Providers.HostingHelpers.GetScope(scope);
Scope.SetVariable(moduleName, ret);
return ret;
}
else
{ // fall back on the built-in method
return IronPython.Modules.Builtin.__import__(context, moduleName);
}
}
Run Code Online (Sandbox Code Playgroud)
希望这有助于某人!
我只想尝试做同样的事情,除了我想将我的脚本存储为嵌入式资源.我正在创建一个C#和IronPython混合的库,并希望将其作为单个dll进行分发.我编写了一个可行的PlatformAdaptationLayer,它首先查看正在加载的脚本的资源,但后来又回到了在文件系统中查找的基本实现.三个部分:
第1部分,自定义PlatformAdaptationLayer
namespace ZenCoding.Hosting
{
internal class ResourceAwarePlatformAdaptationLayer : PlatformAdaptationLayer
{
private readonly Dictionary<string, string> _resourceFiles = new Dictionary<string, string>();
private static readonly char Seperator = Path.DirectorySeparatorChar;
private const string ResourceScriptsPrefix = "ZenCoding.python.";
public ResourceAwarePlatformAdaptationLayer()
{
CreateResourceFileSystemEntries();
}
#region Private methods
private void CreateResourceFileSystemEntries()
{
foreach (string name in Assembly.GetExecutingAssembly().GetManifestResourceNames())
{
if (!name.EndsWith(".py"))
{
continue;
}
string filename = name.Substring(ResourceScriptsPrefix.Length);
filename = filename.Substring(0, filename.Length - 3); //Remove .py
filename = filename.Replace('.', Seperator);
_resourceFiles.Add(filename + ".py", name);
}
}
private Stream OpenResourceInputStream(string path)
{
string resourceName;
if (_resourceFiles.TryGetValue(RemoveCurrentDir(path), out resourceName))
{
return Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
}
return null;
}
private bool ResourceDirectoryExists(string path)
{
return _resourceFiles.Keys.Any(f => f.StartsWith(RemoveCurrentDir(path) + Seperator));
}
private bool ResourceFileExists(string path)
{
return _resourceFiles.ContainsKey(RemoveCurrentDir(path));
}
private static string RemoveCurrentDir(string path)
{
return path.Replace(Directory.GetCurrentDirectory() + Seperator, "").Replace("." + Seperator, "");
}
#endregion
#region Overrides from PlatformAdaptationLayer
public override bool FileExists(string path)
{
return ResourceFileExists(path) || base.FileExists(path);
}
public override string[] GetFileSystemEntries(string path, string searchPattern, bool includeFiles, bool includeDirectories)
{
string fullPath = Path.Combine(path, searchPattern);
if (ResourceFileExists(fullPath) || ResourceDirectoryExists(fullPath))
{
return new[] { fullPath };
}
if (!ResourceDirectoryExists(path))
{
return base.GetFileSystemEntries(path, searchPattern, includeFiles, includeDirectories);
}
return new string[0];
}
public override bool DirectoryExists(string path)
{
return ResourceDirectoryExists(path) || base.DirectoryExists(path);
}
public override Stream OpenInputFileStream(string path)
{
return OpenResourceInputStream(path) ?? base.OpenInputFileStream(path);
}
public override Stream OpenInputFileStream(string path, FileMode mode, FileAccess access, FileShare share)
{
return OpenResourceInputStream(path) ?? base.OpenInputFileStream(path, mode, access, share);
}
public override Stream OpenInputFileStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize)
{
return OpenResourceInputStream(path) ?? base.OpenInputFileStream(path, mode, access, share, bufferSize);
}
#endregion
}
}
Run Code Online (Sandbox Code Playgroud)
您需要将常量ResourceScriptsPrefix更改为存储python脚本的基本命名空间.
第2部分,自定义ScriptHost
namespace ZenCoding.Hosting
{
internal class ResourceAwareScriptHost : ScriptHost
{
private readonly PlatformAdaptationLayer _layer = new ResourceAwarePlatformAdaptationLayer();
public override PlatformAdaptationLayer PlatformAdaptationLayer
{
get { return _layer; }
}
}
}
Run Code Online (Sandbox Code Playgroud)
第3部分,最后,如何使用自定义内容获取Python引擎:
namespace ZenCoding.Hosting
{
internal static class ResourceAwareScriptEngineSetup
{
public static ScriptEngine CreateResourceAwareEngine()
{
var setup = Python.CreateRuntimeSetup(null);
setup.HostType = typeof(ResourceAwareScriptHost);
var runtime = new ScriptRuntime(setup);
return runtime.GetEngineByTypeName(typeof(PythonContext).AssemblyQualifiedName);
}
}
}
Run Code Online (Sandbox Code Playgroud)
可以很容易地将其更改为从其他位置(如数据库)加载脚本.只需更改OpenResourceStream,ResourceFileExists和ResourceDirectoryExists方法即可.
希望这可以帮助.
| 归档时间: |
|
| 查看次数: |
2438 次 |
| 最近记录: |