WhyCrash 1.0.0__tar.gz

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.
@@ -0,0 +1,140 @@
1
+ Metadata-Version: 2.4
2
+ Name: WhyCrash
3
+ Version: 1.0.0
4
+ Summary: A highly automatic AI error handler and code fixer using OpenRouter and Minimax.
5
+ Home-page: https://github.com/yourusername/WhyCrash
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Classifier: Operating System :: OS Independent
9
+ Requires-Python: >=3.8
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: requests
12
+ Requires-Dist: rich
13
+ Requires-Dist: questionary
14
+ Dynamic: classifier
15
+ Dynamic: description
16
+ Dynamic: description-content-type
17
+ Dynamic: home-page
18
+ Dynamic: requires-dist
19
+ Dynamic: requires-python
20
+ Dynamic: summary
21
+
22
+ # πŸš€ WhyCrash
23
+ **WhyCrash** is a fully automatic AI assistant for error handling in Python. When your code crashes, WhyCrash intercepts the error, analyzes it using neural networks (OpenRouter + Minimax), gathers context from your local project files, and provides the cause along with an **AUTOMATIC CODE FIX**.
24
+
25
+ Did your code crash? The AI will explain why and automatically replace the broken file with the fixed one (if you allow it).
26
+
27
+ ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)
28
+ ![Python Versions](https://img.shields.io/badge/python-3.8%2B-blue)
29
+
30
+ ## ✨ Main Features
31
+ - 🧠 **Smart Traceback Analysis**: Understands not just the line with the error but also gathers imported local project files.
32
+ - πŸ› οΈ **Auto-Fixing**: Proposes a ready-made fix and can rewrite the target Python files itself.
33
+ - 🎯 **Precise Control**: You decide where to catch errors: in the entire project, in a single function, or in a specific block of code.
34
+ - 🎨 **Beautiful Interface**: Uses the `rich` library for nice windows and terminal formatting.
35
+
36
+ ---
37
+
38
+ ## πŸ“¦ Installation
39
+
40
+ ```bash
41
+ pip install WhyCrash
42
+ ```
43
+ > *(Requires `requests`, `rich`, and `questionary` β€” they will install automatically)*
44
+
45
+ ---
46
+
47
+ ## πŸ› οΈ How to Use
48
+
49
+ You have 4 ways to control which errors WhyCrash should catch. Choose the one that fits best!
50
+
51
+ ### 1. Global Intercept (Easiest)
52
+ If you want **any** unhandled error in your program to be analyzed by the AI:
53
+
54
+ ```python
55
+ import WhyCrash
56
+
57
+ # Enable error catching for the whole script
58
+ WhyCrash.debug()
59
+
60
+ # If the code crashes below, WhyCrash comes to the rescue!
61
+ print(1 / 0)
62
+ ```
63
+
64
+ ### 2. Dynamic Toggle (start & end)
65
+ If you have a large block of code and want to turn on smart analysis right before it, and turn it off right after:
66
+
67
+ ```python
68
+ import WhyCrash
69
+
70
+ # ... normal code without WhyCrash ...
71
+
72
+ WhyCrash.start_debug() # Turn on the interceptor
73
+
74
+ a = "text"
75
+ b = int(a) # <-- This error will go to the AI!
76
+
77
+ WhyCrash.end_debug() # Turn off the interceptor (returns to standard behavior)
78
+ ```
79
+
80
+ ### 3. Decorator for Specific Functions `@catch_errors`
81
+ If you are only concerned about the reliability of a specific function, you can wrap it in a decorator. If the function crashes, WhyCrash will trigger, while system errors outside of it remain untouched.
82
+
83
+ ```python
84
+ from WhyCrash import catch_errors
85
+
86
+ @catch_errors
87
+ def my_danger_function():
88
+ # If it breaks here β€” WhyCrash will trigger
89
+ file = open("no_exist.txt", "r")
90
+
91
+ def normal_function():
92
+ # And if it breaks here β€” standard Python traceback
93
+ pass
94
+
95
+ my_danger_function()
96
+ ```
97
+
98
+ ### 4. Context Manager `with catch_block()`
99
+ For the most precise control, if you expect a failure in literally 2 specific lines of code:
100
+
101
+ ```python
102
+ from WhyCrash import catch_block
103
+
104
+ print("Starting work...")
105
+ text = "100"
106
+
107
+ with catch_block():
108
+ # Only code inside this block is monitored
109
+ number = int(text)
110
+ result = number / 0 # This will trigger an error sent to WhyCrash!
111
+
112
+ print("This code will not execute if there was an error above.")
113
+ ```
114
+
115
+ ---
116
+
117
+ ## πŸ›‘ How to Ignore Error Catching?
118
+ WhyCrash only analyzes **unhandled** exceptions. If you want an error in your code **not** to reach WhyCrash and the script to keep running, simply use a standard `try...except` block:
119
+
120
+ ```python
121
+ import WhyCrash
122
+ WhyCrash.debug()
123
+
124
+ try:
125
+ int("letter")
126
+ except ValueError:
127
+ print("Error caught, it won't reach WhyCrash. Moving on!")
128
+ ```
129
+
130
+ ## βš™οΈ Under the Hood
131
+ - **OpenRouter & Minimax** β€” Responsible for code analysis, "Reasoning," and generating fix files.
132
+ - **Traceback Walking** β€” The script automatically follows the error chain, finds all your `.py` files involved, reads them, and sends them to the AI as context.
133
+ - **Rich** β€” Beautiful console UI (colors, panels, Markdown formatting).
134
+
135
+ ---
136
+
137
+ Made with ❀️ to save developers' nerves!
138
+
139
+ ---
140
+ 🌍 **Languages:** [Русский](docs/README_ru.md) | [Deutsch](docs/README_de.md)
@@ -0,0 +1,119 @@
1
+ # πŸš€ WhyCrash
2
+ **WhyCrash** is a fully automatic AI assistant for error handling in Python. When your code crashes, WhyCrash intercepts the error, analyzes it using neural networks (OpenRouter + Minimax), gathers context from your local project files, and provides the cause along with an **AUTOMATIC CODE FIX**.
3
+
4
+ Did your code crash? The AI will explain why and automatically replace the broken file with the fixed one (if you allow it).
5
+
6
+ ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)
7
+ ![Python Versions](https://img.shields.io/badge/python-3.8%2B-blue)
8
+
9
+ ## ✨ Main Features
10
+ - 🧠 **Smart Traceback Analysis**: Understands not just the line with the error but also gathers imported local project files.
11
+ - πŸ› οΈ **Auto-Fixing**: Proposes a ready-made fix and can rewrite the target Python files itself.
12
+ - 🎯 **Precise Control**: You decide where to catch errors: in the entire project, in a single function, or in a specific block of code.
13
+ - 🎨 **Beautiful Interface**: Uses the `rich` library for nice windows and terminal formatting.
14
+
15
+ ---
16
+
17
+ ## πŸ“¦ Installation
18
+
19
+ ```bash
20
+ pip install WhyCrash
21
+ ```
22
+ > *(Requires `requests`, `rich`, and `questionary` β€” they will install automatically)*
23
+
24
+ ---
25
+
26
+ ## πŸ› οΈ How to Use
27
+
28
+ You have 4 ways to control which errors WhyCrash should catch. Choose the one that fits best!
29
+
30
+ ### 1. Global Intercept (Easiest)
31
+ If you want **any** unhandled error in your program to be analyzed by the AI:
32
+
33
+ ```python
34
+ import WhyCrash
35
+
36
+ # Enable error catching for the whole script
37
+ WhyCrash.debug()
38
+
39
+ # If the code crashes below, WhyCrash comes to the rescue!
40
+ print(1 / 0)
41
+ ```
42
+
43
+ ### 2. Dynamic Toggle (start & end)
44
+ If you have a large block of code and want to turn on smart analysis right before it, and turn it off right after:
45
+
46
+ ```python
47
+ import WhyCrash
48
+
49
+ # ... normal code without WhyCrash ...
50
+
51
+ WhyCrash.start_debug() # Turn on the interceptor
52
+
53
+ a = "text"
54
+ b = int(a) # <-- This error will go to the AI!
55
+
56
+ WhyCrash.end_debug() # Turn off the interceptor (returns to standard behavior)
57
+ ```
58
+
59
+ ### 3. Decorator for Specific Functions `@catch_errors`
60
+ If you are only concerned about the reliability of a specific function, you can wrap it in a decorator. If the function crashes, WhyCrash will trigger, while system errors outside of it remain untouched.
61
+
62
+ ```python
63
+ from WhyCrash import catch_errors
64
+
65
+ @catch_errors
66
+ def my_danger_function():
67
+ # If it breaks here β€” WhyCrash will trigger
68
+ file = open("no_exist.txt", "r")
69
+
70
+ def normal_function():
71
+ # And if it breaks here β€” standard Python traceback
72
+ pass
73
+
74
+ my_danger_function()
75
+ ```
76
+
77
+ ### 4. Context Manager `with catch_block()`
78
+ For the most precise control, if you expect a failure in literally 2 specific lines of code:
79
+
80
+ ```python
81
+ from WhyCrash import catch_block
82
+
83
+ print("Starting work...")
84
+ text = "100"
85
+
86
+ with catch_block():
87
+ # Only code inside this block is monitored
88
+ number = int(text)
89
+ result = number / 0 # This will trigger an error sent to WhyCrash!
90
+
91
+ print("This code will not execute if there was an error above.")
92
+ ```
93
+
94
+ ---
95
+
96
+ ## πŸ›‘ How to Ignore Error Catching?
97
+ WhyCrash only analyzes **unhandled** exceptions. If you want an error in your code **not** to reach WhyCrash and the script to keep running, simply use a standard `try...except` block:
98
+
99
+ ```python
100
+ import WhyCrash
101
+ WhyCrash.debug()
102
+
103
+ try:
104
+ int("letter")
105
+ except ValueError:
106
+ print("Error caught, it won't reach WhyCrash. Moving on!")
107
+ ```
108
+
109
+ ## βš™οΈ Under the Hood
110
+ - **OpenRouter & Minimax** β€” Responsible for code analysis, "Reasoning," and generating fix files.
111
+ - **Traceback Walking** β€” The script automatically follows the error chain, finds all your `.py` files involved, reads them, and sends them to the AI as context.
112
+ - **Rich** β€” Beautiful console UI (colors, panels, Markdown formatting).
113
+
114
+ ---
115
+
116
+ Made with ❀️ to save developers' nerves!
117
+
118
+ ---
119
+ 🌍 **Languages:** [Русский](docs/README_ru.md) | [Deutsch](docs/README_de.md)
@@ -0,0 +1,243 @@
1
+ import sys
2
+ import traceback
3
+ import os
4
+ import re
5
+
6
+ def debug():
7
+ """Π­Ρ‚Ρƒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ Π½ΡƒΠΆΠ½ΠΎ Π²Ρ‹Π·Π²Π°Ρ‚ΡŒ Π² Π½Π°Ρ‡Π°Π»Π΅ ΠΊΠΎΠ΄Π°: WhyCrash.debug() (Π“Π›ΠžΠ‘ΠΠ›Π¬ΠΠ«Π™ ΠŸΠ•Π Π•Π₯ВАВ)"""
8
+ start_debug()
9
+
10
+ def start_debug():
11
+ """Π’ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ AI-Π°Π½Π°Π»ΠΈΠ· ошибок для всСго ΠΏΠΎΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π³ΠΎ ΠΊΠΎΠ΄Π°"""
12
+ if not hasattr(sys, 'ps1'):
13
+ sys.excepthook = _ai_excepthook
14
+
15
+ def end_debug():
16
+ """Π’Ρ‹ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ AI-Π°Π½Π°Π»ΠΈΠ· ошибок (Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ стандартноС ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ Python)"""
17
+ if sys.excepthook == _ai_excepthook:
18
+ sys.excepthook = sys.__excepthook__
19
+
20
+ import contextlib
21
+ import functools
22
+
23
+ @contextlib.contextmanager
24
+ def catch_block():
25
+ """ΠšΠΎΠ½Ρ‚Π΅ΠΊΡΡ‚Π½Ρ‹ΠΉ ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€ для ΠΏΠ΅Ρ€Π΅Ρ…Π²Π°Ρ‚Π° ошибок Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½ΠΎΠΌ Π±Π»ΠΎΠΊΠ΅ ΠΊΠΎΠ΄Π°"""
26
+ try:
27
+ yield
28
+ except Exception:
29
+ _ai_excepthook(*sys.exc_info())
30
+ sys.exit(1)
31
+
32
+ def catch_errors(func):
33
+ """Π”Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€ для ΠΏΠ΅Ρ€Π΅Ρ…Π²Π°Ρ‚Π° ошибок Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ"""
34
+ @functools.wraps(func)
35
+ def wrapper(*args, **kwargs):
36
+ try:
37
+ return func(*args, **kwargs)
38
+ except Exception:
39
+ _ai_excepthook(*sys.exc_info())
40
+ sys.exit(1)
41
+ return wrapper
42
+
43
+ def _ai_excepthook(exc_type, exc_value, exc_traceback):
44
+ try:
45
+ import requests
46
+ import json
47
+ except ImportError:
48
+ print("Для Ρ€Π°Π±ΠΎΡ‚Ρ‹ WhyCrash Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ ΠΏΠ°ΠΊΠ΅Ρ‚ 'requests': pip install requests")
49
+ sys.__excepthook__(exc_type, exc_value, exc_traceback)
50
+ return
51
+
52
+ try:
53
+ from rich.console import Console
54
+ from rich.markdown import Markdown
55
+ from rich.panel import Panel
56
+ RICH = True
57
+ console = Console()
58
+ except ImportError:
59
+ RICH = False
60
+
61
+ RED = '\033[91m'
62
+ GREEN = '\033[92m'
63
+ YELLOW = '\033[93m'
64
+ CYAN = '\033[96m'
65
+ RESET = '\033[0m'
66
+
67
+ if RICH:
68
+ console.print(Panel("Oops! ΠŸΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка. WhyCrash собираСт контСкст ΠΈ Π°Π½Π°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅Ρ‚ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡƒ...", border_style="bold red", expand=False))
69
+ else:
70
+ print(f"\n{RED}Oops! ΠŸΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка. WhyCrash собираСт контСкст ΠΈ Π°Π½Π°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅Ρ‚ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡƒ...{RESET}\n")
71
+
72
+ tb_lines = traceback.format_exception(exc_type, exc_value, exc_traceback)
73
+ tb_text = "".join(tb_lines)
74
+
75
+ local_files = {}
76
+ deepest_file = None
77
+ deepest_line = 0
78
+
79
+ tb = exc_traceback
80
+ while tb:
81
+ filename = tb.tb_frame.f_code.co_filename
82
+ lineno = tb.tb_lineno
83
+ deepest_file = filename
84
+ deepest_line = lineno
85
+
86
+ if isinstance(filename, str) and os.path.exists(filename):
87
+ if 'site-packages' not in filename and 'lib\\python' not in filename.lower() and 'lib/python' not in filename.lower():
88
+ if filename not in local_files:
89
+ try:
90
+ with open(filename, 'r', encoding='utf-8') as f:
91
+ local_files[filename] = f.read()
92
+ except Exception:
93
+ pass
94
+ tb = tb.tb_next
95
+
96
+ context_str = ""
97
+ for fpath, code in local_files.items():
98
+ context_str += f"### Π€Π°ΠΉΠ»: {fpath} ###\n```python\n{code}\n```\n\n"
99
+
100
+ first_prompt = f"""ΠŸΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка Π² Python ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΈ.
101
+ Π˜ΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ Π²Ρ‹Π·Π²Π°Π½ΠΎ Π² Ρ„Π°ΠΉΠ»Π΅ '{deepest_file}' Π½Π° строкС {deepest_line}.
102
+
103
+ Traceback:
104
+ {tb_text}
105
+
106
+ Π˜ΡΡ…ΠΎΠ΄Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ контСкстных Ρ„Π°ΠΉΠ»ΠΎΠ² (Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ‚Π΅, Ρ‡Ρ‚ΠΎ относятся ΠΊ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Ρƒ):
107
+ {context_str}
108
+
109
+ ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΏΡ€ΠΎΠ°Π½Π°Π»ΠΈΠ·ΠΈΡ€ΡƒΠΉ эту ΠΎΡˆΠΈΠ±ΠΊΡƒ ΠΈ Π΄Π΅Ρ‚Π°Π»ΡŒΠ½ΠΎ объясни Π½Π° русском языкС, ΠΏΠΎΡ‡Π΅ΠΌΡƒ ΠΎΠ½Π° ΠΏΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π°.
110
+ Пока Ρ‡Ρ‚ΠΎ НЕ пиши исправлСнный ΠΊΠΎΠ΄, Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΏΡ€ΠΎΠ°Π½Π°Π»ΠΈΠ·ΠΈΡ€ΡƒΠΉ ΠΈ объясни ΠΏΡ€ΠΈΡ‡ΠΈΠ½Ρƒ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹."""
111
+
112
+ API_KEY = "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"
113
+
114
+ # ========= ΠŸΠ•Π Π’Π«Π™ Π—ΠΠŸΠ ΠžΠ‘ К OPENROUTER =========
115
+ messages = [{"role": "user", "content": first_prompt}]
116
+
117
+ try:
118
+ response = requests.post(
119
+ url="https://openrouter.ai/api/v1/chat/completions",
120
+ headers={
121
+ "Authorization": f"Bearer {API_KEY}",
122
+ "Content-Type": "application/json",
123
+ },
124
+ data=json.dumps({
125
+ "model": "minimax/minimax-m2.5",
126
+ "messages": messages,
127
+ "reasoning": {"enabled": True}
128
+ })
129
+ )
130
+ response.raise_for_status()
131
+ resp_json = response.json()
132
+ assistant_message = resp_json['choices'][0]['message']
133
+
134
+ reasoning = assistant_message.get('reasoning_details') or ""
135
+ content = assistant_message.get('content') or ""
136
+
137
+ if RICH:
138
+ if reasoning:
139
+ console.print(Panel(Markdown(f"**ΠœΡ‹ΡΠ»ΠΈ (Reasoning):**\n\n{reasoning}"), title="AI ΠžΠ±Π΄ΡƒΠΌΡ‹Π²Π°Π΅Ρ‚", border_style="cyan"))
140
+ console.print(Panel(Markdown(content), title="Анализ ошибки", border_style="yellow"))
141
+ else:
142
+ print(f"{CYAN}============== Знания ΠΈ Анализ (Minimax) =============={RESET}\n")
143
+ if reasoning:
144
+ print(f"{CYAN}--- Π Π°Π·ΠΌΡ‹ΡˆΠ»Π΅Π½ΠΈΡ ---{RESET}\n{reasoning}\n")
145
+ print(f"{YELLOW}--- ОбъяснСниС ---{RESET}\n{content}\n")
146
+ print(f"{CYAN}======================================================={RESET}\n")
147
+
148
+ # ΠŸΡ€ΠΎΡΠΈΠΌ Ρƒ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ ΠΏΠΎΠ΄Ρ‚Π²Π΅Ρ€ΠΆΠ΄Π΅Π½ΠΈΠ΅
149
+ try:
150
+ import questionary
151
+ answer = questionary.select(
152
+ "Π₯ΠΎΡ‚ΠΈΡ‚Π΅, Ρ‡Ρ‚ΠΎΠ±Ρ‹ WhyCrash исправил эту ΠΎΡˆΠΈΠ±ΠΊΡƒ?",
153
+ choices=["Π”Π°", "НСт"]
154
+ ).ask()
155
+ if answer != "Π”Π°":
156
+ print(f"{YELLOW}ΠžΡ‚ΠΌΠ΅Π½Π΅Π½ΠΎ. Π’Ρ‹Ρ…ΠΎΠ΄ΠΈΠΌ...{RESET}")
157
+ sys.exit(1)
158
+ except ImportError:
159
+ answer = input(f"{GREEN}Π₯ΠΎΡ‚ΠΈΡ‚Π΅, Ρ‡Ρ‚ΠΎΠ±Ρ‹ WhyCrash исправил эту ΠΎΡˆΠΈΠ±ΠΊΡƒ? (y/n, enter=yes): {RESET}")
160
+ if answer.strip().lower() not in ('', 'y', 'yes', 'Π΄Π°', 'Π΄'):
161
+ print(f"{YELLOW}ΠžΡ‚ΠΌΠ΅Π½Π΅Π½ΠΎ. Π’Ρ‹Ρ…ΠΎΠ΄ΠΈΠΌ...{RESET}")
162
+ sys.exit(1)
163
+
164
+ # ========= Π’Π’ΠžΠ ΠžΠ™ Π—ΠΠŸΠ ΠžΠ‘ К OPENROUTER (ΠŸΠ ΠžΠ”ΠžΠ›Π–ΠΠ•Πœ Π ΠΠ—ΠœΠ«Π¨Π›Π•ΠΠ˜Π―) =========
165
+ if RICH:
166
+ console.print(f"[bold green]Π“Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠ΅ΠΌ исправлСниС...[/bold green]")
167
+ else:
168
+ print(f"\n{GREEN}Π“Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠ΅ΠΌ исправлСниС...{RESET}")
169
+
170
+ messages.append({
171
+ "role": "assistant",
172
+ "content": content,
173
+ "reasoning_details": reasoning
174
+ })
175
+
176
+ second_prompt = """Напиши ΠŸΠžΠ›ΠΠ«Π™ исправлСнный ΠΊΠΎΠ΄ для Ρ„Π°ΠΉΠ»Π°, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ Π½ΡƒΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ измСнСния.
177
+ Π’ΠΠ–ΠΠž: Π’Ρ‹Π²Π΅Π΄ΠΈ исправлСнный ΠΊΠΎΠ΄ Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΎΠ΄Π½ΠΎΠ³ΠΎ Π±Π»ΠΎΠΊΠ° ```python ... ```.
178
+ НСпосрСдствСнно ΠΏΠ΅Ρ€Π΅Π΄ Π±Π»ΠΎΠΊΠΎΠΌ ΠΊΠΎΠ΄Π° напиши пустой ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ ΠΈΠ»ΠΈ строку, ΡƒΠΊΠ°Π·Ρ‹Π²Π°ΡŽΡ‰ΡƒΡŽ ΠΊΠ°ΠΊΠΎΠΉ Ρ„Π°ΠΉΠ» Ρ‚Ρ‹ ΠΈΡΠΏΡ€Π°Π²Π»ΡΠ΅ΡˆΡŒ, Π² Ρ‚Π°ΠΊΠΎΠΌ Ρ‚ΠΎΡ‡Π½ΠΎΠΌ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π΅:
179
+ FILE_TO_FIX: <ΠΏΠΎΠ»Π½Ρ‹ΠΉ_ΠΏΡƒΡ‚ΡŒ_ΠΊ_Ρ„Π°ΠΉΠ»Ρƒ>
180
+ Π’Ρ‹Π²ΠΎΠ΄ΠΈ вСсь Ρ„Π°ΠΉΠ» Ρ†Π΅Π»ΠΈΠΊΠΎΠΌ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ я ΠΌΠΎΠ³ ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ Π·Π°ΠΌΠ΅Π½ΠΈΡ‚ΡŒ старый Ρ„Π°ΠΉΠ»."""
181
+
182
+ messages.append({"role": "user", "content": second_prompt})
183
+
184
+ response2 = requests.post(
185
+ url="https://openrouter.ai/api/v1/chat/completions",
186
+ headers={
187
+ "Authorization": f"Bearer {API_KEY}",
188
+ "Content-Type": "application/json",
189
+ },
190
+ data=json.dumps({
191
+ "model": "minimax/minimax-m2.5",
192
+ "messages": messages,
193
+ "reasoning": {"enabled": True}
194
+ })
195
+ )
196
+ response2.raise_for_status()
197
+ resp_json2 = response2.json()
198
+ assistant_message2 = resp_json2['choices'][0]['message']
199
+
200
+ content2 = assistant_message2.get('content') or ""
201
+
202
+ # ΠŸΠ°Ρ€ΡΠΈΠΌ ΠΎΡ‚Π²Π΅Ρ‚
203
+ file_to_fix = deepest_file
204
+ match_file = re.search(r"FILE_TO_FIX:\s*(.*)", content2)
205
+ if match_file:
206
+ file_to_fix = match_file.group(1).strip()
207
+
208
+ parts = content2.split("```python")
209
+ if len(parts) > 1:
210
+ last_block = parts[-1].split("```")[0]
211
+ fixed_code = last_block.strip()
212
+
213
+ if os.path.exists(file_to_fix):
214
+ try:
215
+ with open(file_to_fix, 'w', encoding='utf-8') as f:
216
+ f.write(fixed_code + '\n')
217
+ if RICH:
218
+ console.print(f"[bold green][+] Π€Π°ΠΉΠ» '{file_to_fix}' ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ исправлСн! ЗапуститС скрипт Π·Π°Π½ΠΎΠ²ΠΎ.[/bold green]")
219
+ else:
220
+ print(f"{GREEN}\n[+] Π€Π°ΠΉΠ» '{file_to_fix}' ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ исправлСн! ЗапуститС скрипт Π·Π°Π½ΠΎΠ²ΠΎ.{RESET}")
221
+ except Exception as e:
222
+ if RICH:
223
+ console.print(f"[bold red][-] НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ Π·Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ Ρ„Π°ΠΉΠ»: {e}[/bold red]")
224
+ else:
225
+ print(f"{RED}\n[-] НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ Π·Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ Ρ„Π°ΠΉΠ»: {e}{RESET}")
226
+ else:
227
+ if RICH:
228
+ console.print(f"[bold red]НС Π½Π°ΠΉΠ΄Π΅Π½ Ρ„Π°ΠΉΠ» для исправлСния: {file_to_fix}[/bold red]")
229
+ else:
230
+ print(f"\n{RED}НС Π½Π°ΠΉΠ΄Π΅Π½ Ρ„Π°ΠΉΠ» для исправлСния: {file_to_fix}{RESET}")
231
+ else:
232
+ if RICH:
233
+ console.print(f"[bold yellow]Код для исправлСния Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½ Π² ΠΎΡ‚Π²Π΅Ρ‚Π΅.[/bold yellow]")
234
+ else:
235
+ print(f"\n{YELLOW}Код для исправлСния Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½ Π² ΠΎΡ‚Π²Π΅Ρ‚Π΅.{RESET}")
236
+
237
+ except Exception as e:
238
+ if RICH:
239
+ console.print(f"[bold red]ΠžΠ¨Π˜Π‘ΠšΠ WhyCrash API: {e}[/bold red]")
240
+ else:
241
+ print(f"{RED}ΠžΠ¨Π˜Π‘ΠšΠ WhyCrash API: {e}{RESET}")
242
+ print("\nΠžΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½Ρ‹ΠΉ Traceback:")
243
+ print(tb_text)
@@ -0,0 +1,140 @@
1
+ Metadata-Version: 2.4
2
+ Name: WhyCrash
3
+ Version: 1.0.0
4
+ Summary: A highly automatic AI error handler and code fixer using OpenRouter and Minimax.
5
+ Home-page: https://github.com/yourusername/WhyCrash
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Classifier: Operating System :: OS Independent
9
+ Requires-Python: >=3.8
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: requests
12
+ Requires-Dist: rich
13
+ Requires-Dist: questionary
14
+ Dynamic: classifier
15
+ Dynamic: description
16
+ Dynamic: description-content-type
17
+ Dynamic: home-page
18
+ Dynamic: requires-dist
19
+ Dynamic: requires-python
20
+ Dynamic: summary
21
+
22
+ # πŸš€ WhyCrash
23
+ **WhyCrash** is a fully automatic AI assistant for error handling in Python. When your code crashes, WhyCrash intercepts the error, analyzes it using neural networks (OpenRouter + Minimax), gathers context from your local project files, and provides the cause along with an **AUTOMATIC CODE FIX**.
24
+
25
+ Did your code crash? The AI will explain why and automatically replace the broken file with the fixed one (if you allow it).
26
+
27
+ ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)
28
+ ![Python Versions](https://img.shields.io/badge/python-3.8%2B-blue)
29
+
30
+ ## ✨ Main Features
31
+ - 🧠 **Smart Traceback Analysis**: Understands not just the line with the error but also gathers imported local project files.
32
+ - πŸ› οΈ **Auto-Fixing**: Proposes a ready-made fix and can rewrite the target Python files itself.
33
+ - 🎯 **Precise Control**: You decide where to catch errors: in the entire project, in a single function, or in a specific block of code.
34
+ - 🎨 **Beautiful Interface**: Uses the `rich` library for nice windows and terminal formatting.
35
+
36
+ ---
37
+
38
+ ## πŸ“¦ Installation
39
+
40
+ ```bash
41
+ pip install WhyCrash
42
+ ```
43
+ > *(Requires `requests`, `rich`, and `questionary` β€” they will install automatically)*
44
+
45
+ ---
46
+
47
+ ## πŸ› οΈ How to Use
48
+
49
+ You have 4 ways to control which errors WhyCrash should catch. Choose the one that fits best!
50
+
51
+ ### 1. Global Intercept (Easiest)
52
+ If you want **any** unhandled error in your program to be analyzed by the AI:
53
+
54
+ ```python
55
+ import WhyCrash
56
+
57
+ # Enable error catching for the whole script
58
+ WhyCrash.debug()
59
+
60
+ # If the code crashes below, WhyCrash comes to the rescue!
61
+ print(1 / 0)
62
+ ```
63
+
64
+ ### 2. Dynamic Toggle (start & end)
65
+ If you have a large block of code and want to turn on smart analysis right before it, and turn it off right after:
66
+
67
+ ```python
68
+ import WhyCrash
69
+
70
+ # ... normal code without WhyCrash ...
71
+
72
+ WhyCrash.start_debug() # Turn on the interceptor
73
+
74
+ a = "text"
75
+ b = int(a) # <-- This error will go to the AI!
76
+
77
+ WhyCrash.end_debug() # Turn off the interceptor (returns to standard behavior)
78
+ ```
79
+
80
+ ### 3. Decorator for Specific Functions `@catch_errors`
81
+ If you are only concerned about the reliability of a specific function, you can wrap it in a decorator. If the function crashes, WhyCrash will trigger, while system errors outside of it remain untouched.
82
+
83
+ ```python
84
+ from WhyCrash import catch_errors
85
+
86
+ @catch_errors
87
+ def my_danger_function():
88
+ # If it breaks here β€” WhyCrash will trigger
89
+ file = open("no_exist.txt", "r")
90
+
91
+ def normal_function():
92
+ # And if it breaks here β€” standard Python traceback
93
+ pass
94
+
95
+ my_danger_function()
96
+ ```
97
+
98
+ ### 4. Context Manager `with catch_block()`
99
+ For the most precise control, if you expect a failure in literally 2 specific lines of code:
100
+
101
+ ```python
102
+ from WhyCrash import catch_block
103
+
104
+ print("Starting work...")
105
+ text = "100"
106
+
107
+ with catch_block():
108
+ # Only code inside this block is monitored
109
+ number = int(text)
110
+ result = number / 0 # This will trigger an error sent to WhyCrash!
111
+
112
+ print("This code will not execute if there was an error above.")
113
+ ```
114
+
115
+ ---
116
+
117
+ ## πŸ›‘ How to Ignore Error Catching?
118
+ WhyCrash only analyzes **unhandled** exceptions. If you want an error in your code **not** to reach WhyCrash and the script to keep running, simply use a standard `try...except` block:
119
+
120
+ ```python
121
+ import WhyCrash
122
+ WhyCrash.debug()
123
+
124
+ try:
125
+ int("letter")
126
+ except ValueError:
127
+ print("Error caught, it won't reach WhyCrash. Moving on!")
128
+ ```
129
+
130
+ ## βš™οΈ Under the Hood
131
+ - **OpenRouter & Minimax** β€” Responsible for code analysis, "Reasoning," and generating fix files.
132
+ - **Traceback Walking** β€” The script automatically follows the error chain, finds all your `.py` files involved, reads them, and sends them to the AI as context.
133
+ - **Rich** β€” Beautiful console UI (colors, panels, Markdown formatting).
134
+
135
+ ---
136
+
137
+ Made with ❀️ to save developers' nerves!
138
+
139
+ ---
140
+ 🌍 **Languages:** [Русский](docs/README_ru.md) | [Deutsch](docs/README_de.md)
@@ -0,0 +1,8 @@
1
+ README.md
2
+ setup.py
3
+ WhyCrash/__init__.py
4
+ WhyCrash.egg-info/PKG-INFO
5
+ WhyCrash.egg-info/SOURCES.txt
6
+ WhyCrash.egg-info/dependency_links.txt
7
+ WhyCrash.egg-info/requires.txt
8
+ WhyCrash.egg-info/top_level.txt
@@ -0,0 +1,3 @@
1
+ requests
2
+ rich
3
+ questionary
@@ -0,0 +1 @@
1
+ WhyCrash
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,25 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ with open("README.md", "r", encoding="utf-8") as fh:
4
+ long_description = fh.read()
5
+
6
+ setup(
7
+ name='WhyCrash',
8
+ version='1.0.0',
9
+ packages=find_packages(),
10
+ install_requires=[
11
+ 'requests',
12
+ 'rich',
13
+ 'questionary',
14
+ ],
15
+ description='A highly automatic AI error handler and code fixer using OpenRouter and Minimax.',
16
+ long_description=long_description,
17
+ long_description_content_type='text/markdown',
18
+ url='https://github.com/yourusername/WhyCrash', # Update this when you have a github repo
19
+ classifiers=[
20
+ 'Programming Language :: Python :: 3',
21
+ 'License :: OSI Approved :: MIT License',
22
+ 'Operating System :: OS Independent',
23
+ ],
24
+ python_requires='>=3.8',
25
+ )