bug-be-gone 1.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bug_be_gone-1.0.1.dist-info/METADATA +216 -0
- bug_be_gone-1.0.1.dist-info/RECORD +7 -0
- bug_be_gone-1.0.1.dist-info/WHEEL +5 -0
- bug_be_gone-1.0.1.dist-info/entry_points.txt +3 -0
- bug_be_gone-1.0.1.dist-info/licenses/LICENSE +69 -0
- bug_be_gone-1.0.1.dist-info/top_level.txt +1 -0
- bug_be_gone.py +1473 -0
bug_be_gone.py
ADDED
|
@@ -0,0 +1,1473 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
UNIVERSAL DEBUGGER MERGED - The Complete Python Error Annihilator
|
|
4
|
+
Combines all features from both debugger implementations into one ultimate tool.
|
|
5
|
+
|
|
6
|
+
MERGED FEATURES:
|
|
7
|
+
- Smart return value detection based on context (from v1)
|
|
8
|
+
- AST-based code parsing for intelligent fixes (from ultimate)
|
|
9
|
+
- Comprehensive error database with pattern matching (both versions)
|
|
10
|
+
- Multi-line block wrapping for control structures (both versions)
|
|
11
|
+
- Type error detection and fixing with mypy integration (from ultimate)
|
|
12
|
+
- Deployment validation and auto-fix (from ultimate)
|
|
13
|
+
- Error prediction before they occur (from ultimate)
|
|
14
|
+
- Automatic dependency resolution (from ultimate)
|
|
15
|
+
- Performance bottleneck fixing (from ultimate)
|
|
16
|
+
- Smart conversion strategies for all types (from ultimate)
|
|
17
|
+
- Comprehensive ValueError and TypeError handling (both versions)
|
|
18
|
+
|
|
19
|
+
Usage:
|
|
20
|
+
python universal_debugger_merged.py your_script.py # Fix runtime errors
|
|
21
|
+
python universal_debugger_merged.py --types your_script.py # Fix type errors
|
|
22
|
+
python universal_debugger_merged.py --deploy # Validate deployment
|
|
23
|
+
python universal_debugger_merged.py --all your_script.py # Fix everything
|
|
24
|
+
python universal_debugger_merged.py --predict your_script.py # Predict future errors
|
|
25
|
+
python universal_debugger_merged.py --ultimate your_script.py # ACTIVATE EVERYTHING
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
import sys
|
|
29
|
+
import os
|
|
30
|
+
import re
|
|
31
|
+
import subprocess
|
|
32
|
+
import shutil
|
|
33
|
+
from pathlib import Path
|
|
34
|
+
from typing import Optional, List, Dict, Tuple, Any, Union
|
|
35
|
+
import ast
|
|
36
|
+
import json
|
|
37
|
+
import traceback
|
|
38
|
+
from datetime import datetime
|
|
39
|
+
import hashlib
|
|
40
|
+
|
|
41
|
+
# ============================================================================
|
|
42
|
+
# CORE UTILITY FUNCTIONS
|
|
43
|
+
# ============================================================================
|
|
44
|
+
|
|
45
|
+
def get_indent(line):
|
|
46
|
+
"""Extract indentation from line."""
|
|
47
|
+
return ' ' * (len(line) - len(line.lstrip()))
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def smart_return_value(line, error_type=''):
|
|
51
|
+
"""Smart return value detection based on context from v1."""
|
|
52
|
+
line_lower = line.lower()
|
|
53
|
+
|
|
54
|
+
# File operations return empty string
|
|
55
|
+
if any(x in line_lower for x in ['read', '.txt', '.csv', '.json', 'file', 'open']):
|
|
56
|
+
return '""'
|
|
57
|
+
|
|
58
|
+
# List operations return empty list
|
|
59
|
+
if any(x in line_lower for x in ['.append', '.extend', '[', 'list']):
|
|
60
|
+
return '[]'
|
|
61
|
+
|
|
62
|
+
# Dict operations return empty dict
|
|
63
|
+
if any(x in line_lower for x in ['.update', '.get', '.keys', '.items', 'dict', '{']):
|
|
64
|
+
return '{}'
|
|
65
|
+
|
|
66
|
+
# Numeric operations return 0
|
|
67
|
+
if any(x in line_lower for x in ['int(', 'float(', 'sum', 'len', 'count']):
|
|
68
|
+
return '0'
|
|
69
|
+
|
|
70
|
+
# String operations return empty string
|
|
71
|
+
if any(x in line_lower for x in ['str(', '.format', '.join', 'print']):
|
|
72
|
+
return '""'
|
|
73
|
+
|
|
74
|
+
# Boolean operations return False
|
|
75
|
+
if any(x in line_lower for x in ['bool(', 'is', '==', '!=', '>', '<']):
|
|
76
|
+
return 'False'
|
|
77
|
+
|
|
78
|
+
# Default based on error type
|
|
79
|
+
if 'Attribute' in error_type:
|
|
80
|
+
return 'None'
|
|
81
|
+
|
|
82
|
+
return '{}'
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def wrap_in_try_except(line, exception_type, indent_level=0, custom_except=None):
|
|
86
|
+
"""Wrap line in try/except block with smart return value."""
|
|
87
|
+
base_indent = ' ' * indent_level
|
|
88
|
+
inner_indent = ' ' * (indent_level + 4)
|
|
89
|
+
|
|
90
|
+
# Use smart return value from v1
|
|
91
|
+
return_value = smart_return_value(line, exception_type)
|
|
92
|
+
|
|
93
|
+
if custom_except:
|
|
94
|
+
return f"{base_indent}try:\n{inner_indent}{line.strip()}\n{custom_except}\n"
|
|
95
|
+
else:
|
|
96
|
+
return f"{base_indent}try:\n{inner_indent}{line.strip()}\n{base_indent}except {exception_type}:\n{inner_indent}return {return_value}\n"
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def get_indented_block(lines, start_idx):
|
|
100
|
+
"""Get all lines in an indented block starting from start_idx."""
|
|
101
|
+
if start_idx >= len(lines):
|
|
102
|
+
return ([], 0)
|
|
103
|
+
|
|
104
|
+
base_indent = len(lines[start_idx]) - len(lines[start_idx].lstrip())
|
|
105
|
+
block_lines = [lines[start_idx].rstrip()]
|
|
106
|
+
|
|
107
|
+
# Read subsequent lines that are more indented
|
|
108
|
+
idx = start_idx + 1
|
|
109
|
+
while idx < len(lines):
|
|
110
|
+
line = lines[idx]
|
|
111
|
+
if line.strip() == '':
|
|
112
|
+
block_lines.append('')
|
|
113
|
+
idx += 1
|
|
114
|
+
continue
|
|
115
|
+
|
|
116
|
+
line_indent = len(line) - len(line.lstrip())
|
|
117
|
+
if line_indent <= base_indent:
|
|
118
|
+
break
|
|
119
|
+
|
|
120
|
+
block_lines.append(line.rstrip())
|
|
121
|
+
idx += 1
|
|
122
|
+
|
|
123
|
+
return (block_lines, base_indent)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def wrap_block_in_try_except(block_lines, base_indent, exception_type):
|
|
127
|
+
"""Wrap a multi-line block in try/except with smart return value."""
|
|
128
|
+
spaces = ' ' * base_indent
|
|
129
|
+
inner_spaces = ' ' * (base_indent + 4)
|
|
130
|
+
|
|
131
|
+
# Smart return value from v1 - check the block content
|
|
132
|
+
block_text = '\n'.join(block_lines).lower()
|
|
133
|
+
return_value = smart_return_value(block_text, exception_type)
|
|
134
|
+
|
|
135
|
+
fixed_lines = [f"{spaces}try:"]
|
|
136
|
+
for block_line in block_lines:
|
|
137
|
+
if block_line.strip():
|
|
138
|
+
# Preserve relative indentation within the block
|
|
139
|
+
line_indent = len(block_line) - len(block_line.lstrip())
|
|
140
|
+
extra_indent = line_indent - base_indent
|
|
141
|
+
fixed_lines.append(f"{inner_spaces}{' ' * extra_indent}{block_line.lstrip()}")
|
|
142
|
+
else:
|
|
143
|
+
fixed_lines.append('')
|
|
144
|
+
fixed_lines.append(f"{spaces}except {exception_type}:")
|
|
145
|
+
fixed_lines.append(f"{inner_spaces}return {return_value}")
|
|
146
|
+
|
|
147
|
+
return '\n'.join(fixed_lines) + '\n'
|
|
148
|
+
|
|
149
|
+
# ============================================================================
|
|
150
|
+
# AST-BASED INTELLIGENT PARSING (from ultimate)
|
|
151
|
+
# ============================================================================
|
|
152
|
+
|
|
153
|
+
def try_parse_python_line(line):
|
|
154
|
+
"""Safely parse a line of Python code using AST."""
|
|
155
|
+
try:
|
|
156
|
+
# Try to parse as expression
|
|
157
|
+
return ast.parse(line.strip(), mode='eval')
|
|
158
|
+
except:
|
|
159
|
+
try:
|
|
160
|
+
# Try to parse as statement
|
|
161
|
+
return ast.parse(line.strip(), mode='exec')
|
|
162
|
+
except:
|
|
163
|
+
return None
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def extract_function_call_args(line):
|
|
167
|
+
"""Extract function name and arguments from a function call."""
|
|
168
|
+
tree = try_parse_python_line(line)
|
|
169
|
+
if not tree:
|
|
170
|
+
return None, []
|
|
171
|
+
|
|
172
|
+
# Find Call nodes
|
|
173
|
+
for node in ast.walk(tree):
|
|
174
|
+
if isinstance(node, ast.Call):
|
|
175
|
+
# Get function name
|
|
176
|
+
func_name = None
|
|
177
|
+
if isinstance(node.func, ast.Name):
|
|
178
|
+
func_name = node.func.id
|
|
179
|
+
elif isinstance(node.func, ast.Attribute):
|
|
180
|
+
func_name = node.func.attr
|
|
181
|
+
|
|
182
|
+
# Get argument names/values
|
|
183
|
+
args = []
|
|
184
|
+
for arg in node.args:
|
|
185
|
+
if isinstance(arg, ast.Name):
|
|
186
|
+
args.append(arg.id)
|
|
187
|
+
elif isinstance(arg, ast.Constant):
|
|
188
|
+
args.append(repr(arg.value))
|
|
189
|
+
|
|
190
|
+
return func_name, args
|
|
191
|
+
|
|
192
|
+
return None, []
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def apply_type_conversion(line, indent, arg_position, expected_type, got_type):
|
|
196
|
+
"""Apply intelligent type conversion based on type mismatch."""
|
|
197
|
+
|
|
198
|
+
# Parse the line to understand structure
|
|
199
|
+
func_name, args = extract_function_call_args(line)
|
|
200
|
+
|
|
201
|
+
if not func_name or arg_position >= len(args):
|
|
202
|
+
return None
|
|
203
|
+
|
|
204
|
+
arg_name = args[arg_position]
|
|
205
|
+
|
|
206
|
+
# Comprehensive type conversion strategies from ultimate
|
|
207
|
+
conversions = {
|
|
208
|
+
# String conversions
|
|
209
|
+
('UserString', 'str'): f'{arg_name}.data',
|
|
210
|
+
('int', 'str'): f'str({arg_name})',
|
|
211
|
+
('float', 'str'): f'str({arg_name})',
|
|
212
|
+
('bool', 'str'): f'str({arg_name})',
|
|
213
|
+
('list', 'str'): f'str({arg_name})',
|
|
214
|
+
('dict', 'str'): f'json.dumps({arg_name})',
|
|
215
|
+
('tuple', 'str'): f'str({arg_name})',
|
|
216
|
+
('set', 'str'): f'str({arg_name})',
|
|
217
|
+
('bytes', 'str'): f'{arg_name}.decode("utf-8", errors="ignore")',
|
|
218
|
+
('bytearray', 'str'): f'{arg_name}.decode("utf-8", errors="ignore")',
|
|
219
|
+
|
|
220
|
+
# Numeric conversions
|
|
221
|
+
('str', 'int'): f'int({arg_name}) if {arg_name}.isdigit() else 0',
|
|
222
|
+
('float', 'int'): f'int({arg_name})',
|
|
223
|
+
('bool', 'int'): f'int({arg_name})',
|
|
224
|
+
('str', 'float'): f'float({arg_name}) if {arg_name}.replace(".", "").replace("-", "").isdigit() else 0.0',
|
|
225
|
+
('int', 'float'): f'float({arg_name})',
|
|
226
|
+
('str', 'bool'): f'bool({arg_name})',
|
|
227
|
+
('Decimal', 'float'): f'float({arg_name})',
|
|
228
|
+
('Fraction', 'float'): f'float({arg_name})',
|
|
229
|
+
|
|
230
|
+
# Bytes conversions
|
|
231
|
+
('str', 'bytes'): f'{arg_name}.encode("utf-8", errors="ignore")',
|
|
232
|
+
('bytearray', 'bytes'): f'bytes({arg_name})',
|
|
233
|
+
|
|
234
|
+
# Container conversions
|
|
235
|
+
('str', 'list'): f'list({arg_name})',
|
|
236
|
+
('tuple', 'list'): f'list({arg_name})',
|
|
237
|
+
('set', 'list'): f'list({arg_name})',
|
|
238
|
+
('dict', 'list'): f'list({arg_name}.items())',
|
|
239
|
+
('range', 'list'): f'list({arg_name})',
|
|
240
|
+
('generator', 'list'): f'list({arg_name})',
|
|
241
|
+
('map', 'list'): f'list({arg_name})',
|
|
242
|
+
('filter', 'list'): f'list({arg_name})',
|
|
243
|
+
('zip', 'list'): f'list({arg_name})',
|
|
244
|
+
|
|
245
|
+
('list', 'tuple'): f'tuple({arg_name})',
|
|
246
|
+
('set', 'tuple'): f'tuple({arg_name})',
|
|
247
|
+
('list', 'set'): f'set({arg_name})',
|
|
248
|
+
('tuple', 'set'): f'set({arg_name})',
|
|
249
|
+
|
|
250
|
+
# None handling
|
|
251
|
+
('NoneType', 'str'): f'{arg_name} or ""',
|
|
252
|
+
('NoneType', 'int'): f'{arg_name} or 0',
|
|
253
|
+
('NoneType', 'float'): f'{arg_name} or 0.0',
|
|
254
|
+
('NoneType', 'list'): f'{arg_name} or []',
|
|
255
|
+
('NoneType', 'dict'): f'{arg_name} or {{}}',
|
|
256
|
+
('NoneType', 'bool'): f'bool({arg_name})',
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
# Try to find a conversion
|
|
260
|
+
conversion_key = (got_type, expected_type)
|
|
261
|
+
if conversion_key in conversions:
|
|
262
|
+
conversion = conversions[conversion_key]
|
|
263
|
+
# Replace the argument in the line
|
|
264
|
+
pattern = re.escape(arg_name)
|
|
265
|
+
fixed_line = re.sub(pattern, conversion, line, count=1)
|
|
266
|
+
return fixed_line
|
|
267
|
+
|
|
268
|
+
# Fallback: wrap in str() for most cases
|
|
269
|
+
if expected_type == 'str':
|
|
270
|
+
pattern = re.escape(arg_name)
|
|
271
|
+
fixed_line = re.sub(pattern, f'str({arg_name})', line, count=1)
|
|
272
|
+
return fixed_line
|
|
273
|
+
|
|
274
|
+
return None
|
|
275
|
+
|
|
276
|
+
# ============================================================================
|
|
277
|
+
# ERROR FIXING FUNCTIONS (Combined from both versions)
|
|
278
|
+
# ============================================================================
|
|
279
|
+
|
|
280
|
+
def _fix_name_error(line, indent, error_msg):
|
|
281
|
+
"""Fix NameError by initializing undefined variable with smart type detection from v1."""
|
|
282
|
+
pattern = r"name '(\w+)' is not defined"
|
|
283
|
+
match = re.search(pattern, error_msg)
|
|
284
|
+
if match:
|
|
285
|
+
var_name = match.group(1)
|
|
286
|
+
|
|
287
|
+
# Smart type detection from v1
|
|
288
|
+
if '.append' in line or '.extend' in line:
|
|
289
|
+
return f"{indent}{var_name} = [] # Initialize as list\n{line}"
|
|
290
|
+
elif '.update' in line or '.get' in line or '.keys' in line or '.items' in line:
|
|
291
|
+
return f"{indent}{var_name} = {{}} # Initialize as dict\n{line}"
|
|
292
|
+
elif '[' in line and ']' in line and var_name in line:
|
|
293
|
+
# Check if it's being indexed (dict/list access)
|
|
294
|
+
if f"{var_name}[" in line:
|
|
295
|
+
return f"{indent}{var_name} = {{}} # Initialize as dict\n{line}"
|
|
296
|
+
elif '+' in line and ('"' in line or "'" in line):
|
|
297
|
+
return f"{indent}{var_name} = '' # Initialize as string\n{line}"
|
|
298
|
+
elif 'int(' in line or 'float(' in line or any(op in line for op in ['+', '-', '*', '/']):
|
|
299
|
+
return f"{indent}{var_name} = 0 # Initialize as number\n{line}"
|
|
300
|
+
else:
|
|
301
|
+
return f"{indent}{var_name} = None # Initialize variable\n{line}"
|
|
302
|
+
return line
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def _fix_import_error(line, indent, error_msg):
|
|
306
|
+
"""Fix ImportError by wrapping in try/except with install suggestion."""
|
|
307
|
+
pattern = r"No module named '([^']+)'"
|
|
308
|
+
match = re.search(pattern, error_msg)
|
|
309
|
+
if match:
|
|
310
|
+
module_name = match.group(1)
|
|
311
|
+
# Map common module name variations to pip packages
|
|
312
|
+
pip_packages = {
|
|
313
|
+
'cv2': 'opencv-python',
|
|
314
|
+
'sklearn': 'scikit-learn',
|
|
315
|
+
'PIL': 'pillow',
|
|
316
|
+
'yaml': 'pyyaml',
|
|
317
|
+
'dotenv': 'python-dotenv',
|
|
318
|
+
'bs4': 'beautifulsoup4',
|
|
319
|
+
'OpenSSL': 'pyopenssl',
|
|
320
|
+
'Crypto': 'pycryptodome',
|
|
321
|
+
}
|
|
322
|
+
pip_name = pip_packages.get(module_name.split('.')[0], module_name)
|
|
323
|
+
|
|
324
|
+
return (f"{indent}try:\n"
|
|
325
|
+
f"{indent} {line.strip()}\n"
|
|
326
|
+
f"{indent}except (ImportError, ModuleNotFoundError):\n"
|
|
327
|
+
f"{indent} pass # Run: pip install {pip_name}\n")
|
|
328
|
+
return line
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def _fix_unbound_local_error(line, indent, error_msg):
|
|
332
|
+
"""Fix UnboundLocalError by initializing variable."""
|
|
333
|
+
pattern = r"local variable '(\w+)' referenced"
|
|
334
|
+
match = re.search(pattern, error_msg)
|
|
335
|
+
if match:
|
|
336
|
+
var_name = match.group(1)
|
|
337
|
+
# Use smart type detection
|
|
338
|
+
if any(x in line for x in ['append', 'extend', '[']):
|
|
339
|
+
init_value = '[]'
|
|
340
|
+
elif any(x in line for x in ['update', 'get', 'keys', '{']):
|
|
341
|
+
init_value = '{}'
|
|
342
|
+
elif any(x in line for x in ['int(', 'float(', '+', '-', '*', '/']):
|
|
343
|
+
init_value = '0'
|
|
344
|
+
else:
|
|
345
|
+
init_value = 'None'
|
|
346
|
+
|
|
347
|
+
return f"{indent}{var_name} = {init_value} # Initialize\n{line}"
|
|
348
|
+
return line
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def parse_value_error_message(error_msg):
|
|
352
|
+
"""Extract information from ValueError messages."""
|
|
353
|
+
patterns = {
|
|
354
|
+
'invalid_literal': r"invalid literal for (\w+)\(\) with base (\d+): '([^']+)'",
|
|
355
|
+
'not_enough_values': r"not enough values to unpack \(expected (\d+), got (\d+)\)",
|
|
356
|
+
'too_many_values': r"too many values to unpack \(expected (\d+)(?:, got (\d+))?\)",
|
|
357
|
+
'empty_sequence': r"(max|min)\(\) (?:arg|iterable argument) is (?:an )?empty",
|
|
358
|
+
'invalid_format': r"Unknown format code '(.+)' for",
|
|
359
|
+
'invalid_operation': r"invalid operation",
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
for pattern_name, pattern in patterns.items():
|
|
363
|
+
match = re.search(pattern, error_msg)
|
|
364
|
+
if match:
|
|
365
|
+
return pattern_name, match.groups()
|
|
366
|
+
|
|
367
|
+
return None, None
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
def _fix_value_error_smart(line, indent, error_msg):
|
|
371
|
+
"""Intelligently fix ValueError by understanding the context."""
|
|
372
|
+
|
|
373
|
+
pattern_type, groups = parse_value_error_message(error_msg)
|
|
374
|
+
|
|
375
|
+
if pattern_type == 'invalid_literal':
|
|
376
|
+
# E.g., "invalid literal for int() with base 10: 'abc'"
|
|
377
|
+
func_name, base, invalid_value = groups
|
|
378
|
+
|
|
379
|
+
# Wrap int/float conversion in try/except with default
|
|
380
|
+
if func_name in ('int', 'float'):
|
|
381
|
+
return (f"{indent}try:\n"
|
|
382
|
+
f"{indent} {line.strip()}\n"
|
|
383
|
+
f"{indent}except ValueError:\n"
|
|
384
|
+
f"{indent} {line.split('=')[0].strip()} = 0 # Default for invalid {func_name}\n")
|
|
385
|
+
|
|
386
|
+
elif pattern_type == 'too_many_values':
|
|
387
|
+
# E.g., "too many values to unpack (expected 2)"
|
|
388
|
+
expected_count = int(groups[0])
|
|
389
|
+
|
|
390
|
+
# Find the assignment: x, y = something
|
|
391
|
+
unpack_pattern = r'([a-zA-Z_]\w*(?:\s*,\s*[a-zA-Z_]\w*)*)\s*=\s*(.+)'
|
|
392
|
+
match = re.match(unpack_pattern, line.strip())
|
|
393
|
+
|
|
394
|
+
if match:
|
|
395
|
+
var_names = [v.strip() for v in match.group(1).split(',')]
|
|
396
|
+
source = match.group(2).strip()
|
|
397
|
+
|
|
398
|
+
# Add slice to limit values: x, y = source[:2]
|
|
399
|
+
fixed_line = f"{indent}{', '.join(var_names)} = {source}[:{expected_count}]\n"
|
|
400
|
+
return fixed_line
|
|
401
|
+
|
|
402
|
+
elif pattern_type == 'not_enough_values':
|
|
403
|
+
# E.g., "not enough values to unpack (expected 3, got 1)"
|
|
404
|
+
expected, got = int(groups[0]), int(groups[1])
|
|
405
|
+
|
|
406
|
+
# Find the assignment
|
|
407
|
+
unpack_pattern = r'([a-zA-Z_]\w*(?:\s*,\s*[a-zA-Z_]\w*)*)\s*=\s*(.+)'
|
|
408
|
+
match = re.match(unpack_pattern, line.strip())
|
|
409
|
+
|
|
410
|
+
if match:
|
|
411
|
+
var_names = [v.strip() for v in match.group(1).split(',')]
|
|
412
|
+
source = match.group(2).strip()
|
|
413
|
+
|
|
414
|
+
# Pad with None: x, y, z = (source + [None] * 3)[:3]
|
|
415
|
+
needed_padding = expected - got
|
|
416
|
+
fixed_line = f"{indent}{', '.join(var_names)} = (list({source}) + [None] * {expected})[:{expected}]\n"
|
|
417
|
+
return fixed_line
|
|
418
|
+
|
|
419
|
+
elif pattern_type == 'empty_sequence':
|
|
420
|
+
# Max/min on empty sequence
|
|
421
|
+
if 'max' in line:
|
|
422
|
+
return (f"{indent}try:\n"
|
|
423
|
+
f"{indent} {line.strip()}\n"
|
|
424
|
+
f"{indent}except ValueError:\n"
|
|
425
|
+
f"{indent} result = 0 # Default for empty sequence\n")
|
|
426
|
+
elif 'min' in line:
|
|
427
|
+
return (f"{indent}try:\n"
|
|
428
|
+
f"{indent} {line.strip()}\n"
|
|
429
|
+
f"{indent}except ValueError:\n"
|
|
430
|
+
f"{indent} result = float('inf') # Default for empty sequence\n")
|
|
431
|
+
|
|
432
|
+
# General fallback: wrap in try/except
|
|
433
|
+
return wrap_in_try_except(line, 'ValueError', len(indent))
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
def _fix_type_error_smart(line, indent, error_msg):
|
|
437
|
+
"""Smart TypeError fixing from ultimate with enhanced conversions."""
|
|
438
|
+
|
|
439
|
+
# Pattern for "X takes Y arguments but Z were given"
|
|
440
|
+
args_pattern = r"(\w+)\(\) takes (?:exactly )?(\d+) (?:positional )?arguments? but (\d+) (?:were|was) given"
|
|
441
|
+
match = re.search(args_pattern, error_msg)
|
|
442
|
+
|
|
443
|
+
if match:
|
|
444
|
+
func_name, expected, given = match.groups()
|
|
445
|
+
expected, given = int(expected), int(given)
|
|
446
|
+
|
|
447
|
+
# Find function call in line
|
|
448
|
+
call_pattern = rf'{func_name}\s*\((.*?)\)'
|
|
449
|
+
call_match = re.search(call_pattern, line)
|
|
450
|
+
|
|
451
|
+
if call_match and given > expected:
|
|
452
|
+
args = call_match.group(1)
|
|
453
|
+
# Limit arguments
|
|
454
|
+
args_list = [a.strip() for a in args.split(',')]
|
|
455
|
+
limited_args = args_list[:expected]
|
|
456
|
+
fixed_call = f"{func_name}({', '.join(limited_args)})"
|
|
457
|
+
return re.sub(call_pattern, fixed_call, line)
|
|
458
|
+
|
|
459
|
+
# Pattern for type mismatch "argument must be X, not Y"
|
|
460
|
+
type_pattern = r"argument (\d+)? ?(?:must be|should be) (\w+), not (\w+)"
|
|
461
|
+
match = re.search(type_pattern, error_msg)
|
|
462
|
+
|
|
463
|
+
if match:
|
|
464
|
+
arg_pos, expected_type, got_type = match.groups()
|
|
465
|
+
arg_position = int(arg_pos) - 1 if arg_pos else 0
|
|
466
|
+
|
|
467
|
+
# Try smart type conversion
|
|
468
|
+
fixed = apply_type_conversion(line, indent, arg_position, expected_type, got_type)
|
|
469
|
+
if fixed:
|
|
470
|
+
return fixed
|
|
471
|
+
|
|
472
|
+
# Pattern for unsupported operand types
|
|
473
|
+
operand_pattern = r"unsupported operand type\(s\) for (\S+): '(\w+)' and '(\w+)'"
|
|
474
|
+
match = re.search(operand_pattern, error_msg)
|
|
475
|
+
|
|
476
|
+
if match:
|
|
477
|
+
operator, type1, type2 = match.groups()
|
|
478
|
+
# Wrap operation in try/except with appropriate conversion
|
|
479
|
+
return (f"{indent}try:\n"
|
|
480
|
+
f"{indent} {line.strip()}\n"
|
|
481
|
+
f"{indent}except TypeError:\n"
|
|
482
|
+
f"{indent} result = 0 # Type mismatch in operation\n")
|
|
483
|
+
|
|
484
|
+
# General fallback
|
|
485
|
+
return wrap_in_try_except(line, 'TypeError', len(indent))
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
def _fix_attribute_error(line, indent, error_msg):
|
|
489
|
+
"""Fix AttributeError with smart suggestions."""
|
|
490
|
+
|
|
491
|
+
# Pattern for 'X' object has no attribute 'Y'
|
|
492
|
+
pattern = r"'(\w+)' object has no attribute '(\w+)'"
|
|
493
|
+
match = re.search(pattern, error_msg)
|
|
494
|
+
|
|
495
|
+
if match:
|
|
496
|
+
obj_type, attr_name = match.groups()
|
|
497
|
+
|
|
498
|
+
# Common attribute alternatives
|
|
499
|
+
alternatives = {
|
|
500
|
+
'append': ['extend', 'add', 'insert'],
|
|
501
|
+
'split': ['strip', 'replace', 'partition'],
|
|
502
|
+
'items': ['keys', 'values', 'get'],
|
|
503
|
+
'find': ['index', 'count', 'startswith'],
|
|
504
|
+
'update': ['setdefault', 'get', 'pop'],
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
# Try to suggest alternative
|
|
508
|
+
if attr_name in alternatives:
|
|
509
|
+
alt = alternatives[attr_name][0]
|
|
510
|
+
suggestion = f"# Maybe you meant .{alt}()?"
|
|
511
|
+
return f"{line.rstrip()} {suggestion}\n{indent}return None # AttributeError handled\n"
|
|
512
|
+
|
|
513
|
+
# Wrap in try/except
|
|
514
|
+
return (f"{indent}try:\n"
|
|
515
|
+
f"{indent} {line.strip()}\n"
|
|
516
|
+
f"{indent}except AttributeError:\n"
|
|
517
|
+
f"{indent} pass # {obj_type} has no {attr_name}\n")
|
|
518
|
+
|
|
519
|
+
return wrap_in_try_except(line, 'AttributeError', len(indent))
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
def _fix_index_error(line, indent, error_msg):
|
|
523
|
+
"""Fix IndexError by adding bounds checking."""
|
|
524
|
+
|
|
525
|
+
# Find index access patterns
|
|
526
|
+
index_pattern = r'(\w+)\[([^\]]+)\]'
|
|
527
|
+
matches = re.finditer(index_pattern, line)
|
|
528
|
+
|
|
529
|
+
for match in matches:
|
|
530
|
+
var_name = match.group(1)
|
|
531
|
+
index_expr = match.group(2)
|
|
532
|
+
|
|
533
|
+
# Wrap access in safe check
|
|
534
|
+
safe_access = f"({var_name}[{index_expr}] if len({var_name}) > {index_expr} else None)"
|
|
535
|
+
line = line.replace(match.group(0), safe_access)
|
|
536
|
+
|
|
537
|
+
# If we modified the line, return it
|
|
538
|
+
if index_pattern in line:
|
|
539
|
+
return line
|
|
540
|
+
|
|
541
|
+
# Otherwise wrap in try/except
|
|
542
|
+
return (f"{indent}try:\n"
|
|
543
|
+
f"{indent} {line.strip()}\n"
|
|
544
|
+
f"{indent}except IndexError:\n"
|
|
545
|
+
f"{indent} pass # Index out of range\n")
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
def _fix_key_error(line, indent, error_msg):
|
|
549
|
+
"""Fix KeyError by using .get() with default."""
|
|
550
|
+
|
|
551
|
+
# Find dictionary access patterns
|
|
552
|
+
dict_pattern = r'(\w+)\[([\'"][^\'"]+[\'"])\]'
|
|
553
|
+
matches = re.finditer(dict_pattern, line)
|
|
554
|
+
|
|
555
|
+
for match in matches:
|
|
556
|
+
dict_name = match.group(1)
|
|
557
|
+
key = match.group(2)
|
|
558
|
+
|
|
559
|
+
# Replace with .get()
|
|
560
|
+
safe_access = f"{dict_name}.get({key}, None)"
|
|
561
|
+
line = line.replace(match.group(0), safe_access)
|
|
562
|
+
|
|
563
|
+
# If we modified the line, return it
|
|
564
|
+
if matches:
|
|
565
|
+
return line
|
|
566
|
+
|
|
567
|
+
# Otherwise wrap in try/except
|
|
568
|
+
return (f"{indent}try:\n"
|
|
569
|
+
f"{indent} {line.strip()}\n"
|
|
570
|
+
f"{indent}except KeyError:\n"
|
|
571
|
+
f"{indent} pass # Key not found in dictionary\n")
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
def _fix_zero_division_error(line, indent, error_msg):
|
|
575
|
+
"""Fix ZeroDivisionError by checking denominator."""
|
|
576
|
+
|
|
577
|
+
# Find division operations
|
|
578
|
+
div_pattern = r'(\S+)\s*/\s*(\S+)'
|
|
579
|
+
match = re.search(div_pattern, line)
|
|
580
|
+
|
|
581
|
+
if match:
|
|
582
|
+
numerator = match.group(1)
|
|
583
|
+
denominator = match.group(2)
|
|
584
|
+
|
|
585
|
+
# Add check for zero
|
|
586
|
+
return (f"{indent}if {denominator} != 0:\n"
|
|
587
|
+
f"{indent} {line.strip()}\n"
|
|
588
|
+
f"{indent}else:\n"
|
|
589
|
+
f"{indent} result = 0 # Avoided division by zero\n")
|
|
590
|
+
|
|
591
|
+
# Fallback to try/except
|
|
592
|
+
return (f"{indent}try:\n"
|
|
593
|
+
f"{indent} {line.strip()}\n"
|
|
594
|
+
f"{indent}except ZeroDivisionError:\n"
|
|
595
|
+
f"{indent} result = 0 # Division by zero\n")
|
|
596
|
+
|
|
597
|
+
|
|
598
|
+
def _fix_file_not_found_error(line, indent, error_msg):
|
|
599
|
+
"""Fix FileNotFoundError by creating file or using default."""
|
|
600
|
+
|
|
601
|
+
# Check if it's a read operation
|
|
602
|
+
if 'open(' in line and ('r' in line or not 'w' in line):
|
|
603
|
+
# Extract filename if possible
|
|
604
|
+
file_pattern = r"open\s*\(\s*['\"]([^'\"]+)['\"]"
|
|
605
|
+
match = re.search(file_pattern, line)
|
|
606
|
+
|
|
607
|
+
if match:
|
|
608
|
+
filename = match.group(1)
|
|
609
|
+
return (f"{indent}try:\n"
|
|
610
|
+
f"{indent} {line.strip()}\n"
|
|
611
|
+
f"{indent}except FileNotFoundError:\n"
|
|
612
|
+
f"{indent} # Create empty file\n"
|
|
613
|
+
f"{indent} open('{filename}', 'w').close()\n"
|
|
614
|
+
f"{indent} {line.strip()}\n")
|
|
615
|
+
|
|
616
|
+
# General fallback
|
|
617
|
+
return wrap_in_try_except(line, 'FileNotFoundError', len(indent))
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+
def _fix_permission_error(line, indent, error_msg):
|
|
621
|
+
"""Fix PermissionError by handling access issues."""
|
|
622
|
+
return (f"{indent}try:\n"
|
|
623
|
+
f"{indent} {line.strip()}\n"
|
|
624
|
+
f"{indent}except PermissionError:\n"
|
|
625
|
+
f"{indent} print('Permission denied - check file permissions')\n"
|
|
626
|
+
f"{indent} pass\n")
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
def _fix_recursion_error(line, indent, error_msg):
|
|
630
|
+
"""Fix RecursionError by adding depth limit."""
|
|
631
|
+
return (f"{indent}import sys\n"
|
|
632
|
+
f"{indent}sys.setrecursionlimit(10000) # Increase recursion limit\n"
|
|
633
|
+
f"{indent}try:\n"
|
|
634
|
+
f"{indent} {line.strip()}\n"
|
|
635
|
+
f"{indent}except RecursionError:\n"
|
|
636
|
+
f"{indent} print('Maximum recursion depth exceeded')\n"
|
|
637
|
+
f"{indent} pass\n")
|
|
638
|
+
|
|
639
|
+
|
|
640
|
+
def _fix_memory_error(line, indent, error_msg):
|
|
641
|
+
"""Fix MemoryError by handling large allocations."""
|
|
642
|
+
return (f"{indent}try:\n"
|
|
643
|
+
f"{indent} {line.strip()}\n"
|
|
644
|
+
f"{indent}except MemoryError:\n"
|
|
645
|
+
f"{indent} print('Out of memory - reduce data size')\n"
|
|
646
|
+
f"{indent} pass\n")
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
def _fix_overflow_error(line, indent, error_msg):
|
|
650
|
+
"""Fix OverflowError by handling large numbers."""
|
|
651
|
+
return (f"{indent}try:\n"
|
|
652
|
+
f"{indent} {line.strip()}\n"
|
|
653
|
+
f"{indent}except OverflowError:\n"
|
|
654
|
+
f"{indent} result = float('inf') # Number too large\n")
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
def _fix_timeout_error(line, indent, error_msg):
|
|
658
|
+
"""Fix TimeoutError by adding timeout handling."""
|
|
659
|
+
return (f"{indent}try:\n"
|
|
660
|
+
f"{indent} {line.strip()}\n"
|
|
661
|
+
f"{indent}except TimeoutError:\n"
|
|
662
|
+
f"{indent} print('Operation timed out')\n"
|
|
663
|
+
f"{indent} pass\n")
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
def _fix_connection_error(line, indent, error_msg):
|
|
667
|
+
"""Fix ConnectionError by handling network issues."""
|
|
668
|
+
return (f"{indent}try:\n"
|
|
669
|
+
f"{indent} {line.strip()}\n"
|
|
670
|
+
f"{indent}except (ConnectionError, ConnectionRefusedError, ConnectionResetError):\n"
|
|
671
|
+
f"{indent} print('Connection failed - check network')\n"
|
|
672
|
+
f"{indent} pass\n")
|
|
673
|
+
|
|
674
|
+
|
|
675
|
+
def _fix_json_decode_error(line, indent, error_msg):
|
|
676
|
+
"""Fix JSONDecodeError by handling invalid JSON."""
|
|
677
|
+
return (f"{indent}try:\n"
|
|
678
|
+
f"{indent} {line.strip()}\n"
|
|
679
|
+
f"{indent}except json.JSONDecodeError:\n"
|
|
680
|
+
f"{indent} data = {{}} # Invalid JSON, using empty dict\n")
|
|
681
|
+
|
|
682
|
+
|
|
683
|
+
def _fix_unicode_error(line, indent, error_msg):
|
|
684
|
+
"""Fix UnicodeError by handling encoding issues."""
|
|
685
|
+
if 'encode' in line:
|
|
686
|
+
return (f"{indent}try:\n"
|
|
687
|
+
f"{indent} {line.strip()}\n"
|
|
688
|
+
f"{indent}except UnicodeEncodeError:\n"
|
|
689
|
+
f"{indent} result = text.encode('utf-8', errors='ignore')\n")
|
|
690
|
+
else:
|
|
691
|
+
return (f"{indent}try:\n"
|
|
692
|
+
f"{indent} {line.strip()}\n"
|
|
693
|
+
f"{indent}except UnicodeDecodeError:\n"
|
|
694
|
+
f"{indent} result = data.decode('utf-8', errors='ignore')\n")
|
|
695
|
+
|
|
696
|
+
|
|
697
|
+
def _fix_assertion_error(line, indent, error_msg):
|
|
698
|
+
"""Fix AssertionError by removing or handling assertion."""
|
|
699
|
+
if line.strip().startswith('assert'):
|
|
700
|
+
# Comment out the assertion
|
|
701
|
+
return f"{indent}# {line.strip()} # Assertion disabled\n"
|
|
702
|
+
else:
|
|
703
|
+
return (f"{indent}try:\n"
|
|
704
|
+
f"{indent} {line.strip()}\n"
|
|
705
|
+
f"{indent}except AssertionError:\n"
|
|
706
|
+
f"{indent} pass # Assertion failed\n")
|
|
707
|
+
|
|
708
|
+
|
|
709
|
+
def _fix_stopiteration_error(line, indent, error_msg):
|
|
710
|
+
"""Fix StopIteration by handling iterator exhaustion."""
|
|
711
|
+
return (f"{indent}try:\n"
|
|
712
|
+
f"{indent} {line.strip()}\n"
|
|
713
|
+
f"{indent}except StopIteration:\n"
|
|
714
|
+
f"{indent} pass # Iterator exhausted\n")
|
|
715
|
+
|
|
716
|
+
|
|
717
|
+
def _fix_generator_exit(line, indent, error_msg):
|
|
718
|
+
"""Fix GeneratorExit by handling generator termination."""
|
|
719
|
+
return (f"{indent}try:\n"
|
|
720
|
+
f"{indent} {line.strip()}\n"
|
|
721
|
+
f"{indent}except GeneratorExit:\n"
|
|
722
|
+
f"{indent} pass # Generator terminated\n")
|
|
723
|
+
|
|
724
|
+
# ============================================================================
|
|
725
|
+
# ERROR DATABASE (Comprehensive merger of both versions)
|
|
726
|
+
# ============================================================================
|
|
727
|
+
|
|
728
|
+
ERROR_DATABASE = {
|
|
729
|
+
'SyntaxError': {
|
|
730
|
+
'patterns': [
|
|
731
|
+
{
|
|
732
|
+
'detect': r'.*',
|
|
733
|
+
'fix': lambda line, indent, msg: line + ' # Fixed syntax\n' if not line.strip().endswith(':') else line,
|
|
734
|
+
'multiline': False
|
|
735
|
+
}
|
|
736
|
+
]
|
|
737
|
+
},
|
|
738
|
+
'NameError': {
|
|
739
|
+
'patterns': [
|
|
740
|
+
{
|
|
741
|
+
'detect': r'.*',
|
|
742
|
+
'fix': _fix_name_error,
|
|
743
|
+
'multiline': False
|
|
744
|
+
}
|
|
745
|
+
]
|
|
746
|
+
},
|
|
747
|
+
'ImportError': {
|
|
748
|
+
'patterns': [
|
|
749
|
+
{
|
|
750
|
+
'detect': r'import|from .* import',
|
|
751
|
+
'fix': _fix_import_error,
|
|
752
|
+
'multiline': True
|
|
753
|
+
}
|
|
754
|
+
]
|
|
755
|
+
},
|
|
756
|
+
'ModuleNotFoundError': {
|
|
757
|
+
'patterns': [
|
|
758
|
+
{
|
|
759
|
+
'detect': r'import|from .* import',
|
|
760
|
+
'fix': _fix_import_error,
|
|
761
|
+
'multiline': True
|
|
762
|
+
}
|
|
763
|
+
]
|
|
764
|
+
},
|
|
765
|
+
'TypeError': {
|
|
766
|
+
'patterns': [
|
|
767
|
+
{
|
|
768
|
+
'detect': r'.*',
|
|
769
|
+
'fix': _fix_type_error_smart,
|
|
770
|
+
'multiline': True
|
|
771
|
+
}
|
|
772
|
+
]
|
|
773
|
+
},
|
|
774
|
+
'ValueError': {
|
|
775
|
+
'patterns': [
|
|
776
|
+
{
|
|
777
|
+
'detect': r'.*',
|
|
778
|
+
'fix': _fix_value_error_smart,
|
|
779
|
+
'multiline': True
|
|
780
|
+
}
|
|
781
|
+
]
|
|
782
|
+
},
|
|
783
|
+
'AttributeError': {
|
|
784
|
+
'patterns': [
|
|
785
|
+
{
|
|
786
|
+
'detect': r'\.\w+',
|
|
787
|
+
'fix': _fix_attribute_error,
|
|
788
|
+
'multiline': True
|
|
789
|
+
}
|
|
790
|
+
]
|
|
791
|
+
},
|
|
792
|
+
'IndexError': {
|
|
793
|
+
'patterns': [
|
|
794
|
+
{
|
|
795
|
+
'detect': r'\[.+\]',
|
|
796
|
+
'fix': _fix_index_error,
|
|
797
|
+
'multiline': True
|
|
798
|
+
}
|
|
799
|
+
]
|
|
800
|
+
},
|
|
801
|
+
'KeyError': {
|
|
802
|
+
'patterns': [
|
|
803
|
+
{
|
|
804
|
+
'detect': r'\[.+\]|\.\w+',
|
|
805
|
+
'fix': _fix_key_error,
|
|
806
|
+
'multiline': True
|
|
807
|
+
}
|
|
808
|
+
]
|
|
809
|
+
},
|
|
810
|
+
'ZeroDivisionError': {
|
|
811
|
+
'patterns': [
|
|
812
|
+
{
|
|
813
|
+
'detect': r'/|//',
|
|
814
|
+
'fix': _fix_zero_division_error,
|
|
815
|
+
'multiline': True
|
|
816
|
+
}
|
|
817
|
+
]
|
|
818
|
+
},
|
|
819
|
+
'FileNotFoundError': {
|
|
820
|
+
'patterns': [
|
|
821
|
+
{
|
|
822
|
+
'detect': r'open\s*\(|with\s+open',
|
|
823
|
+
'fix': _fix_file_not_found_error,
|
|
824
|
+
'multiline': True
|
|
825
|
+
}
|
|
826
|
+
]
|
|
827
|
+
},
|
|
828
|
+
'PermissionError': {
|
|
829
|
+
'patterns': [
|
|
830
|
+
{
|
|
831
|
+
'detect': r'open|write|read|mkdir|rmdir',
|
|
832
|
+
'fix': _fix_permission_error,
|
|
833
|
+
'multiline': True
|
|
834
|
+
}
|
|
835
|
+
]
|
|
836
|
+
},
|
|
837
|
+
'RecursionError': {
|
|
838
|
+
'patterns': [
|
|
839
|
+
{
|
|
840
|
+
'detect': r'.*',
|
|
841
|
+
'fix': _fix_recursion_error,
|
|
842
|
+
'multiline': True
|
|
843
|
+
}
|
|
844
|
+
]
|
|
845
|
+
},
|
|
846
|
+
'MemoryError': {
|
|
847
|
+
'patterns': [
|
|
848
|
+
{
|
|
849
|
+
'detect': r'.*',
|
|
850
|
+
'fix': _fix_memory_error,
|
|
851
|
+
'multiline': True
|
|
852
|
+
}
|
|
853
|
+
]
|
|
854
|
+
},
|
|
855
|
+
'OverflowError': {
|
|
856
|
+
'patterns': [
|
|
857
|
+
{
|
|
858
|
+
'detect': r'\*\*|pow',
|
|
859
|
+
'fix': _fix_overflow_error,
|
|
860
|
+
'multiline': True
|
|
861
|
+
}
|
|
862
|
+
]
|
|
863
|
+
},
|
|
864
|
+
'TimeoutError': {
|
|
865
|
+
'patterns': [
|
|
866
|
+
{
|
|
867
|
+
'detect': r'.*',
|
|
868
|
+
'fix': _fix_timeout_error,
|
|
869
|
+
'multiline': True
|
|
870
|
+
}
|
|
871
|
+
]
|
|
872
|
+
},
|
|
873
|
+
'ConnectionError': {
|
|
874
|
+
'patterns': [
|
|
875
|
+
{
|
|
876
|
+
'detect': r'.*',
|
|
877
|
+
'fix': _fix_connection_error,
|
|
878
|
+
'multiline': True
|
|
879
|
+
}
|
|
880
|
+
]
|
|
881
|
+
},
|
|
882
|
+
'ConnectionRefusedError': {
|
|
883
|
+
'patterns': [
|
|
884
|
+
{
|
|
885
|
+
'detect': r'.*',
|
|
886
|
+
'fix': _fix_connection_error,
|
|
887
|
+
'multiline': True
|
|
888
|
+
}
|
|
889
|
+
]
|
|
890
|
+
},
|
|
891
|
+
'ConnectionResetError': {
|
|
892
|
+
'patterns': [
|
|
893
|
+
{
|
|
894
|
+
'detect': r'.*',
|
|
895
|
+
'fix': _fix_connection_error,
|
|
896
|
+
'multiline': True
|
|
897
|
+
}
|
|
898
|
+
]
|
|
899
|
+
},
|
|
900
|
+
'JSONDecodeError': {
|
|
901
|
+
'patterns': [
|
|
902
|
+
{
|
|
903
|
+
'detect': r'json\.load|json\.loads',
|
|
904
|
+
'fix': _fix_json_decode_error,
|
|
905
|
+
'multiline': True
|
|
906
|
+
}
|
|
907
|
+
]
|
|
908
|
+
},
|
|
909
|
+
'UnicodeDecodeError': {
|
|
910
|
+
'patterns': [
|
|
911
|
+
{
|
|
912
|
+
'detect': r'decode|open.*text|read',
|
|
913
|
+
'fix': _fix_unicode_error,
|
|
914
|
+
'multiline': True
|
|
915
|
+
}
|
|
916
|
+
]
|
|
917
|
+
},
|
|
918
|
+
'UnicodeEncodeError': {
|
|
919
|
+
'patterns': [
|
|
920
|
+
{
|
|
921
|
+
'detect': r'encode|write|print',
|
|
922
|
+
'fix': _fix_unicode_error,
|
|
923
|
+
'multiline': True
|
|
924
|
+
}
|
|
925
|
+
]
|
|
926
|
+
},
|
|
927
|
+
'AssertionError': {
|
|
928
|
+
'patterns': [
|
|
929
|
+
{
|
|
930
|
+
'detect': r'assert',
|
|
931
|
+
'fix': _fix_assertion_error,
|
|
932
|
+
'multiline': False
|
|
933
|
+
}
|
|
934
|
+
]
|
|
935
|
+
},
|
|
936
|
+
'UnboundLocalError': {
|
|
937
|
+
'patterns': [
|
|
938
|
+
{
|
|
939
|
+
'detect': r'.*',
|
|
940
|
+
'fix': _fix_unbound_local_error,
|
|
941
|
+
'multiline': False
|
|
942
|
+
}
|
|
943
|
+
]
|
|
944
|
+
},
|
|
945
|
+
'StopIteration': {
|
|
946
|
+
'patterns': [
|
|
947
|
+
{
|
|
948
|
+
'detect': r'next|__next__|for.*in',
|
|
949
|
+
'fix': _fix_stopiteration_error,
|
|
950
|
+
'multiline': True
|
|
951
|
+
}
|
|
952
|
+
]
|
|
953
|
+
},
|
|
954
|
+
'GeneratorExit': {
|
|
955
|
+
'patterns': [
|
|
956
|
+
{
|
|
957
|
+
'detect': r'yield|generator',
|
|
958
|
+
'fix': _fix_generator_exit,
|
|
959
|
+
'multiline': True
|
|
960
|
+
}
|
|
961
|
+
]
|
|
962
|
+
},
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
# ============================================================================
|
|
966
|
+
# DEPLOYMENT VALIDATION (from ultimate)
|
|
967
|
+
# ============================================================================
|
|
968
|
+
|
|
969
|
+
def check_deployment_issues():
|
|
970
|
+
"""Check for common deployment issues."""
|
|
971
|
+
issues = []
|
|
972
|
+
|
|
973
|
+
# Check environment variables
|
|
974
|
+
required_env_vars = ['DATABASE_URL', 'SECRET_KEY', 'API_KEY']
|
|
975
|
+
for var in required_env_vars:
|
|
976
|
+
if not os.environ.get(var):
|
|
977
|
+
issues.append(f"Missing environment variable: {var}")
|
|
978
|
+
|
|
979
|
+
# Check file permissions
|
|
980
|
+
important_paths = ['./logs', './uploads', './tmp']
|
|
981
|
+
for path in important_paths:
|
|
982
|
+
if os.path.exists(path) and not os.access(path, os.W_OK):
|
|
983
|
+
issues.append(f"No write permission: {path}")
|
|
984
|
+
|
|
985
|
+
# Check port availability
|
|
986
|
+
import socket
|
|
987
|
+
common_ports = [80, 443, 8000, 8080, 3000, 5000]
|
|
988
|
+
for port in common_ports:
|
|
989
|
+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
990
|
+
result = sock.connect_ex(('127.0.0.1', port))
|
|
991
|
+
sock.close()
|
|
992
|
+
if result == 0:
|
|
993
|
+
issues.append(f"Port {port} is already in use")
|
|
994
|
+
|
|
995
|
+
return issues
|
|
996
|
+
|
|
997
|
+
|
|
998
|
+
def fix_deployment_issues(issues):
|
|
999
|
+
"""Auto-fix deployment issues where possible."""
|
|
1000
|
+
for issue in issues:
|
|
1001
|
+
if "Missing environment variable" in issue:
|
|
1002
|
+
var_name = issue.split(": ")[1]
|
|
1003
|
+
# Create .env file
|
|
1004
|
+
with open('.env', 'a') as f:
|
|
1005
|
+
f.write(f"\n{var_name}=your_{var_name.lower()}_here")
|
|
1006
|
+
print(f"[FIX] Added {var_name} to .env file")
|
|
1007
|
+
|
|
1008
|
+
elif "No write permission" in issue:
|
|
1009
|
+
path = issue.split(": ")[1]
|
|
1010
|
+
os.makedirs(path, exist_ok=True)
|
|
1011
|
+
os.chmod(path, 0o755)
|
|
1012
|
+
print(f"[FIX] Fixed permissions for {path}")
|
|
1013
|
+
|
|
1014
|
+
elif "Port" in issue and "in use" in issue:
|
|
1015
|
+
port = int(issue.split(" ")[1])
|
|
1016
|
+
print(f"[INFO] Port {port} is in use, consider using a different port")
|
|
1017
|
+
|
|
1018
|
+
# ============================================================================
|
|
1019
|
+
# TYPE CHECKING (from ultimate)
|
|
1020
|
+
# ============================================================================
|
|
1021
|
+
|
|
1022
|
+
def run_type_checker(file_path):
|
|
1023
|
+
"""Run mypy type checker if available."""
|
|
1024
|
+
try:
|
|
1025
|
+
result = subprocess.run(
|
|
1026
|
+
['mypy', '--ignore-missing-imports', file_path],
|
|
1027
|
+
capture_output=True,
|
|
1028
|
+
text=True,
|
|
1029
|
+
timeout=30
|
|
1030
|
+
)
|
|
1031
|
+
return result.stdout + result.stderr
|
|
1032
|
+
except (FileNotFoundError, subprocess.TimeoutExpired):
|
|
1033
|
+
return None
|
|
1034
|
+
|
|
1035
|
+
|
|
1036
|
+
def parse_type_error(output):
|
|
1037
|
+
"""Parse mypy output for type errors."""
|
|
1038
|
+
errors = []
|
|
1039
|
+
for line in output.split('\n'):
|
|
1040
|
+
if ': error:' in line:
|
|
1041
|
+
match = re.match(r'(.+):(\d+): error: (.+)', line)
|
|
1042
|
+
if match:
|
|
1043
|
+
errors.append({
|
|
1044
|
+
'file': match.group(1),
|
|
1045
|
+
'line': int(match.group(2)),
|
|
1046
|
+
'message': match.group(3)
|
|
1047
|
+
})
|
|
1048
|
+
return errors
|
|
1049
|
+
|
|
1050
|
+
|
|
1051
|
+
def fix_type_error(file_path, line_number, error_message):
|
|
1052
|
+
"""Apply type hint fixes."""
|
|
1053
|
+
try:
|
|
1054
|
+
with open(file_path, 'r') as f:
|
|
1055
|
+
lines = f.readlines()
|
|
1056
|
+
|
|
1057
|
+
if line_number > 0 and line_number <= len(lines):
|
|
1058
|
+
target_line = lines[line_number - 1]
|
|
1059
|
+
indent = get_indent(target_line)
|
|
1060
|
+
|
|
1061
|
+
# Add type: ignore comment
|
|
1062
|
+
if not '# type: ignore' in target_line:
|
|
1063
|
+
lines[line_number - 1] = target_line.rstrip() + ' # type: ignore\n'
|
|
1064
|
+
|
|
1065
|
+
with open(file_path, 'w') as f:
|
|
1066
|
+
f.writelines(lines)
|
|
1067
|
+
|
|
1068
|
+
print(f"[FIX] Added type ignore at line {line_number}")
|
|
1069
|
+
return True
|
|
1070
|
+
except:
|
|
1071
|
+
pass
|
|
1072
|
+
|
|
1073
|
+
return False
|
|
1074
|
+
|
|
1075
|
+
# ============================================================================
|
|
1076
|
+
# ERROR PREDICTION (from ultimate)
|
|
1077
|
+
# ============================================================================
|
|
1078
|
+
|
|
1079
|
+
class ErrorPredictor:
|
|
1080
|
+
"""Predict potential errors before they occur."""
|
|
1081
|
+
|
|
1082
|
+
def __init__(self):
|
|
1083
|
+
self.patterns = {
|
|
1084
|
+
'division_by_zero': r'(\w+)\s*/\s*(\w+)',
|
|
1085
|
+
'uninitialized_var': r'^(\s*)(\w+)\.append\(',
|
|
1086
|
+
'missing_return': r'^\s*def\s+\w+.*:',
|
|
1087
|
+
'infinite_loop': r'^\s*while\s+True:',
|
|
1088
|
+
'unclosed_file': r'open\([^)]+\)\.',
|
|
1089
|
+
'sql_injection': r'execute\(.+%\s*s',
|
|
1090
|
+
'hardcoded_password': r'password\s*=\s*[\'"]',
|
|
1091
|
+
'unused_variable': r'^\s*(\w+)\s*=.*(?!.*\1)',
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
def predict_errors(self, code_lines):
|
|
1095
|
+
"""Analyze code for potential errors."""
|
|
1096
|
+
predictions = []
|
|
1097
|
+
|
|
1098
|
+
for i, line in enumerate(code_lines):
|
|
1099
|
+
for error_type, pattern in self.patterns.items():
|
|
1100
|
+
if re.search(pattern, line):
|
|
1101
|
+
prediction = {
|
|
1102
|
+
'line': i + 1,
|
|
1103
|
+
'type': error_type,
|
|
1104
|
+
'code': line.strip(),
|
|
1105
|
+
'suggestion': self._get_suggestion(error_type)
|
|
1106
|
+
}
|
|
1107
|
+
predictions.append(prediction)
|
|
1108
|
+
|
|
1109
|
+
return predictions
|
|
1110
|
+
|
|
1111
|
+
def _get_suggestion(self, error_type):
|
|
1112
|
+
"""Get suggestion for predicted error."""
|
|
1113
|
+
suggestions = {
|
|
1114
|
+
'division_by_zero': 'Add zero check before division',
|
|
1115
|
+
'uninitialized_var': 'Initialize variable before use',
|
|
1116
|
+
'missing_return': 'Add return statement',
|
|
1117
|
+
'infinite_loop': 'Add break condition',
|
|
1118
|
+
'unclosed_file': 'Use context manager (with statement)',
|
|
1119
|
+
'sql_injection': 'Use parameterized queries',
|
|
1120
|
+
'hardcoded_password': 'Use environment variables',
|
|
1121
|
+
'unused_variable': 'Remove or use the variable',
|
|
1122
|
+
}
|
|
1123
|
+
return suggestions.get(error_type, 'Review this code')
|
|
1124
|
+
|
|
1125
|
+
# ============================================================================
|
|
1126
|
+
# MAIN EXECUTION FUNCTIONS
|
|
1127
|
+
# ============================================================================
|
|
1128
|
+
|
|
1129
|
+
def run_and_capture_error(script_path):
|
|
1130
|
+
"""Run Python script and capture stderr."""
|
|
1131
|
+
try:
|
|
1132
|
+
# Run with timeout to prevent infinite loops
|
|
1133
|
+
result = subprocess.run(
|
|
1134
|
+
[sys.executable, script_path],
|
|
1135
|
+
capture_output=True,
|
|
1136
|
+
text=True,
|
|
1137
|
+
timeout=10 # 10 second timeout
|
|
1138
|
+
)
|
|
1139
|
+
|
|
1140
|
+
# Return stderr if there's an error
|
|
1141
|
+
if result.returncode != 0:
|
|
1142
|
+
return result.stderr
|
|
1143
|
+
return None
|
|
1144
|
+
|
|
1145
|
+
except subprocess.TimeoutExpired:
|
|
1146
|
+
return "TimeoutError: Script execution exceeded time limit"
|
|
1147
|
+
except Exception as e:
|
|
1148
|
+
return str(e)
|
|
1149
|
+
|
|
1150
|
+
|
|
1151
|
+
def parse_error(stderr, target_script=None):
|
|
1152
|
+
"""Parse error from stderr output."""
|
|
1153
|
+
lines = stderr.strip().split('\n')
|
|
1154
|
+
|
|
1155
|
+
error_type = None
|
|
1156
|
+
error_file = None
|
|
1157
|
+
error_line = None
|
|
1158
|
+
error_message = ""
|
|
1159
|
+
|
|
1160
|
+
# Find the error type and message
|
|
1161
|
+
for line in lines:
|
|
1162
|
+
if line.strip() and not line.startswith(' '):
|
|
1163
|
+
# Look for standard Python error format
|
|
1164
|
+
error_match = re.match(r'^(\w+(?:Error|Exception)):\s*(.*)', line)
|
|
1165
|
+
if error_match:
|
|
1166
|
+
error_type = error_match.group(1)
|
|
1167
|
+
error_message = error_match.group(2) or ""
|
|
1168
|
+
break
|
|
1169
|
+
|
|
1170
|
+
# Check for error type in the line
|
|
1171
|
+
parts = line.split(':')
|
|
1172
|
+
if parts:
|
|
1173
|
+
potential_error = parts[0].strip()
|
|
1174
|
+
|
|
1175
|
+
# Handle module prefixed errors
|
|
1176
|
+
if '.' in potential_error:
|
|
1177
|
+
potential_error = potential_error.split('.')[-1]
|
|
1178
|
+
|
|
1179
|
+
# Check if it's a known error or follows Error naming pattern
|
|
1180
|
+
if potential_error in ERROR_DATABASE or potential_error.endswith('Error'):
|
|
1181
|
+
error_type = potential_error
|
|
1182
|
+
break
|
|
1183
|
+
|
|
1184
|
+
# Collect ALL frames from the traceback
|
|
1185
|
+
all_frames = []
|
|
1186
|
+
for line in lines:
|
|
1187
|
+
if 'File "' in line and ', line ' in line:
|
|
1188
|
+
match = re.search(r'File "([^"]+)", line (\d+)', line)
|
|
1189
|
+
if match:
|
|
1190
|
+
file_path = match.group(1)
|
|
1191
|
+
line_num = int(match.group(2))
|
|
1192
|
+
|
|
1193
|
+
# Skip system files
|
|
1194
|
+
if not file_path.startswith('<') and '/lib/python' not in file_path:
|
|
1195
|
+
all_frames.append((file_path, line_num))
|
|
1196
|
+
|
|
1197
|
+
# If target_script specified, filter to only that file
|
|
1198
|
+
if target_script and all_frames:
|
|
1199
|
+
target_abs = os.path.abspath(target_script)
|
|
1200
|
+
target_frames = [
|
|
1201
|
+
(f, ln) for f, ln in all_frames
|
|
1202
|
+
if os.path.abspath(f) == target_abs
|
|
1203
|
+
]
|
|
1204
|
+
|
|
1205
|
+
# Use deepest frame from target file (last in stack = closest to error)
|
|
1206
|
+
if target_frames:
|
|
1207
|
+
error_file, error_line = target_frames[-1]
|
|
1208
|
+
|
|
1209
|
+
# Fallback: use deepest frame overall
|
|
1210
|
+
if not error_file and all_frames:
|
|
1211
|
+
error_file, error_line = all_frames[-1]
|
|
1212
|
+
|
|
1213
|
+
return error_type, error_file, error_line, error_message
|
|
1214
|
+
|
|
1215
|
+
|
|
1216
|
+
def fix_error(file_path, error_type, line_number, error_message):
|
|
1217
|
+
"""Apply hard-coded fix for error type at line number."""
|
|
1218
|
+
|
|
1219
|
+
if error_type not in ERROR_DATABASE:
|
|
1220
|
+
print(f"[WARN] No solution for {error_type} in database")
|
|
1221
|
+
return False
|
|
1222
|
+
|
|
1223
|
+
try:
|
|
1224
|
+
with open(file_path, 'r', encoding='utf-8') as f:
|
|
1225
|
+
lines = f.readlines()
|
|
1226
|
+
except Exception as e:
|
|
1227
|
+
print(f"[ERROR] Cannot read file: {e}")
|
|
1228
|
+
return False
|
|
1229
|
+
|
|
1230
|
+
if line_number > len(lines) or line_number < 1:
|
|
1231
|
+
print(f"[ERROR] Line {line_number} out of range (file has {len(lines)} lines)")
|
|
1232
|
+
return False
|
|
1233
|
+
|
|
1234
|
+
target_line = lines[line_number - 1]
|
|
1235
|
+
indent = get_indent(target_line)
|
|
1236
|
+
|
|
1237
|
+
# Try each pattern for this error type
|
|
1238
|
+
for pattern_idx, pattern in enumerate(ERROR_DATABASE[error_type]['patterns']):
|
|
1239
|
+
if re.search(pattern['detect'], target_line):
|
|
1240
|
+
try:
|
|
1241
|
+
# Check if this needs multi-line block wrapping
|
|
1242
|
+
needs_block_wrap = pattern['multiline'] and (
|
|
1243
|
+
re.search(r'\b(with|for|while)\b', target_line) or
|
|
1244
|
+
target_line.strip().endswith(':')
|
|
1245
|
+
)
|
|
1246
|
+
|
|
1247
|
+
if needs_block_wrap:
|
|
1248
|
+
# Get the entire indented block
|
|
1249
|
+
block_lines, base_indent = get_indented_block(lines, line_number - 1)
|
|
1250
|
+
|
|
1251
|
+
if block_lines:
|
|
1252
|
+
# For FileNotFoundError and similar, wrap entire block
|
|
1253
|
+
if error_type in ['FileNotFoundError', 'JSONDecodeError', 'PermissionError']:
|
|
1254
|
+
fixed = wrap_block_in_try_except(block_lines, base_indent, error_type)
|
|
1255
|
+
else:
|
|
1256
|
+
# Use standard fix
|
|
1257
|
+
fixed = pattern['fix'](target_line, indent, error_message)
|
|
1258
|
+
|
|
1259
|
+
# Determine how many lines to replace
|
|
1260
|
+
lines_to_replace = len(block_lines)
|
|
1261
|
+
|
|
1262
|
+
# Replace the block
|
|
1263
|
+
fixed_lines = fixed.split('\n')
|
|
1264
|
+
new_lines = [line + '\n' for line in fixed_lines if line]
|
|
1265
|
+
lines[line_number - 1:line_number - 1 + lines_to_replace] = new_lines
|
|
1266
|
+
else:
|
|
1267
|
+
# Fallback to single line fix
|
|
1268
|
+
fixed = pattern['fix'](target_line, indent, error_message)
|
|
1269
|
+
if not fixed.endswith('\n'):
|
|
1270
|
+
fixed += '\n'
|
|
1271
|
+
lines[line_number - 1] = fixed
|
|
1272
|
+
elif pattern['multiline']:
|
|
1273
|
+
# Multi-line but not block-based
|
|
1274
|
+
fixed = pattern['fix'](target_line, indent, error_message)
|
|
1275
|
+
lines[line_number - 1] = fixed
|
|
1276
|
+
else:
|
|
1277
|
+
# Single line replacement
|
|
1278
|
+
fixed = pattern['fix'](target_line, indent, error_message)
|
|
1279
|
+
if not fixed.endswith('\n'):
|
|
1280
|
+
fixed += '\n'
|
|
1281
|
+
lines[line_number - 1] = fixed
|
|
1282
|
+
|
|
1283
|
+
# Write back
|
|
1284
|
+
with open(file_path, 'w', encoding='utf-8') as f:
|
|
1285
|
+
f.writelines(lines)
|
|
1286
|
+
|
|
1287
|
+
print(f"[FIX] Applied {error_type} fix at line {line_number} (pattern {pattern_idx + 1})")
|
|
1288
|
+
return True
|
|
1289
|
+
except Exception as e:
|
|
1290
|
+
print(f"[ERROR] Failed to apply fix: {e}")
|
|
1291
|
+
traceback.print_exc()
|
|
1292
|
+
continue
|
|
1293
|
+
|
|
1294
|
+
print(f"[WARN] No matching pattern for {error_type} at line {line_number}")
|
|
1295
|
+
print(f"[LINE] {target_line.strip()}")
|
|
1296
|
+
return False
|
|
1297
|
+
|
|
1298
|
+
|
|
1299
|
+
def main():
|
|
1300
|
+
"""Main entry point with support for multiple modes."""
|
|
1301
|
+
|
|
1302
|
+
# ============================================================================
|
|
1303
|
+
# EVALUATION LICENSE CHECK
|
|
1304
|
+
# ============================================================================
|
|
1305
|
+
EXPIRY = datetime(2025, 11, 17, 23, 59, 59) # 7-day trial
|
|
1306
|
+
if datetime.now() > EXPIRY:
|
|
1307
|
+
print("=" * 70)
|
|
1308
|
+
print("BUG-BE-GONE EVALUATION PERIOD ENDED")
|
|
1309
|
+
print("=" * 70)
|
|
1310
|
+
print()
|
|
1311
|
+
print("Your 7-day trial has expired.")
|
|
1312
|
+
print()
|
|
1313
|
+
print("To purchase a full license or discuss enterprise options:")
|
|
1314
|
+
print(" Email: Keeghan@dishesandmore.com")
|
|
1315
|
+
print(" Subject: Bug-Be-Gone License")
|
|
1316
|
+
print()
|
|
1317
|
+
print("Thank you for evaluating Bug-Be-Gone!")
|
|
1318
|
+
print("=" * 70)
|
|
1319
|
+
sys.exit(1)
|
|
1320
|
+
|
|
1321
|
+
if len(sys.argv) < 2:
|
|
1322
|
+
print(__doc__)
|
|
1323
|
+
sys.exit(1)
|
|
1324
|
+
|
|
1325
|
+
# Parse arguments
|
|
1326
|
+
mode = 'runtime' # default
|
|
1327
|
+
script_path = None
|
|
1328
|
+
|
|
1329
|
+
for arg in sys.argv[1:]:
|
|
1330
|
+
if arg.startswith('--'):
|
|
1331
|
+
if arg == '--types':
|
|
1332
|
+
mode = 'types'
|
|
1333
|
+
elif arg == '--deploy':
|
|
1334
|
+
mode = 'deploy'
|
|
1335
|
+
elif arg == '--all':
|
|
1336
|
+
mode = 'all'
|
|
1337
|
+
elif arg == '--predict':
|
|
1338
|
+
mode = 'predict'
|
|
1339
|
+
elif arg == '--ultimate':
|
|
1340
|
+
mode = 'ultimate'
|
|
1341
|
+
else:
|
|
1342
|
+
script_path = arg
|
|
1343
|
+
|
|
1344
|
+
# Handle deployment mode
|
|
1345
|
+
if mode == 'deploy':
|
|
1346
|
+
print("[DEPLOY] Checking deployment issues...")
|
|
1347
|
+
issues = check_deployment_issues()
|
|
1348
|
+
if issues:
|
|
1349
|
+
print(f"[FOUND] {len(issues)} deployment issue(s)")
|
|
1350
|
+
for issue in issues:
|
|
1351
|
+
print(f" - {issue}")
|
|
1352
|
+
fix_deployment_issues(issues)
|
|
1353
|
+
else:
|
|
1354
|
+
print("[SUCCESS] No deployment issues found!")
|
|
1355
|
+
return
|
|
1356
|
+
|
|
1357
|
+
# Require script path for other modes
|
|
1358
|
+
if not script_path or not os.path.exists(script_path):
|
|
1359
|
+
print(f"[ERROR] File not found: {script_path}")
|
|
1360
|
+
sys.exit(1)
|
|
1361
|
+
|
|
1362
|
+
# Create backup
|
|
1363
|
+
backup_path = script_path + '.backup'
|
|
1364
|
+
shutil.copy2(script_path, backup_path)
|
|
1365
|
+
print(f"[BACKUP] Created at {backup_path}")
|
|
1366
|
+
|
|
1367
|
+
print(f"[START] Universal Debugger MERGED")
|
|
1368
|
+
print(f"[TRIAL] Evaluation license - expires Nov 17, 2025")
|
|
1369
|
+
print(f"[MODE] {mode.upper()}")
|
|
1370
|
+
print(f"[TARGET] {os.path.abspath(script_path)}")
|
|
1371
|
+
print(f"[DATABASE] {len(ERROR_DATABASE)} error types loaded")
|
|
1372
|
+
|
|
1373
|
+
# Error prediction mode
|
|
1374
|
+
if mode in ['predict', 'ultimate']:
|
|
1375
|
+
print("\n[PREDICT] Analyzing code for potential errors...")
|
|
1376
|
+
predictor = ErrorPredictor()
|
|
1377
|
+
with open(script_path, 'r') as f:
|
|
1378
|
+
code_lines = f.readlines()
|
|
1379
|
+
|
|
1380
|
+
predictions = predictor.predict_errors(code_lines)
|
|
1381
|
+
if predictions:
|
|
1382
|
+
print(f"[WARN] Found {len(predictions)} potential issue(s):")
|
|
1383
|
+
for pred in predictions:
|
|
1384
|
+
print(f" Line {pred['line']}: {pred['type']}")
|
|
1385
|
+
print(f" Code: {pred['code']}")
|
|
1386
|
+
print(f" Suggestion: {pred['suggestion']}")
|
|
1387
|
+
else:
|
|
1388
|
+
print("[GOOD] No potential issues detected")
|
|
1389
|
+
|
|
1390
|
+
# Type checking mode
|
|
1391
|
+
if mode in ['types', 'all', 'ultimate']:
|
|
1392
|
+
print("\n[TYPES] Running type checker...")
|
|
1393
|
+
type_output = run_type_checker(script_path)
|
|
1394
|
+
if type_output:
|
|
1395
|
+
type_errors = parse_type_error(type_output)
|
|
1396
|
+
print(f"[FOUND] {len(type_errors)} type error(s)")
|
|
1397
|
+
for err in type_errors:
|
|
1398
|
+
print(f" Line {err['line']}: {err['message']}")
|
|
1399
|
+
fix_type_error(err['file'], err['line'], err['message'])
|
|
1400
|
+
else:
|
|
1401
|
+
print("[SUCCESS] No type errors found!")
|
|
1402
|
+
|
|
1403
|
+
# Runtime error fixing mode
|
|
1404
|
+
if mode in ['runtime', 'all', 'ultimate']:
|
|
1405
|
+
print("\n[RUNTIME] Fixing runtime errors...")
|
|
1406
|
+
|
|
1407
|
+
max_iterations = 100
|
|
1408
|
+
iteration = 0
|
|
1409
|
+
fixed_errors = []
|
|
1410
|
+
|
|
1411
|
+
while iteration < max_iterations:
|
|
1412
|
+
iteration += 1
|
|
1413
|
+
print(f"[ITERATION {iteration}] Running script...")
|
|
1414
|
+
|
|
1415
|
+
stderr = run_and_capture_error(script_path)
|
|
1416
|
+
|
|
1417
|
+
if not stderr:
|
|
1418
|
+
print(f"[SUCCESS] No errors detected!")
|
|
1419
|
+
print(f"[COMPLETE] Fixed {len(fixed_errors)} error(s) in {iteration - 1} iteration(s)")
|
|
1420
|
+
if fixed_errors:
|
|
1421
|
+
print(f"[FIXED]")
|
|
1422
|
+
for err in fixed_errors:
|
|
1423
|
+
print(f" - {err}")
|
|
1424
|
+
break
|
|
1425
|
+
|
|
1426
|
+
error_type, error_file, error_line, error_msg = parse_error(stderr, script_path)
|
|
1427
|
+
|
|
1428
|
+
if not error_type:
|
|
1429
|
+
print(f"[ERROR] Could not determine error type from:")
|
|
1430
|
+
print(stderr)
|
|
1431
|
+
break
|
|
1432
|
+
|
|
1433
|
+
if not error_file or not error_line:
|
|
1434
|
+
print(f"[ERROR] Could not locate error in source:")
|
|
1435
|
+
print(stderr)
|
|
1436
|
+
break
|
|
1437
|
+
|
|
1438
|
+
# Only fix errors in the target script
|
|
1439
|
+
if os.path.abspath(error_file) != os.path.abspath(script_path):
|
|
1440
|
+
print(f"[SKIP] Error is in external file: {error_file}")
|
|
1441
|
+
print(stderr)
|
|
1442
|
+
break
|
|
1443
|
+
|
|
1444
|
+
error_descriptor = f"{error_type} at line {error_line}"
|
|
1445
|
+
print(f"[DETECTED] {error_descriptor}: {error_msg[:50]}...")
|
|
1446
|
+
|
|
1447
|
+
if error_descriptor in fixed_errors:
|
|
1448
|
+
print(f"[ERROR] Already tried to fix this error - infinite loop detected")
|
|
1449
|
+
print(stderr)
|
|
1450
|
+
break
|
|
1451
|
+
|
|
1452
|
+
if fix_error(error_file, error_type, error_line, error_msg):
|
|
1453
|
+
fixed_errors.append(error_descriptor)
|
|
1454
|
+
else:
|
|
1455
|
+
print(f"[FAILED] Could not apply fix")
|
|
1456
|
+
print(error_msg)
|
|
1457
|
+
break
|
|
1458
|
+
|
|
1459
|
+
if iteration >= max_iterations:
|
|
1460
|
+
print(f"[TIMEOUT] Max iterations reached")
|
|
1461
|
+
print(f"[RESTORE] Use {backup_path} to restore original")
|
|
1462
|
+
|
|
1463
|
+
# Ultimate mode summary
|
|
1464
|
+
if mode == 'ultimate':
|
|
1465
|
+
print("\n[ULTIMATE] Complete analysis finished")
|
|
1466
|
+
print("[ULTIMATE] Your code has been thoroughly debugged, optimized, and fortified")
|
|
1467
|
+
print("[ULTIMATE] Smart return values ensure appropriate defaults")
|
|
1468
|
+
print("[ULTIMATE] AST-based parsing provides intelligent fixes")
|
|
1469
|
+
print("[ULTIMATE] It should now be virtually indestructible")
|
|
1470
|
+
|
|
1471
|
+
|
|
1472
|
+
if __name__ == "__main__":
|
|
1473
|
+
main()
|