Files
wehub-resource-sync 2aaeece67c
Pipelines-Test / Pipelines-Test (push) Waiting to run
Codestyle Check / Lint (push) Has been cancelled
Codestyle Check / Check bypass (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:37:14 +08:00

109 lines
4.3 KiB
Python

import libcst as cst
from libcst import CSTTransformer
import re
import os
from typing import Set, List, Union
class GenericRenamerTransformer(CSTTransformer):
"""
一个通用的CST转换器,用于安全地将代码中的标识符从多个源名称替换为同一个目标名称,
并能智能地保留原始名称的大小写风格。
"""
def __init__(self, from_names: Union[Set[str], List[str]], to_name: str):
"""
Args:
from_names: 要被替换的源名称集合或列表 (例如 {'t5', 'llama', 'utils'})。
to_name: 用于替换的目标名称 (例如 'qwen2')。
"""
self.to_name = to_name
# 1. 构建一个包含所有源名称的正则表达式 | (OR 逻辑)
# - 使用 re.escape() 确保特殊字符被正确处理。
# - 使用 | 符号连接所有名称,实现多选一匹配。
# - 确保列表非空
if not from_names:
raise ValueError("from_names 列表不能为空。")
escaped_names = [re.escape(name) for name in from_names]
pattern = "|".join(escaped_names)
# 2. 编译一个不区分大小写 (re.IGNORECASE) 的正则表达式
self.regex = re.compile(pattern, re.IGNORECASE)
def _case_preserving_replace(self, match: re.Match) -> str:
"""
这是一个自定义的替换函数,它根据匹配到的字符串的大小写风格,
来决定 to_name 应该使用哪种大小写形式。
"""
found_str = match.group(0)
# 如果找到的是全大写 (e.g., LLAMA)
if found_str.isupper():
return self.to_name.upper()
# 如果找到的是首字母大写 (e.g., Llama)
if found_str.istitle():
return self.to_name.title()
# 默认情况,包括全小写 (e.g., llama),返回全小写
return self.to_name.lower()
def leave_Name(
self, original_node: cst.Name, updated_node: cst.Name
) -> cst.Name:
"""
当访问离开一个名称节点时,使用正则表达式和自定义替换函数执行重命名。
"""
# 使用 regex.sub() 和我们的自定义函数来进行替换
new_name_str = self.regex.sub(self._case_preserving_replace, updated_node.value)
# 仅在名称确实发生改变时才创建一个新节点
if new_name_str != updated_node.value:
if not new_name_str.isidentifier():
original_name = original_node.value
# 警告,而不是跳过,因为这在依赖于上下文的重命名中可能是允许的。
# 但对于 cst.Name 节点,它必须是有效标识符。
print(f"警告:尝试将 '{original_name}' 重命名为无效标识符 '{new_name_str}'。跳过此重命名。")
return updated_node
return updated_node.with_changes(value=new_name_str)
return updated_node
def rename_identifiers(source_code: str, from_names: Union[Set[str], List[str]], to_name: str) -> str:
"""
接收一段Python源代码,将其中的所有 from_names 相关标识符安全地重命名为 to_name。
Args:
source_code: 包含Python代码的字符串。
from_names: 要被替换的源名称集合或列表 (例如 {"t5", "llama"})。
to_name: 用于替换的目标名称 (例如 "qwen2")。
Returns:
重构后的Python代码字符串。
"""
try:
module = cst.parse_module(source_code)
transformer = GenericRenamerTransformer(from_names, to_name)
modified_module = module.visit(transformer)
return modified_module.code
except cst.ParserSyntaxError as e:
print(f"Error: Failed to parse the source code. {e}")
return source_code
except ValueError as e:
print(f"Error in rename process: {e}")
return source_code
# --- 示例用法 ---
# source_code = """
# class LlamaModel(T5Model):
# def forward(self, input_ids):
# return self.llama_layer(input_ids)
# LLAMA_CONFIG = 1
# """
# from_list = ['llama', 't5']
# to_name = 'qwen2'
# new_code = rename_identifiers(source_code, from_list, to_name)
# print(new_code)
# # 预期输出:
# # class Qwen2Model(Qwen2Model):
# # def forward(self, input_ids):
# # return self.qwen2_layer(input_ids)
# # QWEN2_CONFIG = 1