【问题标题】:Importing submodule using custom importer contains "<module>" in find_module fullname parameter使用自定义导入器导入子模块在 find_module 全名参数中包含“<module>”
【发布时间】: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!')

如果我尝试在脚本中像这样导入MathImplimport 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现在的值是&lt;module&gt;.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


    【解决方案1】:

    这个问题解决了。 Modpath 不允许包含 /。通常只允许使用字符,也可以在文件名中。

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

    【讨论】:

      猜你喜欢
      • 2015-09-09
      • 1970-01-01
      • 2023-01-31
      • 2017-03-16
      • 2012-06-17
      • 1970-01-01
      • 2021-02-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多