【发布时间】:2016-01-28 13:27:21
【问题描述】:
目前我正在为 Ironpython 开发一个自定义导入器,它应该添加一个抽象层来编写自定义导入器。抽象层是一个 IronPython 模块,它基于 PEP 302 和 IronPython zipimporter 模块。架构如下所示:
为了测试我的导入器代码,我编写了一个带有模块的简单测试包,如下所示:
/Math/
__init__.py
/MathImpl/
__init__.py
__Math2__.py
/Math/__init__.py:
print ('Import: /Math/__init__.py')
/Math/MathImpl/__init__.py:
# Sample math package
print ('Begin import /Math/MathImpl/__init__.py')
import Math2
print ('End import /Math/MathImpl/__init__.py: ' + str(Math2.add(1, 2)))
/Math/MathImpl/Math2.py:
# Add two values
def add(x, y):
return x + y
print ('Import Math2.py!')
如果我尝试在脚本中像这样导入MathImpl:import Math.MathImpl
我的genericimporter 被调用并在find_module 方法中搜索一些模块/包。如果找到,则返回导入器的实例,否则不返回:
public object find_module(CodeContext/*!*/ context, string fullname, params object[] args)
{
// Set module
if (fullname.Contains("<module>"))
{
throw new Exception("Why, why does fullname contains <module>?");
}
// Find resolver
foreach (var resolver in Host.Resolver)
{
var res = resolver.GetModuleInformation(fullname);
// If this script could be resolved by some resolver
if (res != ResolvedType.None)
{
this.resolver = resolver;
return this;
}
}
return null;
}
如果find_module第一次被调用,fullname包含Math,没关系,因为Math应该先导入。第二次调用find_module,应该导入Math.MathImpl,这里的问题是,fullname现在的值是<module>.MathImpl,而不是Math.MathImpl。
我的想法是,在导入Math 时模块名称(__name__)设置不正确,但无论如何我在load_module 中导入模块时设置了这个:
public object load_module(CodeContext/*!*/ context, string fullname)
{
string code = null;
GenericModuleCodeType moduleType;
bool ispackage = false;
string modpath = null;
PythonModule mod;
PythonDictionary dict = null;
// Go through available import types by search-order
foreach (var order in _search_order)
{
string tempCode = this.resolver.GetScriptSource(fullname + order.Key);
if (tempCode != null)
{
moduleType = order.Value;
code = tempCode;
modpath = fullname + order.Key;
Console.WriteLine(" IMPORT: " + modpath);
if ((order.Value & GenericModuleCodeType.Package) == GenericModuleCodeType.Package)
{
ispackage = true;
}
break;
}
}
// of no code was loaded
if (code == null)
{
return null;
}
var scriptCode = context.ModuleContext.Context.CompileSourceCode
(
new SourceUnit(context.LanguageContext, new SourceStringContentProvider(code), modpath, SourceCodeKind.AutoDetect),
new IronPython.Compiler.PythonCompilerOptions() { },
ErrorSink.Default
);
// initialize module
mod = context.ModuleContext.Context.InitializeModule(modpath, context.ModuleContext, scriptCode, ModuleOptions.None);
dict = mod.Get__dict__();
// Set values before execute script
dict.Add("__name__", fullname);
dict.Add("__loader__", this);
dict.Add("__package__", null);
if (ispackage)
{
// Add path
string subname = GetSubName(fullname);
string fullpath = string.Format(fullname.Replace(".", "/"));
List pkgpath = PythonOps.MakeList(fullpath);
dict.Add("__path__", pkgpath);
}
else
{
StringBuilder packageName = new StringBuilder();
string[] packageParts = fullname.Split(new char[] { '/' });
for (int i = 0; i < packageParts.Length - 1; i++)
{
if (i > 0)
{
packageName.Append(".");
}
packageName.Append(packageParts[i]);
}
dict["__package__"] = packageName.ToString();
}
var scope = context.ModuleContext.GlobalScope;
scriptCode.Run(scope);
return mod;
}
我希望有人知道为什么会发生这种情况。也可能导致问题的几行是:
var scriptCode = context.ModuleContext.Context.CompileSourceCode
(
new SourceUnit(context.LanguageContext, new SourceStringContentProvider(code), modpath, SourceCodeKind.AutoDetect),
new IronPython.Compiler.PythonCompilerOptions() { },
ErrorSink.Default
);
和
mod = context.ModuleContext.Context.InitializeModule(modpath, context.ModuleContext, scriptCode, ModuleOptions.None);
因为我不知道,这样创建模块是否完全正确。
下载此项目/分支可以重现问题:https://github.com/simplicbe/Simplic.Dlr/tree/f_res_noid 并启动Sample.ImportResolver。将引发find_module 中的异常。
谢谢大家!
【问题讨论】:
标签: c# python import hook ironpython