使用自定义导入器导入子模块在 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!')

如果我尝试在脚本中像这样导入 MathImplimport 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_modulefullname包含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 不允许包含的内容 /。通常只允许使用字符,也可以是文件名。

也许这对其他人有帮助...