代码之家  ›  专栏  ›  技术社区  ›  BendEg

使用自定义导入程序导入子模块find_module全名参数中包含“<module>”

  •  0
  • BendEg  · 技术社区  · 9 年前

    目前我正在为Ironpython开发一个自定义导入程序,它应该为编写自定义导入程序添加一个抽象层。抽象层是一个IronPython模块,它基于 PEP 302 和IronPython zipimporter 单元架构如下:

    Architexture

    为了测试导入程序代码,我编写了一个包含模块的简单测试包,如下所示:

    /Math/
        __init__.py
        /MathImpl/
                 __init__.py
                 __Math2__.py
    

    /数学/__init__.py:

    print ('Import: /Math/__init__.py')
    

    /数学/数学Impl/__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)))
    

    /数学/数学实施/数学2.py:

    # Add two values
    def add(x, y):
        return x + y
    print ('Import Math2.py!')
    

    如果我尝试导入 MathImpl 在脚本中: import Math.MathImpl

    我的 genericimporter 调用get并在 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;
    }
    

    如果 查找模块 被称为第一次, fullname 包含 Math ,这是可以的,因为 数学 应首先导入。第二次 查找模块 被称为, Math.MathImpl 应该进口,这里的问题是 全名 现在有了价值 <module>.MathImpl 而不是 数学数学实现 .

    我的想法是,模块名称( __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 。中的异常 查找模块 将升高。

    谢谢大家!

    1 回复  |  直到 9 年前
        1
  •  0
  •   BendEg    9 年前

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

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