first commit
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
# generate_pyi.py
|
||||
|
||||
import re
|
||||
import os
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
def sanitize_name(name: str) -> str:
|
||||
name = re.sub(r'[^a-zA-Z0-9_]', '_', name)
|
||||
return re.sub(r'^[^a-zA-Z_]+', '', name)
|
||||
|
||||
def pascal_case(s: str) -> str:
|
||||
"""将字符串转为 PascalCase"""
|
||||
return ''.join(word.capitalize() for word in re.split(r'[\W_]+', s) if word)
|
||||
|
||||
def generate_pyi(base_dir: str, output_file: str):
|
||||
base_path = Path(base_dir)
|
||||
if not base_path.exists():
|
||||
raise FileNotFoundError(f"资源目录不存在: {base_dir}")
|
||||
|
||||
# 构建目录树结构
|
||||
tree = {}
|
||||
|
||||
for root, dirs, files in os.walk(str(base_path)):
|
||||
relative_path = Path(root).relative_to(base_path)
|
||||
parts = list(relative_path.parts) if relative_path != Path('.') else []
|
||||
|
||||
# 插入当前路径到树中
|
||||
current = tree
|
||||
for part in parts:
|
||||
safe_part = sanitize_name(part)
|
||||
if safe_part not in current:
|
||||
current[safe_part] = {}
|
||||
current = current[safe_part]
|
||||
|
||||
# 添加图像文件作为叶子节点
|
||||
for file in files:
|
||||
if file.startswith('.'):
|
||||
continue
|
||||
if file.split('.')[-1].lower() in {'png', 'jpg', 'jpeg', 'bmp', 'gif'}:
|
||||
stem = sanitize_name(Path(file).stem)
|
||||
current[stem] = None # 表示这是一个图像资源(str 类型)
|
||||
|
||||
# 构建类定义
|
||||
class_defs = []
|
||||
written_classes = set()
|
||||
|
||||
def build_class(class_name: str, data: dict):
|
||||
if not data or class_name in written_classes:
|
||||
return
|
||||
written_classes.add(class_name)
|
||||
|
||||
lines = [f"class {class_name}:\n"]
|
||||
has_content = False
|
||||
|
||||
for key in sorted(data.keys()):
|
||||
value = data[key]
|
||||
safe_key = key
|
||||
if value is None:
|
||||
# 图像文件:直接定义为 str 属性
|
||||
lines.append(f" {safe_key}: str\n")
|
||||
has_content = True
|
||||
else:
|
||||
# 子目录:引用一个类
|
||||
nested_class_name = pascal_case(safe_key)
|
||||
lines.append(f" {safe_key}: \"{nested_class_name}\"\n")
|
||||
build_class(nested_class_name, value)
|
||||
has_content = True
|
||||
|
||||
if has_content:
|
||||
class_defs.append("".join(lines))
|
||||
else:
|
||||
# 空类不写入
|
||||
written_classes.remove(class_name)
|
||||
|
||||
# 构建主类 ImageResourceLoader
|
||||
loader_lines = []
|
||||
for key in sorted(tree.keys()):
|
||||
value = tree[key]
|
||||
if not value: # 跳过空的子目录
|
||||
loader_lines.append(f" {key}: str\n")
|
||||
continue
|
||||
class_name = pascal_case(key)
|
||||
loader_lines.append(f" {key}: {class_name}\n")
|
||||
build_class(class_name, value)
|
||||
|
||||
# 写入 .pyi 文件
|
||||
with open(output_file, 'w', encoding='utf-8') as f:
|
||||
f.write("from typing import Optional, Any\n\n")
|
||||
|
||||
# 写入所有子类定义
|
||||
for line in class_defs:
|
||||
f.write(line + "\n")
|
||||
|
||||
# 写入主类
|
||||
f.write("class ImageResourceLoader:\n")
|
||||
f.write(" def __init__(self, base_dir: str): ...\n")
|
||||
f.write(" def list_resources(self) -> None: ...\n")
|
||||
f.write(" def get(self, path: str, default: Optional[str] = ...) -> Optional[str]: ...\n")
|
||||
f.write(" def __getattr__(self, name: str) -> Any: ...\n")
|
||||
f.write("\n # 自动生成的资源类属性(仅用于 IDE 提示)\n")
|
||||
f.writelines(loader_lines)
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="为 ImageResourceLoader 类生成 .pyi 存根文件。")
|
||||
parser.add_argument("source_file", help="Python 源文件路径(例如:image_loader.py)")
|
||||
parser.add_argument("--base_dir", default=".automation",
|
||||
help="图像资源目录,默认值:.automation")
|
||||
args = parser.parse_args()
|
||||
|
||||
source_path = Path(args.source_file)
|
||||
if not source_path.exists():
|
||||
raise FileNotFoundError(f"源文件不存在: {args.source_file}")
|
||||
|
||||
# 输出 .pyi 文件路径
|
||||
pyi_path = source_path.with_suffix(".pyi")
|
||||
|
||||
print(f"生成存根文件: {pyi_path}")
|
||||
print(f"使用资源目录: {args.base_dir}")
|
||||
|
||||
generate_pyi(args.base_dir, str(pyi_path))
|
||||
"""
|
||||
python scripts/generate_pyi.py image_loader.py --base_dir assets/images
|
||||
|
||||
"""
|
||||
Reference in New Issue
Block a user