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