fix: auto-fix code issues (cron)

- 修复重复导入/字段
- 修复异常处理
- 修复PEP8格式问题
- 修复语法错误(运算符空格问题)
- 修复类型注解格式
This commit is contained in:
AutoFix Bot
2026-03-02 06:09:49 +08:00
parent b83265e5fd
commit e23f1fec08
84 changed files with 9492 additions and 9491 deletions

View File

@@ -15,25 +15,25 @@ class CodeIssue:
line_no: int,
issue_type: str,
message: str,
severity: str = "info",
):
self.file_path = file_path
self.line_no = line_no
self.issue_type = issue_type
self.message = message
self.severity = severity # info, warning, error
self.fixed = False
severity: str = "info",
) -> None:
self.file_path = file_path
self.line_no = line_no
self.issue_type = issue_type
self.message = message
self.severity = severity # info, warning, error
self.fixed = False
def __repr__(self):
def __repr__(self) -> None:
return f"{self.severity.upper()}: {self.file_path}:{self.line_no} - {self.issue_type}: {self.message}"
class CodeReviewer:
def __init__(self, base_path: str):
self.base_path = Path(base_path)
self.issues: list[CodeIssue] = []
self.fixed_issues: list[CodeIssue] = []
self.manual_review_issues: list[CodeIssue] = []
def __init__(self, base_path: str) -> None:
self.base_path = Path(base_path)
self.issues: list[CodeIssue] = []
self.fixed_issues: list[CodeIssue] = []
self.manual_review_issues: list[CodeIssue] = []
def scan_all(self) -> None:
"""扫描所有 Python 文件"""
@@ -45,14 +45,14 @@ class CodeReviewer:
def scan_file(self, file_path: Path) -> None:
"""扫描单个文件"""
try:
with open(file_path, "r", encoding="utf-8") as f:
content = f.read()
lines = content.split("\n")
with open(file_path, "r", encoding = "utf-8") as f:
content = f.read()
lines = content.split("\n")
except Exception as e:
print(f"Error reading {file_path}: {e}")
return
rel_path = str(file_path.relative_to(self.base_path))
rel_path = str(file_path.relative_to(self.base_path))
# 1. 检查裸异常捕获
self._check_bare_exceptions(content, lines, rel_path)
@@ -92,7 +92,7 @@ class CodeReviewer:
# 跳过有注释说明的情况
if "# noqa" in line or "# intentional" in line.lower():
continue
issue = CodeIssue(
issue = CodeIssue(
file_path,
i,
"bare_exception",
@@ -105,17 +105,17 @@ class CodeReviewer:
self, content: str, lines: list[str], file_path: str
) -> None:
"""检查重复导入"""
imports = {}
imports = {}
for i, line in enumerate(lines, 1):
match = re.match(r"^(?:from\s+(\S+)\s+)?import\s+(.+)$", line.strip())
match = re.match(r"^(?:from\s+(\S+)\s+)?import\s+(.+)$", line.strip())
if match:
module = match.group(1) or ""
names = match.group(2).split(",")
module = match.group(1) or ""
names = match.group(2).split(", ")
for name in names:
name = name.strip().split()[0] # 处理 'as' 别名
key = f"{module}.{name}" if module else name
name = name.strip().split()[0] # 处理 'as' 别名
key = f"{module}.{name}" if module else name
if key in imports:
issue = CodeIssue(
issue = CodeIssue(
file_path,
i,
"duplicate_import",
@@ -123,7 +123,7 @@ class CodeReviewer:
"warning",
)
self.issues.append(issue)
imports[key] = i
imports[key] = i
def _check_pep8_issues(
self, content: str, lines: list[str], file_path: str
@@ -132,7 +132,7 @@ class CodeReviewer:
for i, line in enumerate(lines, 1):
# 行长度超过 120
if len(line) > 120:
issue = CodeIssue(
issue = CodeIssue(
file_path,
i,
"line_too_long",
@@ -143,7 +143,7 @@ class CodeReviewer:
# 行尾空格
if line.rstrip() != line:
issue = CodeIssue(
issue = CodeIssue(
file_path, i, "trailing_whitespace", "行尾有空格", "info"
)
self.issues.append(issue)
@@ -151,7 +151,7 @@ class CodeReviewer:
# 多余的空行
if i > 1 and line.strip() == "" and lines[i - 2].strip() == "":
if i < len(lines) and lines[i].strip() == "":
issue = CodeIssue(
issue = CodeIssue(
file_path, i, "extra_blank_line", "多余的空行", "info"
)
self.issues.append(issue)
@@ -161,23 +161,23 @@ class CodeReviewer:
) -> None:
"""检查未使用的导入"""
try:
tree = ast.parse(content)
tree = ast.parse(content)
except SyntaxError:
return
imported_names = {}
used_names = set()
imported_names = {}
used_names = set()
for node in ast.walk(tree):
if isinstance(node, ast.Import):
for alias in node.names:
name = alias.asname if alias.asname else alias.name
imported_names[name] = node.lineno
name = alias.asname if alias.asname else alias.name
imported_names[name] = node.lineno
elif isinstance(node, ast.ImportFrom):
for alias in node.names:
name = alias.asname if alias.asname else alias.name
name = alias.asname if alias.asname else alias.name
if name != "*":
imported_names[name] = node.lineno
imported_names[name] = node.lineno
elif isinstance(node, ast.Name):
used_names.add(node.id)
@@ -186,7 +186,7 @@ class CodeReviewer:
# 排除一些常见例外
if name in ["annotations", "TYPE_CHECKING"]:
continue
issue = CodeIssue(
issue = CodeIssue(
file_path, lineno, "unused_import", f"未使用的导入: {name}", "info"
)
self.issues.append(issue)
@@ -195,20 +195,20 @@ class CodeReviewer:
self, content: str, lines: list[str], file_path: str
) -> None:
"""检查混合字符串格式化"""
has_fstring = False
has_percent = False
has_format = False
has_fstring = False
has_percent = False
has_format = False
for i, line in enumerate(lines, 1):
if re.search(r'f["\']', line):
has_fstring = True
has_fstring = True
if re.search(r"%[sdfr]", line) and not re.search(r"\d+%", line):
has_percent = True
has_percent = True
if ".format(" in line:
has_format = True
has_format = True
if has_fstring and (has_percent or has_format):
issue = CodeIssue(
issue = CodeIssue(
file_path,
0,
"mixed_formatting",
@@ -222,25 +222,25 @@ class CodeReviewer:
) -> None:
"""检查魔法数字"""
# 常见的魔法数字模式
magic_patterns = [
(r"=\s*(\d{3,})\s*[^:]", "可能的魔法数字"),
(r"timeout\s*=\s*(\d+)", "timeout 魔法数字"),
(r"limit\s*=\s*(\d+)", "limit 魔法数字"),
(r"port\s*=\s*(\d+)", "port 魔法数字"),
magic_patterns = [
(r" = \s*(\d{3, })\s*[^:]", "可能的魔法数字"),
(r"timeout\s* = \s*(\d+)", "timeout 魔法数字"),
(r"limit\s* = \s*(\d+)", "limit 魔法数字"),
(r"port\s* = \s*(\d+)", "port 魔法数字"),
]
for i, line in enumerate(lines, 1):
# 跳过注释和字符串
code_part = line.split("#")[0]
code_part = line.split("#")[0]
if not code_part.strip():
continue
for pattern, msg in magic_patterns:
if re.search(pattern, code_part, re.IGNORECASE):
# 排除常见的合理数字
match = re.search(r"(\d{3,})", code_part)
match = re.search(r"(\d{3, })", code_part)
if match:
num = int(match.group(1))
num = int(match.group(1))
if num in [
200,
404,
@@ -257,7 +257,7 @@ class CodeReviewer:
8000,
]:
continue
issue = CodeIssue(
issue = CodeIssue(
file_path, i, "magic_number", f"{msg}: {num}", "info"
)
self.issues.append(issue)
@@ -272,7 +272,7 @@ class CodeReviewer:
r'execute\s*\(\s*f["\']', line
):
if "?" not in line and "%s" in line:
issue = CodeIssue(
issue = CodeIssue(
file_path,
i,
"sql_injection_risk",
@@ -287,7 +287,7 @@ class CodeReviewer:
"""检查 CORS 配置"""
for i, line in enumerate(lines, 1):
if "allow_origins" in line and '["*"]' in line:
issue = CodeIssue(
issue = CodeIssue(
file_path,
i,
"cors_wildcard",
@@ -303,7 +303,7 @@ class CodeReviewer:
for i, line in enumerate(lines, 1):
# 检查硬编码密钥
if re.search(
r'(password|secret|key|token)\s*=\s*["\'][^"\']+["\']',
r'(password|secret|key|token)\s* = \s*["\'][^"\']+["\']',
line,
re.IGNORECASE,
):
@@ -316,7 +316,7 @@ class CodeReviewer:
if not re.search(r'["\']\*+["\']', line) and not re.search(
r'["\']<[^"\']*>["\']', line
):
issue = CodeIssue(
issue = CodeIssue(
file_path,
i,
"hardcoded_secret",
@@ -328,62 +328,62 @@ class CodeReviewer:
def auto_fix(self) -> None:
"""自动修复问题"""
# 按文件分组问题
issues_by_file: dict[str, list[CodeIssue]] = {}
issues_by_file: dict[str, list[CodeIssue]] = {}
for issue in self.issues:
if issue.file_path not in issues_by_file:
issues_by_file[issue.file_path] = []
issues_by_file[issue.file_path] = []
issues_by_file[issue.file_path].append(issue)
for file_path, issues in issues_by_file.items():
full_path = self.base_path / file_path
full_path = self.base_path / file_path
if not full_path.exists():
continue
try:
with open(full_path, "r", encoding="utf-8") as f:
content = f.read()
lines = content.split("\n")
with open(full_path, "r", encoding = "utf-8") as f:
content = f.read()
lines = content.split("\n")
except Exception as e:
print(f"Error reading {full_path}: {e}")
continue
original_lines = lines.copy()
original_lines = lines.copy()
# 修复行尾空格
for issue in issues:
if issue.issue_type == "trailing_whitespace":
idx = issue.line_no - 1
idx = issue.line_no - 1
if 0 <= idx < len(lines):
lines[idx] = lines[idx].rstrip()
issue.fixed = True
lines[idx] = lines[idx].rstrip()
issue.fixed = True
# 修复裸异常
for issue in issues:
if issue.issue_type == "bare_exception":
idx = issue.line_no - 1
idx = issue.line_no - 1
if 0 <= idx < len(lines):
line = lines[idx]
# 将 except: 改为 except Exception:
line = lines[idx]
# 将 except Exception: 改为 except Exception:
if re.search(r"except\s*:\s*$", line.strip()):
lines[idx] = line.replace("except:", "except Exception:")
issue.fixed = True
lines[idx] = line.replace("except Exception:", "except Exception:")
issue.fixed = True
elif re.search(r"except\s+Exception\s*:\s*$", line.strip()):
# 已经是 Exception但可能需要更具体
pass
# 如果文件有修改,写回
if lines != original_lines:
with open(full_path, "w", encoding="utf-8") as f:
with open(full_path, "w", encoding = "utf-8") as f:
f.write("\n".join(lines))
print(f"Fixed issues in {file_path}")
# 移动到已修复列表
self.fixed_issues = [i for i in self.issues if i.fixed]
self.issues = [i for i in self.issues if not i.fixed]
self.fixed_issues = [i for i in self.issues if i.fixed]
self.issues = [i for i in self.issues if not i.fixed]
def generate_report(self) -> str:
"""生成审查报告"""
report = []
report = []
report.append("# InsightFlow 代码审查报告")
report.append(f"\n扫描路径: {self.base_path}")
report.append(f"扫描时间: {__import__('datetime').datetime.now().isoformat()}")
@@ -421,9 +421,9 @@ class CodeReviewer:
return "\n".join(report)
def main():
base_path = "/root/.openclaw/workspace/projects/insightflow/backend"
reviewer = CodeReviewer(base_path)
def main() -> None:
base_path = "/root/.openclaw/workspace/projects/insightflow/backend"
reviewer = CodeReviewer(base_path)
print("开始扫描代码...")
reviewer.scan_all()
@@ -437,9 +437,9 @@ def main():
print(f"\n已修复 {len(reviewer.fixed_issues)} 个问题")
# 生成报告
report = reviewer.generate_report()
report_path = Path(base_path).parent / "CODE_REVIEW_REPORT.md"
with open(report_path, "w", encoding="utf-8") as f:
report = reviewer.generate_report()
report_path = Path(base_path).parent / "CODE_REVIEW_REPORT.md"
with open(report_path, "w", encoding = "utf-8") as f:
f.write(report)
print(f"\n报告已保存到: {report_path}")