自定义 IronPython 导入分辨率 [英] Custom IronPython import resolution
问题描述
我正在从数据库加载 IronPython 脚本并执行它.这适用于简单的脚本,但导入是一个问题.如何拦截这些导入调用,然后从数据库中加载适当的脚本?
I am loading an IronPython script from a database and executing it. This works fine for simple scripts, but imports are a problem. How can I intercept these import calls and then load the appropriate scripts from the database?
我的主要应用程序是用 C# 编写的,我想在不编辑 Python 脚本的情况下拦截 C# 端的调用.
My main application is written in C# and I'd like to intercept the calls on the C# side without editing the Python scripts.
根据我所做的研究,看起来创建自己的 PlatformAdaptationLayer 是您应该实现这一点的方式,但在这种情况下它不起作用.我已经创建了自己的 PAL,并且在我的测试中,我的 FileExsists
方法在脚本中的每次导入时都会被调用.但出于某种原因,它从不调用 OpenInputFileStream
方法的任何重载.挖掘 IronPython 源代码,一旦 FileExists 返回 true,它就会尝试在路径上定位文件本身.所以这看起来像是一个死胡同.
From the research I've done, it looks like creating your own PlatformAdaptationLayer is the way you're supposed to to implement this, but it doesn't work in this case. I've created my own PAL and in my testing, my FileExsists
method gets called for every import in the script. But for some reason it never calls any overload of the OpenInputFileStream
method. Digging through the IronPython source, once FileExists returns true, it tries to locate the file itself on the path. So this looks like a dead end.
推荐答案
经过大量的反复试验,我找到了一个解决方案.我从来没有设法让 PlatformAdaptationLayer
方法正常工作.尝试加载模块时,它从不回调 PAL.
After a great deal of trial and error, I arrived at a solution. I never managed to get the PlatformAdaptationLayer
approach to work correctly. It never called back to the PAL when attempting to load the modules.
所以我决定做的是使用如下所示的 SetVariable 方法替换内置导入函数(Engine 和 Scope 是保护成员,暴露了 ScriptEngine
和 ScriptScope
用于父脚本):
So what I decided to do was replace the built-in import function by using the SetVariable method as shown below (Engine and Scope are protected members exposing the ScriptEngine
and ScriptScope
for the parent script):
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);
}
}
希望这对某人有所帮助!
Hope this helps someone!
这篇关于自定义 IronPython 导入分辨率的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!