使用自定义导入器导入子模块在 find_module 全名参数中包含“<module>”
Importing submodule using custom importer contains "<module>" in find_module fullname parameter
目前我正在为 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
方法中搜索一些 module/package。 returns 如果找到导入器实例,否则:
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);
因为不知道这样创建模块是否完全正确。
下载这个 project/branch: https://github.com/simplicbe/Simplic.Dlr/tree/f_res_noid 并启动 Sample.ImportResolver
可以重现问题。将引发 find_module
中的异常。
谢谢大家!
此问题已解决。 Modpath
不允许包含的内容 /
。通常只允许使用字符,也可以是文件名。
也许这对其他人有帮助...
目前我正在为 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
方法中搜索一些 module/package。 returns 如果找到导入器实例,否则:
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);
因为不知道这样创建模块是否完全正确。
下载这个 project/branch: https://github.com/simplicbe/Simplic.Dlr/tree/f_res_noid 并启动 Sample.ImportResolver
可以重现问题。将引发 find_module
中的异常。
谢谢大家!
此问题已解决。 Modpath
不允许包含的内容 /
。通常只允许使用字符,也可以是文件名。
也许这对其他人有帮助...