2016-01-28 2 views
0

В настоящее время я работаю над пользовательским импортером для Ironpython, который должен добавить слой абстракции для написания пользовательского импортера. Уровень абстракции - это модуль IronPython, который основывается на PEP 302 и модуле IronPython zipimporter. Архитектура выглядит следующим образом:Импорт подмодуля с использованием пользовательского импортера содержит «<module>» в параметре find_module fullname

Architexture

Для тестирования моего импортера код, я написал простой тестовый пакет с модулями, который выглядит следующим образом:

/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 способ. Который возвращает экземпляр импортера, если найден, а не иначе:

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.

Моя идея была, что имя модуля (__name__) не установлен правильно, когда Math был импортирован, но я установить это в любом случае при импорте модуля в 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.

Спасибо всем!

ответ

0

Эта проблема решается. Modpath Что не разрешено содержать /. В общем случае допускались только символы, которые также могут быть в имени файла.

Возможно, это полезно для кого-то еще ...