149 lines
6.3 KiB
Python
149 lines
6.3 KiB
Python
|
|
# Hook __import__
|
|||
|
|
import builtins
|
|||
|
|
import os
|
|||
|
|
import sys
|
|||
|
|
import public
|
|||
|
|
import public.PluginLoader as plugin_loader
|
|||
|
|
import types
|
|||
|
|
import traceback
|
|||
|
|
|
|||
|
|
|
|||
|
|
if 'class_v2/' not in sys.path and 'class_v2' not in sys.path:
|
|||
|
|
sys.path.insert(0, 'class_v2/')
|
|||
|
|
|
|||
|
|
|
|||
|
|
__basedir = public.get_panel_path()
|
|||
|
|
__hooked = False
|
|||
|
|
old__import__ = builtins.__import__
|
|||
|
|
|
|||
|
|
|
|||
|
|
def hook_import():
|
|||
|
|
global __hooked, __basedir
|
|||
|
|
|
|||
|
|
if __hooked:
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
def _aap__import__(name, globals = None, locals = None, fromlist = (), level = 0):
|
|||
|
|
try:
|
|||
|
|
return old__import__(name, globals, locals, fromlist, level)
|
|||
|
|
except SyntaxError:
|
|||
|
|
panel_path = __basedir
|
|||
|
|
|
|||
|
|
# 处理相对导入
|
|||
|
|
if level > 0:
|
|||
|
|
if not globals or '__package__' not in globals:
|
|||
|
|
raise ImportError("Attempted relative import with no known parent package")
|
|||
|
|
package = globals.get('__package__') or globals.get('__name__', '').rpartition('.')[0]
|
|||
|
|
if not package and level > 0:
|
|||
|
|
raise ImportError("Attempted relative import with no known parent package")
|
|||
|
|
if level > 1:
|
|||
|
|
parent_parts = package.split('.')
|
|||
|
|
if len(parent_parts) < level - 1:
|
|||
|
|
raise ImportError("Attempted relative import beyond top-level package")
|
|||
|
|
package = '.'.join(parent_parts[:-level + 1])
|
|||
|
|
absolute_name = f"{package}.{name}" if name else package
|
|||
|
|
else:
|
|||
|
|
absolute_name = name
|
|||
|
|
|
|||
|
|
# 如果模块已加载,直接返回
|
|||
|
|
if absolute_name in sys.modules:
|
|||
|
|
if fromlist is None or len(fromlist) == 0:
|
|||
|
|
return sys.modules[absolute_name]
|
|||
|
|
|
|||
|
|
is_loaded = True
|
|||
|
|
|
|||
|
|
for name in fromlist:
|
|||
|
|
if name == '*':
|
|||
|
|
continue
|
|||
|
|
if not hasattr(sys.modules[absolute_name], name):
|
|||
|
|
is_loaded = False
|
|||
|
|
break
|
|||
|
|
|
|||
|
|
if is_loaded:
|
|||
|
|
return sys.modules[absolute_name]
|
|||
|
|
|
|||
|
|
|
|||
|
|
module_path_part = absolute_name.replace('.', '/')
|
|||
|
|
is_package_import = bool(fromlist)
|
|||
|
|
|
|||
|
|
for p in set(sys.path):
|
|||
|
|
base_path = os.path.join(panel_path, p)
|
|||
|
|
potential_file_path = os.path.realpath(os.path.join(base_path, module_path_part + '.py'))
|
|||
|
|
potential_dir_path = os.path.realpath(os.path.join(base_path, module_path_part))
|
|||
|
|
|
|||
|
|
if os.path.isdir(potential_dir_path):
|
|||
|
|
init_py = os.path.join(potential_dir_path, '__init__.py')
|
|||
|
|
|
|||
|
|
if os.path.exists(init_py) and os.path.getsize(init_py) > 10:
|
|||
|
|
# 如果 __init__.py 存在并且不为空,作为常规包加载
|
|||
|
|
top_module = plugin_loader.get_module(init_py)
|
|||
|
|
else:
|
|||
|
|
# 如果 __init__.py 不存在,创建一个空的模块对象来代表这个包
|
|||
|
|
top_module = types.ModuleType(absolute_name)
|
|||
|
|
top_module.__file__ = potential_dir_path
|
|||
|
|
top_module.__path__ = [potential_dir_path]
|
|||
|
|
top_module.__package__ = absolute_name
|
|||
|
|
# 将创建的空模块放入 sys.modules 缓存
|
|||
|
|
sys.modules[absolute_name] = top_module
|
|||
|
|
|
|||
|
|
if is_package_import:
|
|||
|
|
for sub_module_name in fromlist:
|
|||
|
|
if sub_module_name == '*':
|
|||
|
|
continue
|
|||
|
|
sub_module_path = os.path.join(potential_dir_path, sub_module_name + '.py')
|
|||
|
|
if os.path.exists(sub_module_path):
|
|||
|
|
try:
|
|||
|
|
sub_module = plugin_loader.get_module(sub_module_path)
|
|||
|
|
setattr(top_module, sub_module_name, sub_module)
|
|||
|
|
except:
|
|||
|
|
traceback.print_exc()
|
|||
|
|
pass
|
|||
|
|
return top_module
|
|||
|
|
|
|||
|
|
elif os.path.exists(potential_file_path):
|
|||
|
|
m = plugin_loader.get_module(potential_file_path)
|
|||
|
|
|
|||
|
|
# 规范化子模块对象属性
|
|||
|
|
parts = absolute_name.split('.')
|
|||
|
|
m.__name__ = absolute_name
|
|||
|
|
m.__file__ = potential_file_path
|
|||
|
|
m.__package__ = '.'.join(parts[:-1]) if len(parts) > 1 else ''
|
|||
|
|
|
|||
|
|
# 注册完整模块名到 sys.modules
|
|||
|
|
sys.modules[absolute_name] = m
|
|||
|
|
|
|||
|
|
# 确保父包链存在并把子模块设置为父包属性(父包的 __path__ 指向模块文件所在目录)
|
|||
|
|
for i in range(1, len(parts)):
|
|||
|
|
parent_name = '.'.join(parts[:i])
|
|||
|
|
child_name = parts[i]
|
|||
|
|
if parent_name not in sys.modules:
|
|||
|
|
parent = types.ModuleType(parent_name)
|
|||
|
|
parent.__package__ = parent_name
|
|||
|
|
# 将父包的 __path__ 指向包含子模块的目录(保守设置)
|
|||
|
|
parent.__path__ = [os.path.dirname(potential_file_path)]
|
|||
|
|
sys.modules[parent_name] = parent
|
|||
|
|
else:
|
|||
|
|
parent = sys.modules[parent_name]
|
|||
|
|
|
|||
|
|
# 设置父包对下级模块的属性引用(使用已经注册的模块对象)
|
|||
|
|
child_full = '.'.join(parts[:i + 1])
|
|||
|
|
child_mod = sys.modules.get(child_full)
|
|||
|
|
if child_mod is not None:
|
|||
|
|
setattr(parent, child_name, child_mod)
|
|||
|
|
|
|||
|
|
# 如果导入没有指定 fromlist(即通常的 `import a.b.c`),返回顶级包对象以匹配 CPython 行为
|
|||
|
|
is_package_import = bool(fromlist)
|
|||
|
|
if not is_package_import:
|
|||
|
|
top_name = parts[0]
|
|||
|
|
return sys.modules.get(top_name, m)
|
|||
|
|
|
|||
|
|
# 有 fromlist 时返回子模块对象
|
|||
|
|
return m
|
|||
|
|
|
|||
|
|
raise
|
|||
|
|
|
|||
|
|
builtins.__import__ = _aap__import__
|
|||
|
|
|
|||
|
|
__hooked = True
|
|||
|
|
|