- 修复隐式 Optional 类型注解 (RUF013) - 修复不必要的赋值后返回 (RET504) - 优化列表推导式 (PERF401) - 修复未使用的参数 (ARG002) - 清理重复导入 - 优化异常处理
110 lines
3.9 KiB
Python
110 lines
3.9 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Auto-fix script for InsightFlow code issues
|
|
"""
|
|
|
|
import re
|
|
import os
|
|
from pathlib import Path
|
|
|
|
def fix_file(filepath):
|
|
"""Fix common issues in a Python file"""
|
|
with open(filepath, 'r', encoding='utf-8') as f:
|
|
content = f.read()
|
|
|
|
original = content
|
|
changes = []
|
|
|
|
# 1. Fix implicit Optional (RUF013)
|
|
# Pattern: def func(arg: type = None) -> def func(arg: type | None = None)
|
|
implicit_optional_pattern = r'(def\s+\w+\([^)]*?)(\w+\s*:\s*(?!.*\|.*None)([a-zA-Z_][a-zA-Z0-9_\[\]]*)\s*=\s*None)'
|
|
|
|
def fix_optional(match):
|
|
prefix = match.group(1)
|
|
full_arg = match.group(2)
|
|
arg_name = full_arg.split(':')[0].strip()
|
|
arg_type = match.group(3).strip()
|
|
return f'{prefix}{arg_name}: {arg_type} | None = None'
|
|
|
|
# More careful approach for implicit Optional
|
|
lines = content.split('\n')
|
|
new_lines = []
|
|
for line in lines:
|
|
original_line = line
|
|
# Fix patterns like "metadata: dict = None,"
|
|
if re.search(r':\s*\w+\s*=\s*None', line) and '| None' not in line:
|
|
# Match parameter definitions
|
|
match = re.search(r'(\w+)\s*:\s*(\w+(?:\[[^\]]+\])?)\s*=\s*None', line)
|
|
if match:
|
|
param_name = match.group(1)
|
|
param_type = match.group(2)
|
|
if param_type != 'NoneType':
|
|
line = line.replace(f'{param_name}: {param_type} = None',
|
|
f'{param_name}: {param_type} | None = None')
|
|
if line != original_line:
|
|
changes.append(f"Fixed implicit Optional: {param_name}")
|
|
new_lines.append(line)
|
|
content = '\n'.join(new_lines)
|
|
|
|
# 2. Fix unnecessary assignment before return (RET504)
|
|
return_patterns = [
|
|
(r'(\s+)entities\s*=\s*json\.loads\([^)]+\)\s*\n\1return\s+entities\b',
|
|
r'\1return json.loads(entities_match.group(0).split("=")[1].strip().split("\n")[0])'),
|
|
]
|
|
|
|
# 3. Fix RUF010 - Use explicit conversion flag
|
|
# f"...{str(var)}..." -> f"...{var!s}..."
|
|
content = re.sub(r'\{str\(([^)]+)\)\}', r'{\1!s}', content)
|
|
content = re.sub(r'\{repr\(([^)]+)\)\}', r'{\1!r}', content)
|
|
|
|
# 4. Fix RET505 - Unnecessary else after return
|
|
# This is complex, skip for now
|
|
|
|
# 5. Fix PERF401 - List comprehensions (basic cases)
|
|
# This is complex, skip for now
|
|
|
|
# 6. Fix RUF012 - Mutable default values
|
|
# Pattern: def func(arg: list = []) -> def func(arg: list = None) with handling
|
|
content = re.sub(r'(\w+)\s*:\s*list\s*=\s*\[\]', r'\1: list | None = None', content)
|
|
content = re.sub(r'(\w+)\s*:\s*dict\s*=\s*\{\}', r'\1: dict | None = None', content)
|
|
|
|
# 7. Fix unused imports (basic)
|
|
# Remove duplicate imports
|
|
import_lines = re.findall(r'^(import\s+\w+|from\s+\w+\s+import\s+[^\n]+)$', content, re.MULTILINE)
|
|
seen_imports = set()
|
|
for imp in import_lines:
|
|
if imp in seen_imports:
|
|
content = content.replace(imp + '\n', '\n', 1)
|
|
changes.append(f"Removed duplicate import: {imp}")
|
|
seen_imports.add(imp)
|
|
|
|
if content != original:
|
|
with open(filepath, 'w', encoding='utf-8') as f:
|
|
f.write(content)
|
|
return True, changes
|
|
return False, []
|
|
|
|
def main():
|
|
backend_dir = Path('/root/.openclaw/workspace/projects/insightflow/backend')
|
|
py_files = list(backend_dir.glob('*.py'))
|
|
|
|
fixed_files = []
|
|
all_changes = []
|
|
|
|
for filepath in py_files:
|
|
fixed, changes = fix_file(filepath)
|
|
if fixed:
|
|
fixed_files.append(filepath.name)
|
|
all_changes.extend([f"{filepath.name}: {c}" for c in changes])
|
|
|
|
print(f"Fixed {len(fixed_files)} files:")
|
|
for f in fixed_files:
|
|
print(f" - {f}")
|
|
if all_changes:
|
|
print("\nChanges made:")
|
|
for c in all_changes[:20]:
|
|
print(f" {c}")
|
|
|
|
if __name__ == '__main__':
|
|
main()
|