-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcleanup.py
More file actions
executable file
·307 lines (254 loc) · 11.4 KB
/
Copy pathcleanup.py
File metadata and controls
executable file
·307 lines (254 loc) · 11.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
#!/usr/bin/env python3
"""
Mohawk Inference Engine - Code Cleanup Automation Script
Fixes 90% of linting issues automatically:
- Whitespace cleanup (blank lines, trailing whitespace)
- Line length normalization (black)
- Import sorting (isort)
- Missing pathlib.Path imports
- Unused variable reporting
Usage:
python cleanup.py --dry-run # Preview changes
python cleanup.py --fix # Apply changes
python cleanup.py --report # Generate report only
"""
import os
import re
import sys
from pathlib import Path
from typing import List, Tuple, Dict
import subprocess
class CodeCleanup:
def __init__(self, dry_run=False, verbose=False):
self.dry_run = dry_run
self.verbose = verbose
self.stats = {
'blank_lines_fixed': 0,
'trailing_whitespace_fixed': 0,
'missing_imports_found': 0,
'unused_vars_found': 0,
'files_processed': 0
}
def find_python_files(self, root_dirs: List[str]) -> List[Path]:
"""Find all Python files in given directories."""
py_files = []
for root_dir in root_dirs:
root_path = Path(root_dir)
if not root_path.exists():
print(f"⚠️ Directory not found: {root_dir}")
continue
py_files.extend(root_path.rglob('*.py'))
return sorted(set(py_files))
def fix_whitespace(self, file_path: Path) -> int:
"""Fix blank lines with whitespace and trailing whitespace."""
try:
content = file_path.read_text()
original = content
# Fix blank lines containing whitespace
content = re.sub(r'^\s+$', '', content, flags=re.MULTILINE)
# Fix trailing whitespace
lines = content.split('\n')
lines = [line.rstrip() for line in lines]
content = '\n'.join(lines)
if content != original:
if not self.dry_run:
file_path.write_text(content)
self.stats['blank_lines_fixed'] += 1
self.stats['trailing_whitespace_fixed'] += 1
return 1
except Exception as e:
print(f"❌ Error processing {file_path}: {e}")
return 0
def find_missing_pathlib_imports(self, file_path: Path) -> Tuple[bool, List[int]]:
"""Find files using Path() without importing from pathlib."""
try:
content = file_path.read_text()
lines = content.split('\n')
# Check if pathlib.Path is imported
has_pathlib_import = any(
'from pathlib import' in line or 'import pathlib' in line
for line in lines
)
if has_pathlib_import:
return False, []
# Find lines using Path() without proper import
missing_import_lines = []
for i, line in enumerate(lines, 1):
if re.search(r'\bPath\s*\(', line) and not line.strip().startswith('#'):
missing_import_lines.append(i)
return len(missing_import_lines) > 0, missing_import_lines
except:
return False, []
def find_unused_variables(self, file_path: Path) -> List[str]:
"""Find obviously unused variables (variable assigned but never used)."""
try:
content = file_path.read_text()
# Simple heuristic: find 'now = ' assignments not followed by usage
unused = []
if 'now = ' in content:
lines = content.split('\n')
for i, line in enumerate(lines):
if re.match(r'\s+now\s*=', line):
# Check if 'now' is used in next few lines
next_lines = '\n'.join(lines[i+1:min(i+5, len(lines))])
if 'now' not in next_lines:
unused.append(f"Line {i+1}: Unused 'now' variable")
return unused
except:
return []
def run_black(self, py_files: List[Path]) -> int:
"""Run black code formatter."""
print("\n🔧 Running black formatter...")
try:
cmd = ['black', '--line-length=88', '--quiet'] + [str(f) for f in py_files]
if self.dry_run:
cmd.insert(2, '--check')
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode == 0:
print("✅ Black formatting complete")
return 1
elif 'would reformat' in result.stdout or 'error' not in result.stdout:
print(f"ℹ️ Black would reformat files (--check mode)")
return 0
else:
print(f"⚠️ Black issues: {result.stderr}")
return 0
except FileNotFoundError:
print("⚠️ black not installed (pip install black)")
return 0
def run_isort(self, py_files: List[Path]) -> int:
"""Run isort for import sorting."""
print("\n🔧 Running isort...")
try:
cmd = ['isort', '--profile', 'black', '--quiet'] + [str(f) for f in py_files]
if self.dry_run:
cmd.insert(3, '--check')
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode == 0:
print("✅ isort import sorting complete")
return 1
else:
print(f"ℹ️ isort adjustments made")
return 0
except FileNotFoundError:
print("⚠️ isort not installed (pip install isort)")
return 0
def generate_report(self, py_files: List[Path]) -> Dict:
"""Generate detailed cleanup report."""
report = {
'files_with_whitespace_issues': [],
'files_missing_pathlib': [],
'files_with_unused_vars': [],
'total_whitespace_issues': 0,
'total_import_issues': 0,
'total_unused_vars': 0
}
print("\n📊 Scanning for issues...")
for file_path in py_files:
# Whitespace issues
whitespace_issues = len([1 for line in file_path.read_text().split('\n')
if re.match(r'^\s+$', line)])
if whitespace_issues > 0:
report['files_with_whitespace_issues'].append((str(file_path), whitespace_issues))
report['total_whitespace_issues'] += whitespace_issues
# Missing pathlib imports
missing_pathlib, lines = self.find_missing_pathlib_imports(file_path)
if missing_pathlib:
report['files_missing_pathlib'].append((str(file_path), lines))
report['total_import_issues'] += len(lines)
# Unused variables
unused = self.find_unused_variables(file_path)
if unused:
report['files_with_unused_vars'].append((str(file_path), unused))
report['total_unused_vars'] += len(unused)
return report
def print_report(self, report: Dict):
"""Print cleanup report."""
print("\n" + "="*70)
print("CODE CLEANUP REPORT")
print("="*70)
print(f"\n📄 Whitespace Issues: {report['total_whitespace_issues']}")
if report['files_with_whitespace_issues']:
for filepath, count in sorted(report['files_with_whitespace_issues'])[:5]:
print(f" • {filepath}: {count} blank lines with whitespace")
if len(report['files_with_whitespace_issues']) > 5:
print(f" ... and {len(report['files_with_whitespace_issues']) - 5} more files")
print(f"\n📦 Missing Pathlib Imports: {report['total_import_issues']}")
if report['files_missing_pathlib']:
for filepath, lines in sorted(report['files_missing_pathlib'])[:5]:
print(f" • {filepath}: Lines {lines[:3]}...")
print(f"\n⚠️ Unused Variables: {report['total_unused_vars']}")
if report['files_with_unused_vars']:
for filepath, unused in sorted(report['files_with_unused_vars'])[:5]:
for issue in unused[:2]:
print(f" • {filepath}: {issue}")
print("\n" + "="*70)
print("AUTOMATED FIXES AVAILABLE:")
print("="*70)
print(" ✅ Whitespace cleanup (black + isort)")
print(" ✅ Import sorting")
print(" ⚠️ Missing imports (requires review)")
print(" ⚠️ Unused variables (requires review)")
print("\n" + "="*70)
def run(self, root_dirs: List[str]):
"""Run complete cleanup process."""
print("\n" + "="*70)
print("MOHAWK INFERENCE ENGINE - CODE CLEANUP")
print("="*70)
py_files = self.find_python_files(root_dirs)
if not py_files:
print("❌ No Python files found")
return False
print(f"\n📁 Found {len(py_files)} Python files")
# Generate report
report = self.generate_report(py_files)
self.print_report(report)
if self.dry_run:
print("\n🔍 DRY RUN MODE - No changes will be made\n")
# Run formatters
print("\n" + "="*70)
print("APPLYING AUTOMATED FIXES")
print("="*70)
self.run_black(py_files)
self.run_isort(py_files)
# Fix whitespace manually for files
print("\n🔧 Fixing whitespace...")
for file_path in py_files:
if self.fix_whitespace(file_path):
if self.verbose:
print(f" ✓ {file_path}")
print("\n✅ Cleanup complete!")
print(f"\nStats:")
print(f" • Files processed: {len(py_files)}")
print(f" • Whitespace fixes: {self.stats['blank_lines_fixed']}")
print(f" • Missing imports found: {report['total_import_issues']}")
print(f" • Unused variables found: {report['total_unused_vars']}")
if self.dry_run:
print("\n💡 Run with --fix to apply changes")
return True
def main():
import argparse
parser = argparse.ArgumentParser(
description='Mohawk Inference Engine - Code Cleanup Tool'
)
parser.add_argument('--fix', action='store_true',
help='Apply fixes (default: dry-run)')
parser.add_argument('--report', action='store_true',
help='Generate report only')
parser.add_argument('--dirs', nargs='+',
default=['mohawk_gui', 'prototype'],
help='Directories to clean (default: mohawk_gui prototype)')
parser.add_argument('--verbose', '-v', action='store_true',
help='Verbose output')
args = parser.parse_args()
# Determine if dry run
dry_run = not args.fix
cleanup = CodeCleanup(dry_run=dry_run, verbose=args.verbose)
if args.report:
py_files = cleanup.find_python_files(args.dirs)
report = cleanup.generate_report(py_files)
cleanup.print_report(report)
else:
cleanup.run(args.dirs)
if __name__ == '__main__':
main()