目前我正在为Ironpython开发一个自定义导入器,它应该添加一个抽象层来编写自定义导入器。抽象层是一个IronPython模块,它基于PEP 302和IronPython zipimporter
模块。架构看起来像这样:
为了测试我的导入器代码,我编写了一个带有模块的简单测试包,如下所示:
/Math/
__init__.py
/MathImpl/
__init__.py
__Math2__.py
。/数学/ __ INIT __ PY:
print ('Import: /Math/__init__.py')
。/数学/ 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
。< / p>
我的想法是,在导入__name__
时未正确设置模块名称(Math
),但我在load_module
中导入模块时无论如何都设置了此项:< / p>
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
中的例外情况。
谢谢大家!
答案 0 :(得分:0)
此问题已解决。 Modpath
不允许包含/
的内容。通常只允许使用字符,也可以使用文件名。
也许这对其他人有帮助......