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.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()