将 .py 和 .pyi 后缀名改为了 .vp 和 .vpi 后缀名
This commit is contained in:
@@ -146,7 +146,7 @@ def main() -> None:
|
||||
parser.add_argument('--clean', action='store_true', help='清理 output 和 temp 目录')
|
||||
parser.add_argument('--run', action='store_true', help='编译成功后立即执行生成的可执行文件')
|
||||
parser.add_argument('--rebuild-includes', action='store_true', help='删除 includes.binary 预编译缓存并重新编译所有 includes')
|
||||
parser.add_argument('--clear-cache', action='store_true', help='清除 .transpyc_cache 全局缓存(.pyi/.stub.ll/.doc.json)')
|
||||
parser.add_argument('--clear-cache', action='store_true', help='清除 .transpyc_cache 全局缓存(.vpi/.stub.ll/.doc.json)')
|
||||
|
||||
args: argparse.Namespace = parser.parse_args()
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ class Phase1Generator:
|
||||
for root, dirs, files in os.walk(includes_dir):
|
||||
dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__']
|
||||
for fname in files:
|
||||
if fname.endswith('.py') or fname.endswith('.pyi'):
|
||||
if fname.endswith('.vp') or fname.endswith('.py') or fname.endswith('.vpi') or fname.endswith('.pyi'):
|
||||
src_path: str = os.path.join(root, fname)
|
||||
rel_from_inc: str = os.path.relpath(src_path, includes_dir)
|
||||
ModulePath: str = rel_from_inc.replace(os.sep, '.').replace('/', '.')
|
||||
@@ -127,10 +127,10 @@ class Phase1Generator:
|
||||
info: tuple[str, str, str] = (src_path, rel_from_inc, includes_dir)
|
||||
include_file_map[module_name] = info
|
||||
top_pkg: str = module_name.split('.')[0]
|
||||
# __init__.py 是包入口,应优先作为 top_pkg 的代表
|
||||
# __init__.vp/__init__.py 是包入口,应优先作为 top_pkg 的代表
|
||||
# (参考 find_reachable_files_from_entries 的优先级逻辑),
|
||||
# 否则若 os/path.py 先被遍历,'os' 会错误指向 path.py
|
||||
# 而非 os/__init__.py,导致包入口 SHA1 未注册到 sha1_map
|
||||
# 否则若 os/path.vp 先被遍历,'os' 会错误指向 path.vp
|
||||
# 而非 os/__init__.vp,导致包入口 SHA1 未注册到 sha1_map
|
||||
if module_name == f"{top_pkg}.__init__":
|
||||
include_file_map[top_pkg] = info
|
||||
elif top_pkg not in include_file_map:
|
||||
@@ -208,12 +208,15 @@ class Phase1Generator:
|
||||
return needed_infos
|
||||
|
||||
def run(self) -> None:
|
||||
"""扫描源目录,只处理入口文件可达的 .py 文件(导入遍历)"""
|
||||
"""扫描源目录,只处理入口文件可达的 .vp/.py 文件(导入遍历)"""
|
||||
py_files: list[str]
|
||||
if self.entry_files:
|
||||
py_files = list(self.entry_files)
|
||||
else:
|
||||
main_py: str = os.path.join(self.src_root, 'main.py')
|
||||
main_py: str = os.path.join(self.src_root, 'main.vp')
|
||||
if not os.path.exists(main_py):
|
||||
# 回退到 main.py(向后兼容)
|
||||
main_py = os.path.join(self.src_root, 'main.py')
|
||||
if os.path.exists(main_py):
|
||||
py_files = [main_py]
|
||||
else:
|
||||
@@ -221,7 +224,7 @@ class Phase1Generator:
|
||||
for root, dirs, files in os.walk(self.src_root):
|
||||
dirs[:] = [d for d in dirs if d not in ('__pycache__',)]
|
||||
for file in files:
|
||||
if file.endswith('.py'):
|
||||
if file.endswith('.vp') or file.endswith('.py'):
|
||||
py_files.append(os.path.join(root, file))
|
||||
|
||||
if not py_files:
|
||||
@@ -286,7 +289,7 @@ class Phase1Generator:
|
||||
for root, dirs, files in os.walk(includes_dir):
|
||||
dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__']
|
||||
for fname in files:
|
||||
if fname.endswith('.py') or fname.endswith('.pyi'):
|
||||
if fname.endswith('.vp') or fname.endswith('.py') or fname.endswith('.vpi') or fname.endswith('.pyi'):
|
||||
src_path: str = os.path.join(root, fname)
|
||||
rel_from_inc: str = os.path.relpath(src_path, includes_dir)
|
||||
include_py_files.append((src_path, rel_from_inc, includes_dir))
|
||||
@@ -315,14 +318,14 @@ class Phase1Generator:
|
||||
self.include_py_map[top_module] = sha1
|
||||
self.include_py_map[module_name] = sha1
|
||||
|
||||
sig_path: str = os.path.join(self.temp_dir, f"{sha1}.pyi")
|
||||
sig_path: str = os.path.join(self.temp_dir, f"{sha1}.vpi")
|
||||
if os.path.isfile(sig_path):
|
||||
_vlog().info(f" 缓存命中: {rel_from_inc} -> {sha1}.pyi")
|
||||
_vlog().info(f" 缓存命中: {rel_from_inc} -> {sha1}.vpi")
|
||||
continue
|
||||
|
||||
# 全局缓存检查(不被 --clean 清除)
|
||||
if _TryGlobalCache(sha1, 'pyi', sig_path):
|
||||
_vlog().info(f" 缓存命中(全局): {rel_from_inc} -> {sha1}.pyi")
|
||||
_vlog().info(f" 缓存命中(全局): {rel_from_inc} -> {sha1}.vpi")
|
||||
continue
|
||||
|
||||
# 缓存未命中,需读取 content 生成 .pyi
|
||||
@@ -332,7 +335,7 @@ class Phase1Generator:
|
||||
with open(sig_path, 'w', encoding='utf-8', newline='\n') as f:
|
||||
f.write(sig_content)
|
||||
_SaveToGlobalCache(sha1, 'pyi', sig_path)
|
||||
_vlog().info(f" 生成签名: {rel_from_inc} -> {sha1}.pyi")
|
||||
_vlog().info(f" 生成签名: {rel_from_inc} -> {sha1}.vpi")
|
||||
except Exception as e:
|
||||
_vlog().error(f"处理 include 文件失败 {rel_from_inc}: {e}")
|
||||
|
||||
@@ -341,7 +344,7 @@ class Phase1Generator:
|
||||
if not os.path.isdir(self.temp_dir):
|
||||
return typedef_map
|
||||
for fname in os.listdir(self.temp_dir):
|
||||
if not fname.endswith('.pyi'):
|
||||
if not (fname.endswith('.vpi') or fname.endswith('.pyi')):
|
||||
continue
|
||||
pyi_path: str = os.path.join(self.temp_dir, fname)
|
||||
try:
|
||||
@@ -474,7 +477,7 @@ class Phase1Generator:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
sig_path: str = os.path.join(self.temp_dir, f"{sha1}.pyi")
|
||||
sig_path: str = os.path.join(self.temp_dir, f"{sha1}.vpi")
|
||||
if not os.path.isfile(sig_path):
|
||||
_TryGlobalCache(sha1, 'pyi', sig_path)
|
||||
with open(sig_path, 'r', encoding='utf-8') as f:
|
||||
@@ -530,9 +533,9 @@ class Phase1Generator:
|
||||
return
|
||||
self.sha1_map[sha1] = rel_path.replace(os.sep, '/').replace(chr(92), '/')
|
||||
|
||||
sig_path: str = os.path.join(self.temp_dir, f"{sha1}.pyi")
|
||||
sig_path: str = os.path.join(self.temp_dir, f"{sha1}.vpi")
|
||||
if os.path.isfile(sig_path):
|
||||
_vlog().info(f" -> {sha1}.pyi (缓存)")
|
||||
_vlog().info(f" -> {sha1}.vpi (缓存)")
|
||||
# 缓存命中时补全缺失的 .doc.json
|
||||
doc_path: str = os.path.join(self.temp_dir, f"{sha1}.doc.json")
|
||||
if not os.path.isfile(doc_path):
|
||||
@@ -551,7 +554,7 @@ class Phase1Generator:
|
||||
|
||||
# 全局缓存检查
|
||||
if _TryGlobalCache(sha1, 'pyi', sig_path):
|
||||
_vlog().info(f" -> {sha1}.pyi (全局缓存)")
|
||||
_vlog().info(f" -> {sha1}.vpi (全局缓存)")
|
||||
doc_path: str = os.path.join(self.temp_dir, f"{sha1}.doc.json")
|
||||
if not os.path.isfile(doc_path):
|
||||
_TryGlobalCache(sha1, 'doc.json', doc_path)
|
||||
@@ -566,7 +569,7 @@ class Phase1Generator:
|
||||
with open(sig_path, 'w', encoding='utf-8', newline='\n') as f:
|
||||
f.write(sig_content)
|
||||
_SaveToGlobalCache(sha1, 'pyi', sig_path)
|
||||
_vlog().info(f" -> {sha1}.pyi (签名)")
|
||||
_vlog().info(f" -> {sha1}.vpi (签名)")
|
||||
|
||||
# 提取 docstring 写入 {sha1}.doc.json,供 Phase2 跨模块 __doc__ 加载
|
||||
docs: dict[str, str] = self._extract_docstrings(content)
|
||||
@@ -588,7 +591,7 @@ class Phase1Generator:
|
||||
_vlog().info(f" -> {sha1}.stub.ll (缓存)")
|
||||
return
|
||||
|
||||
sig_path: str = os.path.join(self.temp_dir, f"{sha1}.pyi")
|
||||
sig_path: str = os.path.join(self.temp_dir, f"{sha1}.vpi")
|
||||
with open(sig_path, 'r', encoding='utf-8') as f:
|
||||
sig_content: str = f.read()
|
||||
|
||||
@@ -613,9 +616,9 @@ class Phase1Generator:
|
||||
ctype_marker_names.add(attr_name)
|
||||
valid_sha1_keys: set[str] = set(self.sha1_map.keys())
|
||||
for fname in os.listdir(self.temp_dir):
|
||||
if not fname.endswith('.pyi'):
|
||||
if not (fname.endswith('.vpi') or fname.endswith('.pyi')):
|
||||
continue
|
||||
sha1_key: str = fname.replace('.pyi', '')
|
||||
sha1_key: str = fname.replace('.vpi', '').replace('.pyi', '')
|
||||
if sha1_key not in valid_sha1_keys:
|
||||
continue
|
||||
pyi_path: str = os.path.join(self.temp_dir, fname)
|
||||
|
||||
@@ -217,19 +217,19 @@ class Phase2Translator:
|
||||
fpath = os.path.join(self.temp_dir, fname)
|
||||
if fname.startswith('_'):
|
||||
continue
|
||||
if fname.endswith('.pyi'):
|
||||
if fname.endswith('.vpi') or fname.endswith('.pyi'):
|
||||
sha1 = fname[:-4]
|
||||
self.sig_files[sha1] = fpath
|
||||
elif fname.endswith('.stub.ll'):
|
||||
sha1 = fname[:-8]
|
||||
self.stub_files[sha1] = fpath
|
||||
|
||||
# 从全局缓存补充 temp_dir 中缺失的 .pyi / .stub.ll
|
||||
# 从全局缓存补充 temp_dir 中缺失的 .vpi / .stub.ll
|
||||
if os.path.isdir(_GLOBAL_CACHE_DIR):
|
||||
for fname in os.listdir(_GLOBAL_CACHE_DIR):
|
||||
if fname.startswith('_'):
|
||||
continue
|
||||
if fname.endswith('.pyi'):
|
||||
if fname.endswith('.vpi') or fname.endswith('.pyi'):
|
||||
sha1 = fname[:-4]
|
||||
if sha1 not in self.sig_files:
|
||||
self.sig_files[sha1] = os.path.join(_GLOBAL_CACHE_DIR, fname)
|
||||
@@ -256,7 +256,7 @@ class Phase2Translator:
|
||||
def _build_struct_sha1_map(self) -> dict[str, str]:
|
||||
struct_sha1_map = {}
|
||||
valid_sha1_keys = set(self.sha1_map.keys())
|
||||
# 收集 temp_dir 和全局缓存中的 .pyi 文件
|
||||
# 收集 temp_dir 和全局缓存中的 .vpi/.pyi 文件
|
||||
pyi_dirs: list[str] = [self.temp_dir]
|
||||
if os.path.isdir(_GLOBAL_CACHE_DIR):
|
||||
pyi_dirs.append(_GLOBAL_CACHE_DIR)
|
||||
@@ -264,9 +264,9 @@ class Phase2Translator:
|
||||
if not os.path.isdir(scan_dir):
|
||||
continue
|
||||
for fname in os.listdir(scan_dir):
|
||||
if not fname.endswith('.pyi'):
|
||||
if not (fname.endswith('.vpi') or fname.endswith('.pyi')):
|
||||
continue
|
||||
sha1_key = fname.replace('.pyi', '')
|
||||
sha1_key = fname.replace('.vpi', '').replace('.pyi', '')
|
||||
if sha1_key not in valid_sha1_keys:
|
||||
continue
|
||||
if sha1_key in struct_sha1_map:
|
||||
@@ -287,7 +287,10 @@ class Phase2Translator:
|
||||
if self.entry_files:
|
||||
py_files = list(self.entry_files)
|
||||
else:
|
||||
main_py = os.path.join(self.src_root, 'main.py')
|
||||
main_py = os.path.join(self.src_root, 'main.vp')
|
||||
if not os.path.exists(main_py):
|
||||
# 回退到 main.py(向后兼容)
|
||||
main_py = os.path.join(self.src_root, 'main.py')
|
||||
if os.path.exists(main_py):
|
||||
py_files = [main_py]
|
||||
else:
|
||||
@@ -295,7 +298,7 @@ class Phase2Translator:
|
||||
for root, dirs, files in os.walk(self.src_root):
|
||||
dirs[:] = [d for d in dirs if d not in ('__pycache__',)]
|
||||
for file in files:
|
||||
if file.endswith('.py'):
|
||||
if file.endswith('.vp') or file.endswith('.py'):
|
||||
py_files.append(os.path.join(root, file))
|
||||
|
||||
if not py_files:
|
||||
@@ -525,7 +528,10 @@ class Phase2Translator:
|
||||
for inc_dir in self.include_dirs:
|
||||
if os.path.isdir(inc_dir):
|
||||
py_path = os.path.join(inc_dir, rel_path[len('includes/'):].replace(os.sep, '/'))
|
||||
py_path = os.path.splitext(py_path)[0] + '.py'
|
||||
py_path = os.path.splitext(py_path)[0] + '.vp'
|
||||
if not os.path.isfile(py_path):
|
||||
# 回退到 .py(向后兼容)
|
||||
py_path = os.path.splitext(py_path)[0] + '.py'
|
||||
if os.path.isfile(py_path):
|
||||
with open(py_path, 'r', encoding='utf-8') as f:
|
||||
py_sha1 = compute_sha1(f.read())
|
||||
@@ -982,12 +988,12 @@ class Phase2Translator:
|
||||
for includes_dir in self.include_dirs:
|
||||
if os.path.isdir(includes_dir):
|
||||
for pyi_file in os.listdir(includes_dir):
|
||||
if pyi_file.endswith('.pyi'):
|
||||
if pyi_file.endswith('.vpi') or pyi_file.endswith('.pyi'):
|
||||
pyi_path = os.path.join(includes_dir, pyi_file)
|
||||
module_name = os.path.splitext(pyi_file)[0]
|
||||
trans.translator.SymbolTable.LoadModuleSymbols(pyi_path, module_name, lineno=0)
|
||||
for py_file in os.listdir(includes_dir):
|
||||
if py_file.endswith('.py') and (not py_file.startswith('_') or py_file == '_list.py' or py_file == '_dict.py'):
|
||||
if (py_file.endswith('.vp') or py_file.endswith('.py')) and (not py_file.startswith('_') or py_file == '_list.vp' or py_file == '_list.py' or py_file == '_dict.vp' or py_file == '_dict.py'):
|
||||
module_name = os.path.splitext(py_file)[0]
|
||||
sha1_key = self.include_py_map.get(module_name)
|
||||
if sha1_key and sha1_key in self.sig_files:
|
||||
@@ -1635,7 +1641,7 @@ class Phase2Translator:
|
||||
for root, dirs, files in os.walk(includes_dir):
|
||||
dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__']
|
||||
for fname in files:
|
||||
if not fname.endswith('.py'):
|
||||
if not (fname.endswith('.vp') or fname.endswith('.py')):
|
||||
continue
|
||||
py_path: str = os.path.join(root, fname)
|
||||
code, tree = parse_python_file(py_path)
|
||||
@@ -1691,7 +1697,7 @@ class Phase2Translator:
|
||||
for root, dirs, files in os.walk(includes_dir):
|
||||
dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__']
|
||||
for fname in files:
|
||||
if fname.endswith('.py'):
|
||||
if fname.endswith('.vp') or fname.endswith('.py'):
|
||||
py_index.add(os.path.normcase(os.path.join(root, fname)))
|
||||
return py_index
|
||||
|
||||
@@ -1714,7 +1720,7 @@ class Phase2Translator:
|
||||
for root, dirs, files in os.walk(module_dir):
|
||||
dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__']
|
||||
for fname in files:
|
||||
if fname.endswith('.py'):
|
||||
if fname.endswith('.vp') or fname.endswith('.py'):
|
||||
py_path = os.path.join(root, fname)
|
||||
if py_path not in self.extra_py_files:
|
||||
self.extra_py_files.append(py_path)
|
||||
@@ -1732,7 +1738,10 @@ class Phase2Translator:
|
||||
self.extra_compile_files.append(src_path)
|
||||
_vlog().info(f" [includes] 发现源文件: {os.path.relpath(src_path, includes_dir)}")
|
||||
|
||||
py_path = os.path.join(includes_dir, module_name + '.py')
|
||||
py_path = os.path.join(includes_dir, module_name + '.vp')
|
||||
if os.path.normcase(py_path) not in py_index:
|
||||
# 回退到 .py(向后兼容)
|
||||
py_path = os.path.join(includes_dir, module_name + '.py')
|
||||
if os.path.normcase(py_path) in py_index:
|
||||
self.extra_py_files.append(py_path)
|
||||
_vlog().info(f" [includes] 发现 Python 源文件: {os.path.relpath(py_path, includes_dir)}")
|
||||
@@ -1790,15 +1799,18 @@ class Phase2Translator:
|
||||
|
||||
py_index 非空时用 set 查询替代 os.path.isfile(O(1) vs 24ms/次)。
|
||||
"""
|
||||
# 候选路径:子包路径(w32/win32base.py)、顶层模块(w32.py)、子包 __init__.py
|
||||
# 候选路径:子包路径(w32/win32base.vp/.py)、顶层模块(w32.vp/.py)、子包 __init__.vp/__init__.py
|
||||
candidates: list[str] = []
|
||||
# 子包路径:w32.win32base → w32/win32base.py
|
||||
# 子包路径:w32.win32base → w32/win32base.vp / .py
|
||||
candidates.append(os.path.join(includes_dir, module_name.replace('.', os.sep) + '.vp'))
|
||||
candidates.append(os.path.join(includes_dir, module_name.replace('.', os.sep) + '.py'))
|
||||
# 子包 __init__.py:w32.win32base → w32/win32base/__init__.py
|
||||
# 子包 __init__.vp/__init__.py:w32.win32base → w32/win32base/__init__.vp / .py
|
||||
candidates.append(os.path.join(includes_dir, module_name.replace('.', os.sep), '__init__.vp'))
|
||||
candidates.append(os.path.join(includes_dir, module_name.replace('.', os.sep), '__init__.py'))
|
||||
# 顶层模块:取第一个组件 → w32.py
|
||||
# 顶层模块:取第一个组件 → w32.vp / .py
|
||||
top_module = module_name.split('.')[0]
|
||||
if top_module != module_name:
|
||||
candidates.append(os.path.join(includes_dir, top_module + '.vp'))
|
||||
candidates.append(os.path.join(includes_dir, top_module + '.py'))
|
||||
|
||||
for py_path in candidates:
|
||||
@@ -2423,7 +2435,7 @@ class Phase2Translator:
|
||||
if not os.path.isdir(includes_dir):
|
||||
continue
|
||||
for filename in os.listdir(includes_dir):
|
||||
if not filename.endswith('.py'):
|
||||
if not (filename.endswith('.vp') or filename.endswith('.py')):
|
||||
continue
|
||||
src_path = os.path.join(includes_dir, filename)
|
||||
try:
|
||||
@@ -2533,7 +2545,7 @@ class Phase2Translator:
|
||||
pass
|
||||
|
||||
# 1. 生成 .pyi 签名文件(如果还没有的话)
|
||||
sig_path = os.path.join(self.temp_dir, f"{sha1}.pyi")
|
||||
sig_path = os.path.join(self.temp_dir, f"{sha1}.vpi")
|
||||
if not os.path.isfile(sig_path):
|
||||
# 全局缓存检查(不被 --clean 清除)
|
||||
_TryGlobalCache(sha1, 'pyi', sig_path)
|
||||
@@ -2554,7 +2566,7 @@ class Phase2Translator:
|
||||
# 注册到 sig_files 和 _source_module_sig_files
|
||||
if os.path.isfile(sig_path):
|
||||
self.sig_files[sha1] = sig_path
|
||||
self.sha1_map[sha1] = f"includes/{mod_full.replace('.', '/')}.py"
|
||||
self.sha1_map[sha1] = f"includes/{mod_full.replace('.', '/')}.vp"
|
||||
if self._shared_source_module_sig_files is not None:
|
||||
self._shared_source_module_sig_files[mod_full] = sig_path
|
||||
self._shared_source_module_sig_files[module_name] = sig_path
|
||||
@@ -2611,10 +2623,13 @@ class Phase2Translator:
|
||||
for root, dirs, files in os.walk(module_dir):
|
||||
dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__']
|
||||
for fname in files:
|
||||
if fname.endswith('.py'):
|
||||
if fname.endswith('.vp') or fname.endswith('.py'):
|
||||
src_path = os.path.join(root, fname)
|
||||
self._collect_inline_symbols(src_path)
|
||||
py_path = os.path.join(includes_dir, module_name + '.py')
|
||||
py_path = os.path.join(includes_dir, module_name + '.vp')
|
||||
if not os.path.isfile(py_path):
|
||||
# 回退到 .py(向后兼容)
|
||||
py_path = os.path.join(includes_dir, module_name + '.py')
|
||||
if os.path.isfile(py_path):
|
||||
self._collect_inline_symbols(py_path)
|
||||
for ef in self.extra_py_files:
|
||||
@@ -2677,12 +2692,12 @@ class Phase2Translator:
|
||||
for includes_dir in self.include_dirs:
|
||||
if os.path.isdir(includes_dir):
|
||||
for pyi_file in os.listdir(includes_dir):
|
||||
if pyi_file.endswith('.pyi'):
|
||||
if pyi_file.endswith('.vpi') or pyi_file.endswith('.pyi'):
|
||||
pyi_path = os.path.join(includes_dir, pyi_file)
|
||||
module_name = os.path.splitext(pyi_file)[0]
|
||||
base_trans.translator.SymbolTable.LoadModuleSymbols(pyi_path, module_name, lineno=0)
|
||||
for py_file in os.listdir(includes_dir):
|
||||
if py_file.endswith('.py') and (not py_file.startswith('_') or py_file == '_list.py' or py_file == '_dict.py'):
|
||||
if (py_file.endswith('.vp') or py_file.endswith('.py')) and (not py_file.startswith('_') or py_file == '_list.vp' or py_file == '_list.py' or py_file == '_dict.vp' or py_file == '_dict.py'):
|
||||
module_name = os.path.splitext(py_file)[0]
|
||||
sha1_key = self.include_py_map.get(module_name)
|
||||
if sha1_key and sha1_key in self.sig_files:
|
||||
@@ -2775,7 +2790,7 @@ class Phase2Translator:
|
||||
if not os.path.isdir(abs_includes):
|
||||
abs_includes = includes_dir
|
||||
for py_file in os.listdir(abs_includes):
|
||||
if py_file.endswith('.py') and (not py_file.startswith('_') or py_file == '_list.py' or py_file == '_dict.py'):
|
||||
if (py_file.endswith('.vp') or py_file.endswith('.py')) and (not py_file.startswith('_') or py_file == '_list.vp' or py_file == '_list.py' or py_file == '_dict.vp' or py_file == '_dict.py'):
|
||||
py_path = os.path.join(abs_includes, py_file)
|
||||
try:
|
||||
# 复用 parse_python_file 的 AST 缓存
|
||||
|
||||
@@ -127,19 +127,19 @@ def clear_file_deps_cache() -> None:
|
||||
|
||||
|
||||
def find_reachable_files_from_entries(src_root: str, entry_files: list[str]) -> set[str]:
|
||||
"""从入口文件出发,找出所有可达的 .py 文件(通过导入关系)"""
|
||||
"""从入口文件出发,找出所有可达的 .vp/.py 文件(通过导入关系)"""
|
||||
all_files: dict[str, str] = {} # module_name -> filepath
|
||||
for root, dirs, files in os.walk(src_root):
|
||||
dirs[:] = [d for d in dirs if d not in ('__pycache__',)]
|
||||
for file in files:
|
||||
if file.endswith('.py'):
|
||||
if file.endswith('.vp') or file.endswith('.py'):
|
||||
filepath: str = os.path.join(root, file)
|
||||
rel: str = os.path.relpath(filepath, src_root)
|
||||
module: str = os.path.splitext(rel)[0].replace(os.sep, '.').replace('/', '.')
|
||||
if filepath.endswith('__init__.py'):
|
||||
if filepath.endswith('__init__.vp') or filepath.endswith('__init__.py'):
|
||||
all_files[module] = filepath
|
||||
parent_module: str = module.rsplit('.', 1)[0] if '.' in module else module
|
||||
if parent_module not in all_files or not all_files[parent_module].endswith('__init__.py'):
|
||||
if parent_module not in all_files or not (all_files[parent_module].endswith('__init__.vp') or all_files[parent_module].endswith('__init__.py')):
|
||||
all_files[parent_module] = filepath
|
||||
elif module not in all_files:
|
||||
all_files[module] = filepath
|
||||
|
||||
@@ -89,7 +89,7 @@ class TransPyC:
|
||||
FileType: str | None = SymbolFile.FileType
|
||||
if not FileType and SymbolFile.FilePath:
|
||||
# 从文件路径推断类型
|
||||
if SymbolFile.FilePath.endswith('.py'):
|
||||
if SymbolFile.FilePath.endswith('.vp') or SymbolFile.FilePath.endswith('.py'):
|
||||
FileType = 'py'
|
||||
elif SymbolFile.FilePath.endswith('.c') or SymbolFile.FilePath.endswith('.h'):
|
||||
FileType = 'c'
|
||||
@@ -298,7 +298,7 @@ class TransPyC:
|
||||
|
||||
# 如果没有指定输出文件,使用默认名称
|
||||
if not OutputFile:
|
||||
OutputFile = InputFile.replace('.py', '.symbin').replace('.c', '.symbin')
|
||||
OutputFile = InputFile.replace('.vp', '.symbin').replace('.py', '.symbin').replace('.c', '.symbin')
|
||||
|
||||
# 执行预处理
|
||||
self.Args['PreSym'] = {
|
||||
@@ -599,7 +599,7 @@ class TransPyC:
|
||||
encoding: str = self.Args.get('Encoding', 'utf-8')
|
||||
|
||||
# 推断文件类型
|
||||
FileType: str | None = 'py' if InputFile.endswith('.py') else 'c' if InputFile.endswith('.c') else None
|
||||
FileType: str | None = 'py' if (InputFile.endswith('.vp') or InputFile.endswith('.py')) else 'c' if InputFile.endswith('.c') else None
|
||||
|
||||
# 创建 SymbolFile 对象,传入编码参数
|
||||
SymbolFile: SymbolFile = SymbolFile(file=InputFile, type=FileType, encoding=encoding)
|
||||
@@ -629,11 +629,11 @@ class TransPyC:
|
||||
# 没有命令行参数,使用默认的测试文件名称
|
||||
InputFile: str = DEFAULT_INPUT_FILE
|
||||
OutputFile: str = DEFAULT_OUTPUT_FILE
|
||||
info('使用默认测试文件: test.py -> test.c')
|
||||
info('使用默认测试文件: test.vp -> test.c')
|
||||
|
||||
FileType: str = DetectFileType(InputFile)
|
||||
|
||||
if FileType == '.py':
|
||||
if FileType in ('.vp', '.py'):
|
||||
self.PythonToC(InputFile, OutputFile)
|
||||
# 检查是否需要编译和运行
|
||||
if 'CompileCommand' in self.Args or self.Args.get('Run', False):
|
||||
|
||||
@@ -11,7 +11,7 @@ class StubGenConfig:
|
||||
InputDir: Optional[str] = None
|
||||
OutputDir: str = "./stubs"
|
||||
InputFiles: List[str] = field(default_factory=list)
|
||||
IncludePatterns: List[str] = field(default_factory=lambda: ["*.h", "*.c", "*.py"])
|
||||
IncludePatterns: List[str] = field(default_factory=lambda: ["*.h", "*.c", "*.vp", "*.py"])
|
||||
ExcludePatterns: List[str] = field(default_factory=list)
|
||||
TypeMappings: Dict[str, str] = field(default_factory=dict)
|
||||
PreserveStructure: bool = True # 保持目录结构
|
||||
@@ -26,7 +26,7 @@ class StubGenConfig:
|
||||
InputDir=data.get('InputDir'),
|
||||
OutputDir=data.get('OutputDir', './stubs'),
|
||||
InputFiles=data.get('InputFiles', []),
|
||||
IncludePatterns=data.get('IncludePatterns', ['*.h', '*.c', '*.py']),
|
||||
IncludePatterns=data.get('IncludePatterns', ['*.h', '*.c', '*.vp', '*.py']),
|
||||
ExcludePatterns=data.get('ExcludePatterns', []),
|
||||
TypeMappings=data.get('TypeMappings', {}),
|
||||
PreserveStructure=data.get('PreserveStructure', True),
|
||||
|
||||
@@ -58,7 +58,7 @@ class PythonToStubConverter:
|
||||
|
||||
# 添加文件头
|
||||
StubLines.append('"""')
|
||||
StubLines.append(f'Auto-generated Python stub file from {ModuleName}.py')
|
||||
StubLines.append(f'Auto-generated Python stub file from {ModuleName}.vp')
|
||||
StubLines.append(f'Module: {ModuleName}')
|
||||
StubLines.append('"""')
|
||||
StubLines.append('')
|
||||
|
||||
@@ -98,9 +98,9 @@ class StubGen:
|
||||
|
||||
def _GetOutputPath(self, RelPath: str) -> str:
|
||||
"""获取输出文件路径"""
|
||||
# 更改扩展名为 .pyi (Python stub file)
|
||||
# 更改扩展名为 .vpi (Python stub file)
|
||||
BaseName: str = os.path.splitext(RelPath)[0]
|
||||
OutputRelPath: str = BaseName + '.pyi'
|
||||
OutputRelPath: str = BaseName + '.vpi'
|
||||
|
||||
# 构建完整输出路径
|
||||
if self.config.OutputDir:
|
||||
@@ -280,7 +280,7 @@ Examples:
|
||||
config: StubGenConfig = StubGenConfig.from_file(args.config)
|
||||
else:
|
||||
config = StubGenConfig()
|
||||
config.IncludePatterns = args.include or ['*.h', '*.c', '*.py']
|
||||
config.IncludePatterns = args.include or ['*.h', '*.c', '*.vp', '*.py']
|
||||
config.ExcludePatterns = args.exclude or []
|
||||
config.GenerateGuards = not args.no_guards
|
||||
config.PreserveStructure = not args.no_structure
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 常量定义
|
||||
from __future__ import annotations
|
||||
|
||||
DEFAULT_INPUT_FILE: str = 'test.py'
|
||||
DEFAULT_INPUT_FILE: str = 'test.vp'
|
||||
DEFAULT_OUTPUT_FILE: str = 'test.ll'
|
||||
|
||||
SLICE_THRESHOLD: int = 50
|
||||
|
||||
@@ -2124,9 +2124,12 @@ class ExprCallHandle(BaseHandle):
|
||||
def load_pyi(sha1: str) -> dict[str, ast.ClassDef] | None:
|
||||
if sha1 in pyi_cache:
|
||||
return pyi_cache[sha1]
|
||||
pyi_path = os.path.join(project_root, 'temp', f'{sha1}.pyi')
|
||||
pyi_path = os.path.join(project_root, 'temp', f'{sha1}.vpi')
|
||||
if not os.path.isfile(pyi_path):
|
||||
return None
|
||||
# 回退读取旧缓存 .pyi
|
||||
pyi_path = os.path.join(project_root, 'temp', f'{sha1}.pyi')
|
||||
if not os.path.isfile(pyi_path):
|
||||
return None
|
||||
with open(pyi_path, 'r', encoding='utf-8') as f:
|
||||
pyi_code = f.read()
|
||||
tree = ast.parse(pyi_code)
|
||||
|
||||
@@ -199,7 +199,7 @@ class ImportHandle(BaseHandle):
|
||||
for _ in range(Node.level - 1):
|
||||
parent_dir = os.path.dirname(parent_dir)
|
||||
if module:
|
||||
SearchExtensions = ['.pyi', '.py']
|
||||
SearchExtensions = ['.vpi', '.vp', '.pyi', '.py']
|
||||
sub_path_base = os.path.join(parent_dir, module)
|
||||
for ext in SearchExtensions:
|
||||
candidate = sub_path_base + ext
|
||||
@@ -215,7 +215,7 @@ class ImportHandle(BaseHandle):
|
||||
if target_sha1:
|
||||
temp_dir = getattr(Gen, '_temp_dir', None)
|
||||
if temp_dir:
|
||||
sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.pyi")
|
||||
sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.vpi")
|
||||
if os.path.isfile(sha1_pyi):
|
||||
self.Trans._ImportedModules.add(module)
|
||||
self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=module, register_module_name=current_module)
|
||||
@@ -224,7 +224,7 @@ class ImportHandle(BaseHandle):
|
||||
else:
|
||||
mod_dir = parent_dir
|
||||
|
||||
SearchExtensions = ['.pyi', '.py']
|
||||
SearchExtensions = ['.vpi', '.vp', '.pyi', '.py']
|
||||
pkg_name = ''
|
||||
if not module:
|
||||
# When 'from . import name' is used, Load the package's __init__
|
||||
@@ -251,7 +251,7 @@ class ImportHandle(BaseHandle):
|
||||
if target_sha1:
|
||||
temp_dir = getattr(Gen, '_temp_dir', None)
|
||||
if temp_dir:
|
||||
sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.pyi")
|
||||
sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.vpi")
|
||||
if os.path.isfile(sha1_pyi):
|
||||
self.Trans._ImportedModules.add(sub_ModulePath)
|
||||
self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=alias.name, register_module_name=current_module)
|
||||
@@ -274,8 +274,8 @@ class ImportHandle(BaseHandle):
|
||||
if not module_prefix:
|
||||
return
|
||||
basename: str = os.path.basename(pyi_path)
|
||||
# 若传入 .py 文件,则从 _source_module_sig_files 查找对应的 {sha1}.pyi
|
||||
if basename.endswith('.py'):
|
||||
# 若传入 .vp/.py 文件,则从 _source_module_sig_files 查找对应的 {sha1}.vpi
|
||||
if basename.endswith('.vp') or basename.endswith('.py'):
|
||||
source_sig_files = getattr(self.Trans, '_source_module_sig_files', None)
|
||||
if source_sig_files:
|
||||
sig_path = source_sig_files.get(module_prefix)
|
||||
@@ -286,9 +286,9 @@ class ImportHandle(BaseHandle):
|
||||
return
|
||||
else:
|
||||
return
|
||||
if not basename.endswith('.pyi'):
|
||||
if not (basename.endswith('.vpi') or basename.endswith('.pyi')):
|
||||
return
|
||||
sha1: str = basename[:-len('.pyi')]
|
||||
sha1: str = basename[:-4] # 去掉 .vpi 或 .pyi 后缀(均为 4 字符)
|
||||
shared_doc_meta = getattr(self.Trans, '_shared_doc_meta', None)
|
||||
if not shared_doc_meta:
|
||||
return
|
||||
@@ -390,7 +390,7 @@ class ImportHandle(BaseHandle):
|
||||
for _ in range(node.level - 1):
|
||||
parent_dir = os.path.dirname(parent_dir)
|
||||
if node.module:
|
||||
SearchExtensions = ['.pyi', '.py']
|
||||
SearchExtensions = ['.vpi', '.vp', '.pyi', '.py']
|
||||
sub_path_base = os.path.join(parent_dir, node.module)
|
||||
found_sub = False
|
||||
# 治本修复:用包目录名(如 'json')而非 register_module_name(当前编译模块名,如 '_dict')。
|
||||
@@ -428,7 +428,7 @@ class ImportHandle(BaseHandle):
|
||||
if target_sha1:
|
||||
temp_dir = getattr(Gen, '_temp_dir', None)
|
||||
if temp_dir:
|
||||
sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.pyi")
|
||||
sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.vpi")
|
||||
if os.path.isfile(sha1_pyi):
|
||||
if not getattr(self.Trans, '_ImportedModules', None):
|
||||
self.Trans._ImportedModules = set()
|
||||
@@ -440,7 +440,7 @@ class ImportHandle(BaseHandle):
|
||||
self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=alias.name, register_module_name=register_module_name, actual_module_name=actual_module, reexport_package=reexport_package or module_name)
|
||||
else:
|
||||
mod_dir = parent_dir
|
||||
SearchExtensions = ['.pyi', '.py']
|
||||
SearchExtensions = ['.vpi', '.vp', '.pyi', '.py']
|
||||
# Load __init__.py to make package-level names available
|
||||
self._LoadPackageInitForRelativeImport(mod_dir, Gen, register_module_name)
|
||||
# 治本修复:用包目录名(如 'json')而非 register_module_name(当前编译模块名,如 '_dict')。
|
||||
@@ -472,7 +472,7 @@ class ImportHandle(BaseHandle):
|
||||
if target_sha1:
|
||||
temp_dir = getattr(Gen, '_temp_dir', None)
|
||||
if temp_dir:
|
||||
sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.pyi")
|
||||
sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.vpi")
|
||||
if os.path.isfile(sha1_pyi):
|
||||
if not getattr(self.Trans, '_ImportedModules', None):
|
||||
self.Trans._ImportedModules = set()
|
||||
@@ -528,14 +528,14 @@ class ImportHandle(BaseHandle):
|
||||
if pkg_sha1:
|
||||
temp_dir = getattr(Gen, '_temp_dir', None)
|
||||
if temp_dir:
|
||||
sha1_pyi = os.path.join(temp_dir, f"{pkg_sha1}.pyi")
|
||||
sha1_pyi = os.path.join(temp_dir, f"{pkg_sha1}.vpi")
|
||||
if os.path.isfile(sha1_pyi):
|
||||
self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=pkg_name, register_module_name=register_module_name)
|
||||
init_Loaded = True
|
||||
|
||||
# Fallback: try Loading __init__.py directly from the package directory
|
||||
if not init_Loaded:
|
||||
for ext in ['.pyi', '.py']:
|
||||
for ext in ['.vpi', '.vp', '.pyi', '.py']:
|
||||
init_path = os.path.join(mod_dir, '__init__' + ext)
|
||||
if os.path.isfile(init_path):
|
||||
self._LoadModuleDeclarationsFromFile(init_path, Gen, module_name=pkg_name, register_module_name=register_module_name)
|
||||
@@ -552,48 +552,59 @@ class ImportHandle(BaseHandle):
|
||||
self._emitted_module_decls.add(decl_key)
|
||||
if module_name in ('pyzlib',):
|
||||
source_sig_files = getattr(self.Trans, '_source_module_sig_files', None)
|
||||
ModulePath = module_name.replace('.', os.sep) + '.pyi'
|
||||
PackageInitPath = module_name.replace('.', os.sep) + os.sep + '__init__.pyi'
|
||||
ModulePathBase = module_name.replace('.', os.sep)
|
||||
PackageInitPathBase = module_name.replace('.', os.sep) + os.sep + '__init__'
|
||||
ProjectRoot = os.path.dirname(os.path.abspath(getattr(self.Trans, 'CurrentFile', '') or '')) or os.getcwd()
|
||||
|
||||
HandlesFile = os.path.abspath(inspect.getfile(self.__class__))
|
||||
TransPyCRoot = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(HandlesFile))))
|
||||
|
||||
|
||||
FullModulePath = None
|
||||
SearchDirs = [os.path.join(TransPyCRoot, 'includes'), os.path.join(TransPyCRoot, 'lib', 'includes')] + list(self.Trans.LibraryPaths)
|
||||
|
||||
for LibPath in SearchDirs:
|
||||
SearchPath = os.path.join(ProjectRoot, LibPath) if not os.path.isabs(LibPath) else LibPath
|
||||
CandidatePath = os.path.join(SearchPath, ModulePath)
|
||||
if os.path.isfile(CandidatePath):
|
||||
FullModulePath = CandidatePath
|
||||
# 优先尝试 .vpi,回退 .pyi
|
||||
for stub_ext in ('.vpi', '.pyi'):
|
||||
CandidatePath = os.path.join(SearchPath, ModulePathBase + stub_ext)
|
||||
if os.path.isfile(CandidatePath):
|
||||
FullModulePath = CandidatePath
|
||||
break
|
||||
CandidatePath = os.path.join(SearchPath, PackageInitPathBase + stub_ext)
|
||||
if os.path.isfile(CandidatePath):
|
||||
FullModulePath = CandidatePath
|
||||
break
|
||||
if FullModulePath:
|
||||
break
|
||||
CandidatePath = os.path.join(SearchPath, PackageInitPath)
|
||||
if os.path.isfile(CandidatePath):
|
||||
FullModulePath = CandidatePath
|
||||
break
|
||||
ModuleParts = ModulePath.split(os.sep)
|
||||
ModuleParts = ModulePathBase.split(os.sep)
|
||||
if len(ModuleParts) > 1:
|
||||
LibPathBasename = os.path.basename(LibPath.rstrip('/\\'))
|
||||
if LibPathBasename == ModuleParts[0]:
|
||||
RemainingPath = os.sep.join(ModuleParts[1:])
|
||||
CandidatePath = os.path.join(SearchPath, RemainingPath)
|
||||
if os.path.isfile(CandidatePath):
|
||||
FullModulePath = CandidatePath
|
||||
for stub_ext in ('.vpi', '.pyi'):
|
||||
CandidatePath = os.path.join(SearchPath, RemainingPath + stub_ext)
|
||||
if os.path.isfile(CandidatePath):
|
||||
FullModulePath = CandidatePath
|
||||
break
|
||||
if FullModulePath:
|
||||
break
|
||||
if not FullModulePath:
|
||||
ModulePathPy = module_name.replace('.', os.sep) + '.py'
|
||||
PackageInitPathPy = module_name.replace('.', os.sep) + os.sep + '__init__.py'
|
||||
ModulePathPyBase = module_name.replace('.', os.sep)
|
||||
PackageInitPathPyBase = module_name.replace('.', os.sep) + os.sep + '__init__'
|
||||
SearchDirsForPy = [os.path.join(TransPyCRoot, 'includes'), os.path.join(TransPyCRoot, 'lib', 'includes')] + list(self.Trans.LibraryPaths)
|
||||
for LibPath in SearchDirsForPy:
|
||||
SearchPath = os.path.join(ProjectRoot, LibPath) if not os.path.isabs(LibPath) else LibPath
|
||||
CandidatePath = os.path.join(SearchPath, ModulePathPy)
|
||||
if os.path.isfile(CandidatePath):
|
||||
FullModulePath = CandidatePath
|
||||
break
|
||||
CandidatePath = os.path.join(SearchPath, PackageInitPathPy)
|
||||
if os.path.isfile(CandidatePath):
|
||||
FullModulePath = CandidatePath
|
||||
# 优先尝试 .vp,回退 .py
|
||||
for src_ext in ('.vp', '.py'):
|
||||
CandidatePath = os.path.join(SearchPath, ModulePathPyBase + src_ext)
|
||||
if os.path.isfile(CandidatePath):
|
||||
FullModulePath = CandidatePath
|
||||
break
|
||||
CandidatePath = os.path.join(SearchPath, PackageInitPathPyBase + src_ext)
|
||||
if os.path.isfile(CandidatePath):
|
||||
FullModulePath = CandidatePath
|
||||
break
|
||||
if FullModulePath:
|
||||
break
|
||||
if not FullModulePath or not os.path.isfile(FullModulePath):
|
||||
source_sig_files = getattr(self.Trans, '_source_module_sig_files', None)
|
||||
@@ -622,11 +633,11 @@ class ImportHandle(BaseHandle):
|
||||
for root, dirs, files in os.walk(SearchPath):
|
||||
if '__pycache__' in root:
|
||||
continue
|
||||
if module_name + '.py' in files:
|
||||
FullModulePath = os.path.join(root, module_name + '.py')
|
||||
break
|
||||
if module_name + '.pyi' in files:
|
||||
FullModulePath = os.path.join(root, module_name + '.pyi')
|
||||
for src_ext in ('.vp', '.py', '.vpi', '.pyi'):
|
||||
if module_name + src_ext in files:
|
||||
FullModulePath = os.path.join(root, module_name + src_ext)
|
||||
break
|
||||
if FullModulePath:
|
||||
break
|
||||
if FullModulePath:
|
||||
break
|
||||
@@ -687,7 +698,7 @@ class ImportHandle(BaseHandle):
|
||||
for _ in range(node.level - 1):
|
||||
parent_dir = os.path.dirname(parent_dir)
|
||||
if node.module:
|
||||
SearchExtensions = ['.pyi', '.py']
|
||||
SearchExtensions = ['.vpi', '.vp', '.pyi', '.py']
|
||||
sub_path_base = os.path.join(parent_dir, node.module)
|
||||
found_sub = False
|
||||
for ext in SearchExtensions:
|
||||
@@ -715,7 +726,7 @@ class ImportHandle(BaseHandle):
|
||||
if target_sha1:
|
||||
temp_dir = getattr(Gen, '_temp_dir', None)
|
||||
if temp_dir:
|
||||
sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.pyi")
|
||||
sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.vpi")
|
||||
if os.path.isfile(sha1_pyi):
|
||||
if not getattr(self.Trans, '_ImportedModules', None):
|
||||
self.Trans._ImportedModules = set()
|
||||
@@ -728,7 +739,7 @@ class ImportHandle(BaseHandle):
|
||||
has_functions_or_classes = True
|
||||
else:
|
||||
mod_dir = parent_dir
|
||||
SearchExtensions = ['.pyi', '.py']
|
||||
SearchExtensions = ['.vpi', '.vp', '.pyi', '.py']
|
||||
# Load __init__.py to make package-level names available
|
||||
self._LoadPackageInitForRelativeImport(mod_dir, Gen, register_module_name or module_name)
|
||||
for alias in node.names:
|
||||
@@ -755,7 +766,7 @@ class ImportHandle(BaseHandle):
|
||||
if target_sha1:
|
||||
temp_dir = getattr(Gen, '_temp_dir', None)
|
||||
if temp_dir:
|
||||
sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.pyi")
|
||||
sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.vpi")
|
||||
if os.path.isfile(sha1_pyi):
|
||||
if not getattr(self.Trans, '_ImportedModules', None):
|
||||
self.Trans._ImportedModules = set()
|
||||
@@ -2063,8 +2074,12 @@ class ImportHandle(BaseHandle):
|
||||
temp_dir = os.path.join(ProjectRoot, 'temp')
|
||||
if class_name in Gen.class_members and len(Gen.class_members[class_name]) > 0:
|
||||
return
|
||||
pyi_basename = stub_filename.replace('.stub.ll', '.pyi')
|
||||
pyi_basename = stub_filename.replace('.stub.ll', '.vpi')
|
||||
pyi_path = os.path.join(temp_dir, pyi_basename)
|
||||
if not os.path.isfile(pyi_path):
|
||||
# 回退读取旧缓存 .pyi
|
||||
pyi_basename = stub_filename.replace('.stub.ll', '.pyi')
|
||||
pyi_path = os.path.join(temp_dir, pyi_basename)
|
||||
|
||||
if self._pyi_cache_dir != temp_dir:
|
||||
self._pyi_cache.clear()
|
||||
@@ -2286,7 +2301,7 @@ class ImportHandle(BaseHandle):
|
||||
if module_name:
|
||||
for key, val in source_sig_files.items():
|
||||
if key == module_name or key.endswith('.' + module_name):
|
||||
target_sha1 = os.path.basename(val).replace('.pyi', '')
|
||||
target_sha1 = os.path.basename(val).replace('.vpi', '').replace('.pyi', '')
|
||||
break
|
||||
if not target_sha1:
|
||||
ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
|
||||
|
||||
@@ -395,8 +395,8 @@ class FuncGenMixin:
|
||||
for temp_dir_candidate in [getattr(self, '_temp_dir', None)]:
|
||||
if temp_dir_candidate and os.path.isdir(temp_dir_candidate):
|
||||
for pyi_file in os.listdir(temp_dir_candidate):
|
||||
if pyi_file.endswith('.pyi'):
|
||||
stub_name: str = pyi_file.replace('.pyi', '.stub.ll')
|
||||
if pyi_file.endswith('.vpi') or pyi_file.endswith('.pyi'):
|
||||
stub_name: str = pyi_file.replace('.vpi', '.stub.ll').replace('.pyi', '.stub.ll')
|
||||
short_cn: str = short_name if short_name else ClassName
|
||||
self._Trans.ImportHandler._TryLoadClassMembersFromPyi(short_cn, stub_name, self)
|
||||
if short_cn in self.class_members and len(self.class_members[short_cn]) > 0:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"""
|
||||
C/H 文件到 Python 存根文件生成器
|
||||
|
||||
将 C 头文件 (.h) 或 C 源文件 (.c) 转换为 Python 存根文件 (.pyi)
|
||||
将 C 头文件 (.h) 或 C 源文件 (.c) 转换为 Python 存根文件 (.vpi)
|
||||
生成的 Python 代码使用 TransPyC 语法,包含类型注解
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
Reference in New Issue
Block a user