Skip to content

Commit d1c718a

Browse files
author
baiqing
committed
fix: resolve flake8 linting errors in code review script
- Remove unused 'os' import - Fix f-string syntax errors by converting static strings to regular strings - Ensure all code quality checks pass with pre-commit hooks Resolves pre-commit CI failures for flake8 F401 and F541 errors
1 parent 5911693 commit d1c718a

1 file changed

Lines changed: 157 additions & 71 deletions

File tree

code_review.py

Lines changed: 157 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -4,173 +4,259 @@
44
Comprehensive code quality analysis for the A.YLM project
55
"""
66

7-
import os
87
import ast
9-
import sys
108
import re
9+
import sys
1110
from pathlib import Path
1211

1312

1413
class CodeQualityReviewer:
15-
def __init__(self, root_dir='.'):
14+
def __init__(self, root_dir="."):
1615
self.root_dir = Path(root_dir)
1716
self.issues = []
1817

1918
def add_issue(self, file_path, line_num, category, severity, description):
20-
self.issues.append({
21-
'file': str(file_path),
22-
'line': line_num,
23-
'category': category,
24-
'severity': severity,
25-
'description': description
26-
})
19+
self.issues.append(
20+
{
21+
"file": str(file_path),
22+
"line": line_num,
23+
"category": category,
24+
"severity": severity,
25+
"description": description,
26+
}
27+
)
2728

2829
def check_python_files(self):
29-
print('Checking Python files...')
30-
for py_file in self.root_dir.rglob('*.py'):
31-
if 'ml-sharp' in str(py_file):
30+
print("Checking Python files...")
31+
for py_file in self.root_dir.rglob("*.py"):
32+
if "ml-sharp" in str(py_file):
3233
continue # Skip ml-sharp submodule
3334
self._check_single_python_file(py_file)
3435

3536
def _check_single_python_file(self, file_path):
3637
try:
37-
with open(file_path, 'r', encoding='utf-8') as f:
38+
with open(file_path, "r", encoding="utf-8") as f:
3839
content = f.read()
39-
lines = content.split('\n')
40+
lines = content.split("\n")
4041

4142
# Syntax check
4243
try:
4344
ast.parse(content)
4445
except SyntaxError as e:
45-
self.add_issue(file_path, e.lineno or 0, 'syntax', 'critical', f'Syntax error: {e.msg}')
46+
self.add_issue(
47+
file_path,
48+
e.lineno or 0,
49+
"syntax",
50+
"critical",
51+
f"Syntax error: {e.msg}",
52+
)
4653
return
4754

4855
# Check each line
4956
for i, line in enumerate(lines, 1):
5057
stripped = line.strip()
5158

5259
# Check trailing whitespace
53-
if line.rstrip() != line.rstrip('\n'):
54-
self.add_issue(file_path, i, 'formatting', 'minor', 'Trailing whitespace')
60+
if line.rstrip() != line.rstrip("\n"):
61+
self.add_issue(
62+
file_path, i, "formatting", "minor", "Trailing whitespace"
63+
)
5564

5665
# Check line length
5766
if len(line.rstrip()) > 100:
58-
self.add_issue(file_path, i, 'formatting', 'minor', f'Line too long ({len(line.rstrip())} characters)')
67+
self.add_issue(
68+
file_path,
69+
i,
70+
"formatting",
71+
"minor",
72+
f"Line too long ({len(line.rstrip())} characters)",
73+
)
5974

6075
# Check tabs
61-
if '\t' in line:
62-
self.add_issue(file_path, i, 'formatting', 'minor', 'Tab character found')
76+
if "\t" in line:
77+
self.add_issue(
78+
file_path, i, "formatting", "minor", "Tab character found"
79+
)
6380

6481
# Check print statements without parentheses (Python 2 style)
65-
if re.search(r'\bprint\s+[^(]', stripped):
66-
self.add_issue(file_path, i, 'compatibility', 'major', 'Print statement without parentheses')
82+
if re.search(r"\bprint\s+[^(]", stripped):
83+
self.add_issue(
84+
file_path,
85+
i,
86+
"compatibility",
87+
"major",
88+
"Print statement without parentheses",
89+
)
6790

6891
# Check bare except clauses
69-
if re.search(r'\bexcept\s*:', stripped) and not re.search(r'\bexcept\s+\w+', stripped):
70-
self.add_issue(file_path, i, 'error_handling', 'major', 'Bare except clause')
92+
if re.search(r"\bexcept\s*:", stripped) and not re.search(
93+
r"\bexcept\s+\w+", stripped
94+
):
95+
self.add_issue(
96+
file_path, i, "error_handling", "major", "Bare except clause"
97+
)
7198

7299
# Check TODO/FIXME comments
73-
if 'TODO' in line.upper() or 'FIXME' in line.upper():
74-
self.add_issue(file_path, i, 'maintenance', 'info', 'TODO/FIXME comment found')
100+
if "TODO" in line.upper() or "FIXME" in line.upper():
101+
self.add_issue(
102+
file_path, i, "maintenance", "info", "TODO/FIXME comment found"
103+
)
75104

76105
# Check unreachable code patterns
77-
if stripped.startswith('return ') or stripped.startswith('raise '):
106+
if stripped.startswith("return ") or stripped.startswith("raise "):
78107
# Check if there's code after return/raise in the same logical block
79108
indent_level = len(line) - len(line.lstrip())
80109
for j in range(i, min(i + 5, len(lines))):
81110
next_line = lines[j].strip()
82-
if next_line and not next_line.startswith('#'):
111+
if next_line and not next_line.startswith("#"):
83112
next_indent = len(lines[j]) - len(lines[j].lstrip())
84-
if next_indent > indent_level and not next_line.startswith(('except', 'finally', 'else:')):
85-
self.add_issue(file_path, j + 1, 'logic', 'major', 'Potentially unreachable code after return/raise')
113+
if next_indent > indent_level and not next_line.startswith(
114+
("except", "finally", "else:")
115+
):
116+
self.add_issue(
117+
file_path,
118+
j + 1,
119+
"logic",
120+
"major",
121+
"Potentially unreachable code after return/raise",
122+
)
86123
break
87124

88125
except Exception as e:
89-
self.add_issue(file_path, 0, 'file_error', 'major', f'Could not read file: {e}')
126+
self.add_issue(
127+
file_path, 0, "file_error", "major", f"Could not read file: {e}"
128+
)
90129

91130
def check_shell_scripts(self):
92-
print('Checking shell scripts...')
93-
for sh_file in self.root_dir.rglob('*.sh'):
131+
print("Checking shell scripts...")
132+
for sh_file in self.root_dir.rglob("*.sh"):
94133
self._check_single_shell_file(sh_file)
95134

96135
def _check_single_shell_file(self, file_path):
97136
try:
98-
with open(file_path, 'r', encoding='utf-8') as f:
137+
with open(file_path, "r", encoding="utf-8") as f:
99138
content = f.read()
100-
lines = content.split('\n')
139+
lines = content.split("\n")
101140

102141
for i, line in enumerate(lines, 1):
103142
stripped = line.strip()
104143

105144
# Check for deprecated command substitutions
106-
if re.search(r'`[^`]*`', stripped):
107-
self.add_issue(file_path, i, 'compatibility', 'minor', 'Deprecated backtick command substitution')
145+
if re.search(r"`[^`]*`", stripped):
146+
self.add_issue(
147+
file_path,
148+
i,
149+
"compatibility",
150+
"minor",
151+
"Deprecated backtick command substitution",
152+
)
108153

109154
# Check for unquoted variables
110155
if re.search(r'\\$\\w+[^"]', stripped):
111-
self.add_issue(file_path, i, 'robustness', 'minor', 'Unquoted variable')
156+
self.add_issue(
157+
file_path, i, "robustness", "minor", "Unquoted variable"
158+
)
112159

113160
# Check for set -e usage
114-
if 'set -e' in content and i == 1 and 'set -e' not in stripped:
115-
self.add_issue(file_path, 1, 'robustness', 'info', 'Consider adding set -e for error handling')
161+
if "set -e" in content and i == 1 and "set -e" not in stripped:
162+
self.add_issue(
163+
file_path,
164+
1,
165+
"robustness",
166+
"info",
167+
"Consider adding set -e for error handling",
168+
)
116169

117170
except Exception as e:
118-
self.add_issue(file_path, 0, 'file_error', 'major', f'Could not read file: {e}')
171+
self.add_issue(
172+
file_path, 0, "file_error", "major", f"Could not read file: {e}"
173+
)
119174

120175
def check_config_files(self):
121-
print('Checking configuration files...')
122-
config_files = ['requirements.txt', 'pyproject.toml', 'mypy.ini', '.pre-commit-config.yaml']
176+
print("Checking configuration files...")
177+
config_files = [
178+
"requirements.txt",
179+
"pyproject.toml",
180+
"mypy.ini",
181+
".pre-commit-config.yaml",
182+
]
123183

124184
for config_file in config_files:
125185
config_path = self.root_dir / config_file
126186
if config_path.exists():
127187
try:
128-
with open(config_path, 'r', encoding='utf-8') as f:
188+
with open(config_path, "r", encoding="utf-8") as f:
129189
content = f.read()
130190

131191
# Basic checks for common config issues
132-
if config_file == 'requirements.txt':
133-
lines = content.split('\n')
192+
if config_file == "requirements.txt":
193+
lines = content.split("\n")
134194
for i, line in enumerate(lines, 1):
135195
line = line.strip()
136-
if line and not line.startswith('#'):
196+
if line and not line.startswith("#"):
137197
# Check for unpinned versions
138-
if '>=' in line or '==' not in line:
139-
self.add_issue(config_path, i, 'security', 'minor', 'Unpinned dependency version')
140-
141-
elif config_file == 'pyproject.toml':
142-
if '[tool.black]' not in content:
143-
self.add_issue(config_path, 0, 'configuration', 'info', 'Consider adding Black configuration')
198+
if ">=" in line or "==" not in line:
199+
self.add_issue(
200+
config_path,
201+
i,
202+
"security",
203+
"minor",
204+
"Unpinned dependency version",
205+
)
206+
207+
elif config_file == "pyproject.toml":
208+
if "[tool.black]" not in content:
209+
self.add_issue(
210+
config_path,
211+
0,
212+
"configuration",
213+
"info",
214+
"Consider adding Black configuration",
215+
)
144216

145217
except Exception as e:
146-
self.add_issue(config_path, 0, 'file_error', 'major', f'Could not read config file: {e}')
218+
self.add_issue(
219+
config_path,
220+
0,
221+
"file_error",
222+
"major",
223+
f"Could not read config file: {e}",
224+
)
147225

148226
def generate_report(self):
149-
print(f'\n=== Code Quality Review Report ===')
150-
print(f'Total issues found: {len(self.issues)}')
227+
print("\n=== Code Quality Review Report ===")
228+
print(f"Total issues found: {len(self.issues)}")
151229

152230
# Group issues by severity
153231
severity_counts = {}
154232
category_counts = {}
155233

156234
for issue in self.issues:
157-
severity_counts[issue['severity']] = severity_counts.get(issue['severity'], 0) + 1
158-
category_counts[issue['category']] = category_counts.get(issue['category'], 0) + 1
159-
160-
print(f'\nIssues by severity:')
235+
severity_counts[issue["severity"]] = (
236+
severity_counts.get(issue["severity"], 0) + 1
237+
)
238+
category_counts[issue["category"]] = (
239+
category_counts.get(issue["category"], 0) + 1
240+
)
241+
242+
print("\nIssues by severity:")
161243
for severity, count in severity_counts.items():
162-
print(f' {severity}: {count}')
244+
print(f" {severity}: {count}")
163245

164-
print(f'\nIssues by category:')
246+
print("\nIssues by category:")
165247
for category, count in category_counts.items():
166-
print(f' {category}: {count}')
248+
print(f" {category}: {count}")
167249

168250
# Show critical and major issues first
169-
critical_major = [i for i in self.issues if i['severity'] in ['critical', 'major']]
251+
critical_major = [
252+
i for i in self.issues if i["severity"] in ["critical", "major"]
253+
]
170254
if critical_major:
171-
print(f'\n=== Critical/Major Issues ===')
255+
print("\n=== Critical/Major Issues ===")
172256
for issue in critical_major[:10]: # Show first 10
173-
print(f'{issue["file"]}:{issue["line"]} [{issue["severity"]}] {issue["description"]}')
257+
print(
258+
f'{issue["file"]}:{issue["line"]} [{issue["severity"]}] {issue["description"]}'
259+
)
174260

175261
return self.issues
176262

@@ -184,14 +270,14 @@ def main():
184270
issues = reviewer.generate_report()
185271

186272
# Exit with appropriate code
187-
critical_issues = [i for i in issues if i['severity'] == 'critical']
273+
critical_issues = [i for i in issues if i["severity"] == "critical"]
188274
if critical_issues:
189-
print(f'\nFound {len(critical_issues)} critical issues')
275+
print(f"\nFound {len(critical_issues)} critical issues")
190276
return 1
191277
else:
192-
print(f'\nNo critical issues found')
278+
print("\nNo critical issues found")
193279
return 0
194280

195281

196282
if __name__ == "__main__":
197-
sys.exit(main())
283+
sys.exit(main())

0 commit comments

Comments
 (0)