error-translator-cli-v2 1.1.4__tar.gz → 2.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.
- {error_translator_cli_v2-1.1.4 → error_translator_cli_v2-2.0.0}/PKG-INFO +42 -13
- {error_translator_cli_v2-1.1.4 → error_translator_cli_v2-2.0.0}/README.md +31 -3
- {error_translator_cli_v2-1.1.4 → error_translator_cli_v2-2.0.0}/pyproject.toml +31 -10
- error_translator_cli_v2-2.0.0/src/error_translator/cli.py +265 -0
- {error_translator_cli_v2-1.1.4 → error_translator_cli_v2-2.0.0/src}/error_translator/core.py +50 -23
- {error_translator_cli_v2-1.1.4 → error_translator_cli_v2-2.0.0/src}/error_translator_cli_v2.egg-info/PKG-INFO +42 -13
- error_translator_cli_v2-2.0.0/src/error_translator_cli_v2.egg-info/SOURCES.txt +15 -0
- {error_translator_cli_v2-1.1.4 → error_translator_cli_v2-2.0.0}/tests/test_core.py +22 -0
- error_translator_cli_v2-1.1.4/error_translator/ast_handlers.py +0 -50
- error_translator_cli_v2-1.1.4/error_translator/cli.py +0 -178
- error_translator_cli_v2-1.1.4/error_translator/server.py +0 -47
- error_translator_cli_v2-1.1.4/error_translator/static/index.html +0 -78
- error_translator_cli_v2-1.1.4/error_translator/static/style.css +0 -93
- error_translator_cli_v2-1.1.4/error_translator_cli_v2.egg-info/SOURCES.txt +0 -19
- {error_translator_cli_v2-1.1.4 → error_translator_cli_v2-2.0.0}/LICENSE +0 -0
- {error_translator_cli_v2-1.1.4 → error_translator_cli_v2-2.0.0}/setup.cfg +0 -0
- {error_translator_cli_v2-1.1.4 → error_translator_cli_v2-2.0.0/src}/error_translator/__init__.py +0 -0
- {error_translator_cli_v2-1.1.4 → error_translator_cli_v2-2.0.0/src}/error_translator/auto.py +0 -0
- {error_translator_cli_v2-1.1.4 → error_translator_cli_v2-2.0.0/src}/error_translator/rules.json +0 -0
- {error_translator_cli_v2-1.1.4 → error_translator_cli_v2-2.0.0/src}/error_translator_cli_v2.egg-info/dependency_links.txt +0 -0
- {error_translator_cli_v2-1.1.4 → error_translator_cli_v2-2.0.0/src}/error_translator_cli_v2.egg-info/entry_points.txt +0 -0
- {error_translator_cli_v2-1.1.4 → error_translator_cli_v2-2.0.0/src}/error_translator_cli_v2.egg-info/requires.txt +0 -0
- {error_translator_cli_v2-1.1.4 → error_translator_cli_v2-2.0.0/src}/error_translator_cli_v2.egg-info/top_level.txt +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: error-translator-cli-v2
|
|
3
|
-
Version:
|
|
4
|
-
Summary:
|
|
5
|
-
Author-email: Gourabananda Datta <gourabanandadatta@zohomail.
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Offline Python traceback translator and error explainer CLI that converts exceptions into clear explanations and actionable fixes.
|
|
5
|
+
Author-email: Gourabananda Datta <gourabanandadatta@zohomail.in>
|
|
6
6
|
License: MIT License
|
|
7
7
|
|
|
8
8
|
Copyright (c) 2026 Gourabananda Datta
|
|
@@ -25,13 +25,14 @@ License: MIT License
|
|
|
25
25
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
26
|
SOFTWARE.
|
|
27
27
|
|
|
28
|
-
Project-URL: Homepage, https://github.com/gourabanandad/error-translator
|
|
29
|
-
Project-URL: Source, https://github.com/gourabanandad/error-translator
|
|
30
|
-
Project-URL: Documentation, https://github.
|
|
31
|
-
Project-URL: Issues, https://github.com/gourabanandad/error-translator/issues
|
|
32
|
-
Project-URL: Changelog, https://github.com/gourabanandad/error-translator/releases
|
|
33
|
-
Project-URL: Contributors, https://github.com/gourabanandad/error-translator/graphs/contributors
|
|
34
|
-
|
|
28
|
+
Project-URL: Homepage, https://github.com/gourabanandad/error-translator-cli-v2
|
|
29
|
+
Project-URL: Source, https://github.com/gourabanandad/error-translator-cli-v2
|
|
30
|
+
Project-URL: Documentation, https://gourabanandad.github.io/error-translator-cli-v2/
|
|
31
|
+
Project-URL: Issues, https://github.com/gourabanandad/error-translator-cli-v2/issues
|
|
32
|
+
Project-URL: Changelog, https://github.com/gourabanandad/error-translator-cli-v2/releases
|
|
33
|
+
Project-URL: Contributors, https://github.com/gourabanandad/error-translator-cli-v2/graphs/contributors
|
|
34
|
+
Project-URL: PyPI, https://pypi.org/project/error-translator-cli-v2/
|
|
35
|
+
Keywords: python,python error translator,traceback translator,python traceback analyzer,python exception explainer,error explainer,error handling,debugging,developer tools,stack-trace,cli,terminal,offline,fastapi,human-readable
|
|
35
36
|
Classifier: Development Status :: 4 - Beta
|
|
36
37
|
Classifier: Environment :: Console
|
|
37
38
|
Classifier: Intended Audience :: Developers
|
|
@@ -75,7 +76,7 @@ Dynamic: license-file
|
|
|
75
76
|
|
|
76
77
|
<br>
|
|
77
78
|
|
|
78
|
-
**Error Translator** is
|
|
79
|
+
**Error Translator** is an offline Python traceback translator and exception explainer that converts raw errors into crystal-clear explanations and immediately actionable fixes. Built for local-first development workflows, it supports direct CLI usage, an automatic import hook, a programmatic Python API, and a FastAPI integration.
|
|
79
80
|
|
|
80
81
|
If this project saves you debugging time, please consider starring it on GitHub: https://github.com/gourabanandad/error-translator-cli-v2
|
|
81
82
|
|
|
@@ -89,9 +90,11 @@ If this project saves you debugging time, please consider starring it on GitHub:
|
|
|
89
90
|
## Key Features
|
|
90
91
|
|
|
91
92
|
* **CLI-First Architecture**: Seamlessly process scripts, direct error strings, or piped logs via the `explain-error` command.
|
|
93
|
+
* **Professional Rich Terminal UI**: Clean panels, syntax-highlighted code context, structured sections, and improved readability for day-to-day debugging.
|
|
92
94
|
* **Automatic Integration Mode**: Inject the module via `import error_translator.auto` to automatically override `sys.excepthook` for graceful, translated crash reporting.
|
|
93
95
|
* **Extensible API Surfaces**: Integrate natively within Python or expose the core engine over HTTP via the included FastAPI server.
|
|
94
96
|
* **Deterministic Rules Engine**: High-performance, regex-based matching powered by `rules.json` guarantees offline and privacy-first translations.
|
|
97
|
+
* **Optional Native Acceleration**: A C extension matcher (`fast_matcher`) can accelerate rule scanning, with automatic fallback to pure Python when unavailable.
|
|
95
98
|
* **Optional AST Insight Hooks**: Registered handlers can append targeted hints (`ast_insight`) for selected error types.
|
|
96
99
|
|
|
97
100
|
## Installation
|
|
@@ -129,6 +132,19 @@ Pipe system or Docker logs into the engine:
|
|
|
129
132
|
cat error.log | explain-error
|
|
130
133
|
```
|
|
131
134
|
|
|
135
|
+
Emit structured JSON for scripting and automation:
|
|
136
|
+
```bash
|
|
137
|
+
explain-error --json "NameError: name 'x' is not defined"
|
|
138
|
+
# {"explanation": "...", "fix": "...", "matched_error": "...", "file": "...", "line": "...", "code": "...", "ast_insight": null}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Show an about screen with project metadata and quick usage examples:
|
|
142
|
+
```bash
|
|
143
|
+
explain-error --about
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The `--json` flag works with every input mode (`run <script>`, raw string, piped log).
|
|
147
|
+
|
|
132
148
|
### 2. Automatic Import Hook
|
|
133
149
|
|
|
134
150
|
Catch and translate unhandled exceptions globally by importing the module:
|
|
@@ -149,7 +165,7 @@ if __name__ == "__main__":
|
|
|
149
165
|
Start the built-in HTTP server for remote translation services:
|
|
150
166
|
|
|
151
167
|
```bash
|
|
152
|
-
uvicorn error_translator.server:app --host 127.0.0.1 --port 8000 --reload
|
|
168
|
+
uvicorn error_translator.api.server:app --host 127.0.0.1 --port 8000 --reload
|
|
153
169
|
```
|
|
154
170
|
|
|
155
171
|
Submit a traceback payload via the exposed REST API:
|
|
@@ -163,7 +179,20 @@ curl -X POST http://127.0.0.1:8000/translate \
|
|
|
163
179
|
Additional endpoints:
|
|
164
180
|
|
|
165
181
|
- `GET /health` returns service status.
|
|
166
|
-
- `GET /` serves the bundled web UI from `error_translator/static/index.html`.
|
|
182
|
+
- `GET /` serves the bundled web UI from `error_translator/api/static/index.html`.
|
|
183
|
+
|
|
184
|
+
### 4. Optional C Extension Build
|
|
185
|
+
|
|
186
|
+
The translation engine automatically attempts to import `error_translator.fast_matcher`.
|
|
187
|
+
If it is not built or not available on the platform, Error Translator falls back to the pure Python regex loop with no behavior change.
|
|
188
|
+
|
|
189
|
+
Build the extension in-place from the repository root:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
python setup_ext.py build_ext --inplace
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
This step is optional and intended for local performance optimization.
|
|
167
196
|
|
|
168
197
|
## Documentation
|
|
169
198
|
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
<br>
|
|
13
13
|
|
|
14
|
-
**Error Translator** is
|
|
14
|
+
**Error Translator** is an offline Python traceback translator and exception explainer that converts raw errors into crystal-clear explanations and immediately actionable fixes. Built for local-first development workflows, it supports direct CLI usage, an automatic import hook, a programmatic Python API, and a FastAPI integration.
|
|
15
15
|
|
|
16
16
|
If this project saves you debugging time, please consider starring it on GitHub: https://github.com/gourabanandad/error-translator-cli-v2
|
|
17
17
|
|
|
@@ -25,9 +25,11 @@ If this project saves you debugging time, please consider starring it on GitHub:
|
|
|
25
25
|
## Key Features
|
|
26
26
|
|
|
27
27
|
* **CLI-First Architecture**: Seamlessly process scripts, direct error strings, or piped logs via the `explain-error` command.
|
|
28
|
+
* **Professional Rich Terminal UI**: Clean panels, syntax-highlighted code context, structured sections, and improved readability for day-to-day debugging.
|
|
28
29
|
* **Automatic Integration Mode**: Inject the module via `import error_translator.auto` to automatically override `sys.excepthook` for graceful, translated crash reporting.
|
|
29
30
|
* **Extensible API Surfaces**: Integrate natively within Python or expose the core engine over HTTP via the included FastAPI server.
|
|
30
31
|
* **Deterministic Rules Engine**: High-performance, regex-based matching powered by `rules.json` guarantees offline and privacy-first translations.
|
|
32
|
+
* **Optional Native Acceleration**: A C extension matcher (`fast_matcher`) can accelerate rule scanning, with automatic fallback to pure Python when unavailable.
|
|
31
33
|
* **Optional AST Insight Hooks**: Registered handlers can append targeted hints (`ast_insight`) for selected error types.
|
|
32
34
|
|
|
33
35
|
## Installation
|
|
@@ -65,6 +67,19 @@ Pipe system or Docker logs into the engine:
|
|
|
65
67
|
cat error.log | explain-error
|
|
66
68
|
```
|
|
67
69
|
|
|
70
|
+
Emit structured JSON for scripting and automation:
|
|
71
|
+
```bash
|
|
72
|
+
explain-error --json "NameError: name 'x' is not defined"
|
|
73
|
+
# {"explanation": "...", "fix": "...", "matched_error": "...", "file": "...", "line": "...", "code": "...", "ast_insight": null}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Show an about screen with project metadata and quick usage examples:
|
|
77
|
+
```bash
|
|
78
|
+
explain-error --about
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The `--json` flag works with every input mode (`run <script>`, raw string, piped log).
|
|
82
|
+
|
|
68
83
|
### 2. Automatic Import Hook
|
|
69
84
|
|
|
70
85
|
Catch and translate unhandled exceptions globally by importing the module:
|
|
@@ -85,7 +100,7 @@ if __name__ == "__main__":
|
|
|
85
100
|
Start the built-in HTTP server for remote translation services:
|
|
86
101
|
|
|
87
102
|
```bash
|
|
88
|
-
uvicorn error_translator.server:app --host 127.0.0.1 --port 8000 --reload
|
|
103
|
+
uvicorn error_translator.api.server:app --host 127.0.0.1 --port 8000 --reload
|
|
89
104
|
```
|
|
90
105
|
|
|
91
106
|
Submit a traceback payload via the exposed REST API:
|
|
@@ -99,7 +114,20 @@ curl -X POST http://127.0.0.1:8000/translate \
|
|
|
99
114
|
Additional endpoints:
|
|
100
115
|
|
|
101
116
|
- `GET /health` returns service status.
|
|
102
|
-
- `GET /` serves the bundled web UI from `error_translator/static/index.html`.
|
|
117
|
+
- `GET /` serves the bundled web UI from `error_translator/api/static/index.html`.
|
|
118
|
+
|
|
119
|
+
### 4. Optional C Extension Build
|
|
120
|
+
|
|
121
|
+
The translation engine automatically attempts to import `error_translator.fast_matcher`.
|
|
122
|
+
If it is not built or not available on the platform, Error Translator falls back to the pure Python regex loop with no behavior change.
|
|
123
|
+
|
|
124
|
+
Build the extension in-place from the repository root:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
python setup_ext.py build_ext --inplace
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
This step is optional and intended for local performance optimization.
|
|
103
131
|
|
|
104
132
|
## Documentation
|
|
105
133
|
|
|
@@ -4,15 +4,31 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "error-translator-cli-v2"
|
|
7
|
-
version = "
|
|
8
|
-
description = "
|
|
7
|
+
version = "2.0.0"
|
|
8
|
+
description = "Offline Python traceback translator and error explainer CLI that converts exceptions into clear explanations and actionable fixes."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
11
11
|
license = { file = "LICENSE" }
|
|
12
12
|
authors = [
|
|
13
|
-
{ name = "Gourabananda Datta", email = "gourabanandadatta@zohomail.
|
|
13
|
+
{ name = "Gourabananda Datta", email = "gourabanandadatta@zohomail.in" }
|
|
14
|
+
]
|
|
15
|
+
keywords = [
|
|
16
|
+
"python",
|
|
17
|
+
"python error translator",
|
|
18
|
+
"traceback translator",
|
|
19
|
+
"python traceback analyzer",
|
|
20
|
+
"python exception explainer",
|
|
21
|
+
"error explainer",
|
|
22
|
+
"error handling",
|
|
23
|
+
"debugging",
|
|
24
|
+
"developer tools",
|
|
25
|
+
"stack-trace",
|
|
26
|
+
"cli",
|
|
27
|
+
"terminal",
|
|
28
|
+
"offline",
|
|
29
|
+
"fastapi",
|
|
30
|
+
"human-readable"
|
|
14
31
|
]
|
|
15
|
-
keywords = ["python", "traceback", "cli", "debugging", "error handling", "developer tools"]
|
|
16
32
|
classifiers = [
|
|
17
33
|
"Development Status :: 4 - Beta",
|
|
18
34
|
"Environment :: Console",
|
|
@@ -30,12 +46,13 @@ classifiers = [
|
|
|
30
46
|
]
|
|
31
47
|
|
|
32
48
|
[project.urls]
|
|
33
|
-
"Homepage" = "https://github.com/gourabanandad/error-translator"
|
|
34
|
-
"Source" = "https://github.com/gourabanandad/error-translator"
|
|
35
|
-
"Documentation" = "https://github.
|
|
36
|
-
"Issues" = "https://github.com/gourabanandad/error-translator/issues"
|
|
37
|
-
"Changelog" = "https://github.com/gourabanandad/error-translator/releases"
|
|
38
|
-
"Contributors" = "https://github.com/gourabanandad/error-translator/graphs/contributors"
|
|
49
|
+
"Homepage" = "https://github.com/gourabanandad/error-translator-cli-v2"
|
|
50
|
+
"Source" = "https://github.com/gourabanandad/error-translator-cli-v2"
|
|
51
|
+
"Documentation" = "https://gourabanandad.github.io/error-translator-cli-v2/"
|
|
52
|
+
"Issues" = "https://github.com/gourabanandad/error-translator-cli-v2/issues"
|
|
53
|
+
"Changelog" = "https://github.com/gourabanandad/error-translator-cli-v2/releases"
|
|
54
|
+
"Contributors" = "https://github.com/gourabanandad/error-translator-cli-v2/graphs/contributors"
|
|
55
|
+
"PyPI" = "https://pypi.org/project/error-translator-cli-v2/"
|
|
39
56
|
|
|
40
57
|
[project.scripts]
|
|
41
58
|
explain-error = "error_translator.cli:main"
|
|
@@ -46,7 +63,11 @@ docs = ["mkdocs>=1.6", "mkdocs-material>=9.7", "pymdown-extensions>=10.0"]
|
|
|
46
63
|
dev = ["pytest>=8.0", "build>=1.2", "twine>=5.0"]
|
|
47
64
|
|
|
48
65
|
[tool.setuptools]
|
|
66
|
+
package-dir = {"" = "src"}
|
|
49
67
|
packages = ["error_translator"]
|
|
50
68
|
|
|
69
|
+
[tool.pytest.ini_options]
|
|
70
|
+
pythonpath = ["src"]
|
|
71
|
+
|
|
51
72
|
[tool.setuptools.package-data]
|
|
52
73
|
error_translator = ["rules.json", "static/*.html", "static/*.css"]
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import sys
|
|
3
|
+
import argparse
|
|
4
|
+
from .core import translate_error
|
|
5
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
6
|
+
|
|
7
|
+
# Import Rich UI Components
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
from rich.panel import Panel
|
|
10
|
+
from rich.syntax import Syntax
|
|
11
|
+
from rich.text import Text
|
|
12
|
+
from rich.table import Table
|
|
13
|
+
from rich import box
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
VERSION = version("error-translator-cli-v2")
|
|
17
|
+
except PackageNotFoundError:
|
|
18
|
+
VERSION = "unknown (not installed via pip)"
|
|
19
|
+
|
|
20
|
+
# Initialize the global rich console
|
|
21
|
+
console = Console()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _print_title_banner():
|
|
25
|
+
banner = Text()
|
|
26
|
+
banner.append("Error Translator CLI\n", style="bold bright_magenta")
|
|
27
|
+
banner.append("Translate Python tracebacks into clear, actionable guidance.", style="cyan")
|
|
28
|
+
console.print(
|
|
29
|
+
Panel(
|
|
30
|
+
banner,
|
|
31
|
+
border_style="magenta",
|
|
32
|
+
padding=(1, 2),
|
|
33
|
+
expand=False,
|
|
34
|
+
)
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
def print_about():
|
|
38
|
+
"""Prints a polished about view using rich components."""
|
|
39
|
+
_print_title_banner()
|
|
40
|
+
|
|
41
|
+
meta = Table.grid(padding=(0, 1))
|
|
42
|
+
meta.add_column(style="bold white", justify="right")
|
|
43
|
+
meta.add_column(style="green")
|
|
44
|
+
meta.add_row("Version", VERSION)
|
|
45
|
+
meta.add_row("Author", "Gourabananda Datta")
|
|
46
|
+
meta.add_row("Repository", "https://github.com/gourabanandad/error-translator-cli-v2")
|
|
47
|
+
console.print(Panel(meta, title="[bold cyan]Project[/]", border_style="cyan", expand=False))
|
|
48
|
+
|
|
49
|
+
features = Text()
|
|
50
|
+
features.append("• Offline and fast translation\n", style="white")
|
|
51
|
+
features.append("• Human-readable explanations\n", style="white")
|
|
52
|
+
features.append("• Actionable fix suggestions\n", style="white")
|
|
53
|
+
features.append("• Optional AST-level insight", style="white")
|
|
54
|
+
console.print(Panel(features, title="[bold green]Features[/]", border_style="green", expand=False))
|
|
55
|
+
|
|
56
|
+
examples = Text()
|
|
57
|
+
examples.append("explain-error run your_script.py\n", style="bold cyan")
|
|
58
|
+
examples.append("explain-error \"TypeError: ...\"\n", style="bold cyan")
|
|
59
|
+
examples.append("cat error.log | explain-error", style="bold cyan")
|
|
60
|
+
console.print(Panel(examples, title="[bold yellow]Quick Start[/]", border_style="yellow", expand=False))
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def print_result(result: dict):
|
|
64
|
+
"""Print translated output in a polished, professional layout."""
|
|
65
|
+
console.print()
|
|
66
|
+
|
|
67
|
+
if result.get("error") and not result.get("matched_error"):
|
|
68
|
+
message = result.get("message", "An unexpected error occurred.")
|
|
69
|
+
console.print(
|
|
70
|
+
Panel(
|
|
71
|
+
f"[bold red]{message}[/]",
|
|
72
|
+
title="[bold red]Error[/]",
|
|
73
|
+
border_style="red",
|
|
74
|
+
box=box.ROUNDED,
|
|
75
|
+
expand=False,
|
|
76
|
+
)
|
|
77
|
+
)
|
|
78
|
+
return
|
|
79
|
+
|
|
80
|
+
error_title = result.get("matched_error", "Unknown Error")
|
|
81
|
+
console.print(
|
|
82
|
+
Panel(
|
|
83
|
+
f"[bold white]{error_title}[/]",
|
|
84
|
+
title="[bold red]Detected Error[/]",
|
|
85
|
+
border_style="red",
|
|
86
|
+
box=box.ROUNDED,
|
|
87
|
+
expand=False,
|
|
88
|
+
)
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
file_name = result.get("file")
|
|
92
|
+
line_no = result.get("line", "?")
|
|
93
|
+
if file_name and file_name != "Unknown File":
|
|
94
|
+
console.print(
|
|
95
|
+
Panel(
|
|
96
|
+
f"[yellow]File:[/] {file_name}\n[yellow]Line:[/] {line_no}",
|
|
97
|
+
title="[bold yellow]Location[/]",
|
|
98
|
+
border_style="yellow",
|
|
99
|
+
box=box.ROUNDED,
|
|
100
|
+
expand=False,
|
|
101
|
+
)
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
if result.get("code"):
|
|
105
|
+
try:
|
|
106
|
+
start_line = int(line_no)
|
|
107
|
+
except (TypeError, ValueError):
|
|
108
|
+
start_line = 1
|
|
109
|
+
|
|
110
|
+
syntax = Syntax(
|
|
111
|
+
result["code"],
|
|
112
|
+
"python",
|
|
113
|
+
theme="monokai",
|
|
114
|
+
line_numbers=True,
|
|
115
|
+
start_line=start_line,
|
|
116
|
+
word_wrap=True,
|
|
117
|
+
)
|
|
118
|
+
console.print(Panel(syntax, title="[bold blue]Code Context[/]", border_style="blue", box=box.ROUNDED))
|
|
119
|
+
|
|
120
|
+
explanation = result.get("explanation", "No explanation available.")
|
|
121
|
+
console.print(
|
|
122
|
+
Panel(
|
|
123
|
+
f"[white]{explanation}[/]",
|
|
124
|
+
title="[bold cyan]Explanation[/]",
|
|
125
|
+
title_align="left",
|
|
126
|
+
border_style="cyan",
|
|
127
|
+
box=box.ROUNDED,
|
|
128
|
+
expand=False,
|
|
129
|
+
)
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
fix = result.get("fix", "No suggested fix available.")
|
|
133
|
+
console.print(
|
|
134
|
+
Panel(
|
|
135
|
+
f"[bold green]{fix}[/]",
|
|
136
|
+
title="[bold green]Suggested Fix[/]",
|
|
137
|
+
title_align="left",
|
|
138
|
+
border_style="green",
|
|
139
|
+
box=box.ROUNDED,
|
|
140
|
+
expand=False,
|
|
141
|
+
)
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
if result.get("ast_insight"):
|
|
145
|
+
console.print(
|
|
146
|
+
Panel(
|
|
147
|
+
f"[white]{result['ast_insight']}[/]",
|
|
148
|
+
title="[bold magenta]AST Insight[/]",
|
|
149
|
+
title_align="left",
|
|
150
|
+
border_style="magenta",
|
|
151
|
+
box=box.ROUNDED,
|
|
152
|
+
expand=False,
|
|
153
|
+
)
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def print_result_json(result: dict):
|
|
158
|
+
"""Prints the translated error as a single-line JSON object on stdout."""
|
|
159
|
+
print(json.dumps(result, ensure_ascii=False))
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def run_script(script_name: str, *, as_json: bool = False):
|
|
163
|
+
"""Run a Python script and translate traceback output if it fails."""
|
|
164
|
+
import subprocess
|
|
165
|
+
try:
|
|
166
|
+
result = subprocess.run(
|
|
167
|
+
[sys.executable, script_name],
|
|
168
|
+
capture_output=True,
|
|
169
|
+
text=True
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
if result.returncode == 0:
|
|
173
|
+
print(result.stdout, end="")
|
|
174
|
+
else:
|
|
175
|
+
if result.stdout:
|
|
176
|
+
print(result.stdout, end="")
|
|
177
|
+
|
|
178
|
+
translation = translate_error(result.stderr)
|
|
179
|
+
if as_json:
|
|
180
|
+
print_result_json(translation)
|
|
181
|
+
else:
|
|
182
|
+
print_result(translation)
|
|
183
|
+
|
|
184
|
+
except FileNotFoundError:
|
|
185
|
+
if as_json:
|
|
186
|
+
print(json.dumps({
|
|
187
|
+
"error": "script_not_found",
|
|
188
|
+
"message": f"Could not find script '{script_name}'",
|
|
189
|
+
}))
|
|
190
|
+
else:
|
|
191
|
+
console.print(
|
|
192
|
+
Panel(
|
|
193
|
+
f"[bold red]Could not find script '{script_name}'[/]",
|
|
194
|
+
title="[bold red]Execution Error[/]",
|
|
195
|
+
border_style="red",
|
|
196
|
+
box=box.ROUNDED,
|
|
197
|
+
expand=False,
|
|
198
|
+
)
|
|
199
|
+
)
|
|
200
|
+
except Exception as exc:
|
|
201
|
+
if as_json:
|
|
202
|
+
print(json.dumps({
|
|
203
|
+
"error": "runtime_failure",
|
|
204
|
+
"message": str(exc),
|
|
205
|
+
}))
|
|
206
|
+
else:
|
|
207
|
+
console.print(
|
|
208
|
+
Panel(
|
|
209
|
+
f"[bold red]{exc}[/]",
|
|
210
|
+
title="[bold red]Runtime Error[/]",
|
|
211
|
+
border_style="red",
|
|
212
|
+
box=box.ROUNDED,
|
|
213
|
+
expand=False,
|
|
214
|
+
)
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
def main():
|
|
218
|
+
parser = argparse.ArgumentParser(
|
|
219
|
+
prog="explain-error",
|
|
220
|
+
description="Error Translator — Turn cryptic Python tracebacks into clear, actionable advice.",
|
|
221
|
+
epilog="""
|
|
222
|
+
Examples:
|
|
223
|
+
explain-error run my_script.py
|
|
224
|
+
explain-error "NameError: name 'usr_count' is not defined"
|
|
225
|
+
cat error.log | explain-error
|
|
226
|
+
""",
|
|
227
|
+
formatter_class=argparse.RawDescriptionHelpFormatter
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
parser.add_argument("-a", "--about", action="store_true", help="Display information about the tool.")
|
|
231
|
+
parser.add_argument("-v", "--version", action="store_true", help="Show the current version of the tool.")
|
|
232
|
+
parser.add_argument("--json", action="store_true", dest="as_json", help="Output the translated error as a JSON object.")
|
|
233
|
+
parser.add_argument("args", nargs="*", help="Positional arguments.")
|
|
234
|
+
|
|
235
|
+
parsed_args = parser.parse_args()
|
|
236
|
+
|
|
237
|
+
if parsed_args.about:
|
|
238
|
+
print_about()
|
|
239
|
+
sys.exit(0)
|
|
240
|
+
|
|
241
|
+
if parsed_args.version:
|
|
242
|
+
console.print(f"Error Translator CLI Version: [bold green]{VERSION}[/]")
|
|
243
|
+
sys.exit(0)
|
|
244
|
+
|
|
245
|
+
emit = print_result_json if parsed_args.as_json else print_result
|
|
246
|
+
|
|
247
|
+
if not sys.stdin.isatty():
|
|
248
|
+
error_input = sys.stdin.read()
|
|
249
|
+
if error_input.strip():
|
|
250
|
+
emit(translate_error(error_input))
|
|
251
|
+
return
|
|
252
|
+
|
|
253
|
+
if not parsed_args.args:
|
|
254
|
+
parser.print_help()
|
|
255
|
+
sys.exit(1)
|
|
256
|
+
|
|
257
|
+
if parsed_args.args[0] == "run" and len(parsed_args.args) > 1:
|
|
258
|
+
script_name = parsed_args.args[1]
|
|
259
|
+
run_script(script_name, as_json=parsed_args.as_json)
|
|
260
|
+
else:
|
|
261
|
+
error_input = " ".join(parsed_args.args)
|
|
262
|
+
emit(translate_error(error_input))
|
|
263
|
+
|
|
264
|
+
if __name__ == "__main__":
|
|
265
|
+
main()
|
{error_translator_cli_v2-1.1.4 → error_translator_cli_v2-2.0.0/src}/error_translator/core.py
RENAMED
|
@@ -3,7 +3,14 @@ import os
|
|
|
3
3
|
import re
|
|
4
4
|
import linecache
|
|
5
5
|
from functools import lru_cache
|
|
6
|
-
from .ast_handlers import AST_REGISTRY
|
|
6
|
+
from .ast.ast_handlers import AST_REGISTRY
|
|
7
|
+
|
|
8
|
+
# Attempt to load the ultra-fast C extension, fallback to Python if unavailable
|
|
9
|
+
try:
|
|
10
|
+
from .fast_matcher import match_loop
|
|
11
|
+
C_EXTENSION_AVAILABLE = True
|
|
12
|
+
except ImportError:
|
|
13
|
+
C_EXTENSION_AVAILABLE = False
|
|
7
14
|
|
|
8
15
|
|
|
9
16
|
@lru_cache(maxsize=1)
|
|
@@ -55,27 +62,47 @@ def translate_error(traceback_text: str) -> dict:
|
|
|
55
62
|
except Exception:
|
|
56
63
|
pass
|
|
57
64
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
65
|
+
# ==========================================
|
|
66
|
+
# FAST MATCHING ENGINE (C Extension + Python Fallback)
|
|
67
|
+
# ==========================================
|
|
68
|
+
match = None
|
|
69
|
+
rule = None
|
|
70
|
+
|
|
71
|
+
if C_EXTENSION_AVAILABLE:
|
|
72
|
+
# Execute the C extension (runs at C speed)
|
|
73
|
+
result = match_loop(actual_error_line, rules)
|
|
74
|
+
if result:
|
|
75
|
+
match, rule = result
|
|
76
|
+
else:
|
|
77
|
+
# Standard Python fallback loop
|
|
78
|
+
for pattern, r in rules:
|
|
79
|
+
m = pattern.search(actual_error_line)
|
|
80
|
+
if m:
|
|
81
|
+
match, rule = m, r
|
|
82
|
+
break
|
|
83
|
+
|
|
84
|
+
if match and rule:
|
|
85
|
+
extracted_values = list(match.groups())
|
|
86
|
+
fix_text = rule["fix"].format(*extracted_values)
|
|
87
|
+
|
|
88
|
+
error_type = actual_error_line.split(":")[0].strip()
|
|
89
|
+
handler_function = AST_REGISTRY.get(error_type)
|
|
90
|
+
insight = None
|
|
91
|
+
|
|
92
|
+
if handler_function and file_name != "Unknown File":
|
|
93
|
+
insight = handler_function(file_name, line_number, extracted_values)
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
"explanation": rule["explanation"].format(*extracted_values),
|
|
97
|
+
"fix": fix_text,
|
|
98
|
+
"ast_insight": insight,
|
|
99
|
+
"matched_error": actual_error_line,
|
|
100
|
+
"file": file_name,
|
|
101
|
+
"line": line_number,
|
|
102
|
+
"code": code_context,
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
# Default fallback when no rules match
|
|
79
106
|
return {
|
|
80
107
|
"explanation": default_error["explanation"],
|
|
81
108
|
"fix": default_error["fix"],
|
|
@@ -83,4 +110,4 @@ def translate_error(traceback_text: str) -> dict:
|
|
|
83
110
|
"file": file_name,
|
|
84
111
|
"line": line_number,
|
|
85
112
|
"code": code_context,
|
|
86
|
-
}
|
|
113
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: error-translator-cli-v2
|
|
3
|
-
Version:
|
|
4
|
-
Summary:
|
|
5
|
-
Author-email: Gourabananda Datta <gourabanandadatta@zohomail.
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Offline Python traceback translator and error explainer CLI that converts exceptions into clear explanations and actionable fixes.
|
|
5
|
+
Author-email: Gourabananda Datta <gourabanandadatta@zohomail.in>
|
|
6
6
|
License: MIT License
|
|
7
7
|
|
|
8
8
|
Copyright (c) 2026 Gourabananda Datta
|
|
@@ -25,13 +25,14 @@ License: MIT License
|
|
|
25
25
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
26
|
SOFTWARE.
|
|
27
27
|
|
|
28
|
-
Project-URL: Homepage, https://github.com/gourabanandad/error-translator
|
|
29
|
-
Project-URL: Source, https://github.com/gourabanandad/error-translator
|
|
30
|
-
Project-URL: Documentation, https://github.
|
|
31
|
-
Project-URL: Issues, https://github.com/gourabanandad/error-translator/issues
|
|
32
|
-
Project-URL: Changelog, https://github.com/gourabanandad/error-translator/releases
|
|
33
|
-
Project-URL: Contributors, https://github.com/gourabanandad/error-translator/graphs/contributors
|
|
34
|
-
|
|
28
|
+
Project-URL: Homepage, https://github.com/gourabanandad/error-translator-cli-v2
|
|
29
|
+
Project-URL: Source, https://github.com/gourabanandad/error-translator-cli-v2
|
|
30
|
+
Project-URL: Documentation, https://gourabanandad.github.io/error-translator-cli-v2/
|
|
31
|
+
Project-URL: Issues, https://github.com/gourabanandad/error-translator-cli-v2/issues
|
|
32
|
+
Project-URL: Changelog, https://github.com/gourabanandad/error-translator-cli-v2/releases
|
|
33
|
+
Project-URL: Contributors, https://github.com/gourabanandad/error-translator-cli-v2/graphs/contributors
|
|
34
|
+
Project-URL: PyPI, https://pypi.org/project/error-translator-cli-v2/
|
|
35
|
+
Keywords: python,python error translator,traceback translator,python traceback analyzer,python exception explainer,error explainer,error handling,debugging,developer tools,stack-trace,cli,terminal,offline,fastapi,human-readable
|
|
35
36
|
Classifier: Development Status :: 4 - Beta
|
|
36
37
|
Classifier: Environment :: Console
|
|
37
38
|
Classifier: Intended Audience :: Developers
|
|
@@ -75,7 +76,7 @@ Dynamic: license-file
|
|
|
75
76
|
|
|
76
77
|
<br>
|
|
77
78
|
|
|
78
|
-
**Error Translator** is
|
|
79
|
+
**Error Translator** is an offline Python traceback translator and exception explainer that converts raw errors into crystal-clear explanations and immediately actionable fixes. Built for local-first development workflows, it supports direct CLI usage, an automatic import hook, a programmatic Python API, and a FastAPI integration.
|
|
79
80
|
|
|
80
81
|
If this project saves you debugging time, please consider starring it on GitHub: https://github.com/gourabanandad/error-translator-cli-v2
|
|
81
82
|
|
|
@@ -89,9 +90,11 @@ If this project saves you debugging time, please consider starring it on GitHub:
|
|
|
89
90
|
## Key Features
|
|
90
91
|
|
|
91
92
|
* **CLI-First Architecture**: Seamlessly process scripts, direct error strings, or piped logs via the `explain-error` command.
|
|
93
|
+
* **Professional Rich Terminal UI**: Clean panels, syntax-highlighted code context, structured sections, and improved readability for day-to-day debugging.
|
|
92
94
|
* **Automatic Integration Mode**: Inject the module via `import error_translator.auto` to automatically override `sys.excepthook` for graceful, translated crash reporting.
|
|
93
95
|
* **Extensible API Surfaces**: Integrate natively within Python or expose the core engine over HTTP via the included FastAPI server.
|
|
94
96
|
* **Deterministic Rules Engine**: High-performance, regex-based matching powered by `rules.json` guarantees offline and privacy-first translations.
|
|
97
|
+
* **Optional Native Acceleration**: A C extension matcher (`fast_matcher`) can accelerate rule scanning, with automatic fallback to pure Python when unavailable.
|
|
95
98
|
* **Optional AST Insight Hooks**: Registered handlers can append targeted hints (`ast_insight`) for selected error types.
|
|
96
99
|
|
|
97
100
|
## Installation
|
|
@@ -129,6 +132,19 @@ Pipe system or Docker logs into the engine:
|
|
|
129
132
|
cat error.log | explain-error
|
|
130
133
|
```
|
|
131
134
|
|
|
135
|
+
Emit structured JSON for scripting and automation:
|
|
136
|
+
```bash
|
|
137
|
+
explain-error --json "NameError: name 'x' is not defined"
|
|
138
|
+
# {"explanation": "...", "fix": "...", "matched_error": "...", "file": "...", "line": "...", "code": "...", "ast_insight": null}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Show an about screen with project metadata and quick usage examples:
|
|
142
|
+
```bash
|
|
143
|
+
explain-error --about
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The `--json` flag works with every input mode (`run <script>`, raw string, piped log).
|
|
147
|
+
|
|
132
148
|
### 2. Automatic Import Hook
|
|
133
149
|
|
|
134
150
|
Catch and translate unhandled exceptions globally by importing the module:
|
|
@@ -149,7 +165,7 @@ if __name__ == "__main__":
|
|
|
149
165
|
Start the built-in HTTP server for remote translation services:
|
|
150
166
|
|
|
151
167
|
```bash
|
|
152
|
-
uvicorn error_translator.server:app --host 127.0.0.1 --port 8000 --reload
|
|
168
|
+
uvicorn error_translator.api.server:app --host 127.0.0.1 --port 8000 --reload
|
|
153
169
|
```
|
|
154
170
|
|
|
155
171
|
Submit a traceback payload via the exposed REST API:
|
|
@@ -163,7 +179,20 @@ curl -X POST http://127.0.0.1:8000/translate \
|
|
|
163
179
|
Additional endpoints:
|
|
164
180
|
|
|
165
181
|
- `GET /health` returns service status.
|
|
166
|
-
- `GET /` serves the bundled web UI from `error_translator/static/index.html`.
|
|
182
|
+
- `GET /` serves the bundled web UI from `error_translator/api/static/index.html`.
|
|
183
|
+
|
|
184
|
+
### 4. Optional C Extension Build
|
|
185
|
+
|
|
186
|
+
The translation engine automatically attempts to import `error_translator.fast_matcher`.
|
|
187
|
+
If it is not built or not available on the platform, Error Translator falls back to the pure Python regex loop with no behavior change.
|
|
188
|
+
|
|
189
|
+
Build the extension in-place from the repository root:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
python setup_ext.py build_ext --inplace
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
This step is optional and intended for local performance optimization.
|
|
167
196
|
|
|
168
197
|
## Documentation
|
|
169
198
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/error_translator/__init__.py
|
|
5
|
+
src/error_translator/auto.py
|
|
6
|
+
src/error_translator/cli.py
|
|
7
|
+
src/error_translator/core.py
|
|
8
|
+
src/error_translator/rules.json
|
|
9
|
+
src/error_translator_cli_v2.egg-info/PKG-INFO
|
|
10
|
+
src/error_translator_cli_v2.egg-info/SOURCES.txt
|
|
11
|
+
src/error_translator_cli_v2.egg-info/dependency_links.txt
|
|
12
|
+
src/error_translator_cli_v2.egg-info/entry_points.txt
|
|
13
|
+
src/error_translator_cli_v2.egg-info/requires.txt
|
|
14
|
+
src/error_translator_cli_v2.egg-info/top_level.txt
|
|
15
|
+
tests/test_core.py
|
|
@@ -147,3 +147,25 @@ def test_regex_extraction_for_supported_errors(mock_traceback, expected_in_expla
|
|
|
147
147
|
# 2. Prove the Context Engine successfully parsed the file location
|
|
148
148
|
assert result["file"] == "script.py"
|
|
149
149
|
assert result["line"] == "5"
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def test_print_result_json_emits_valid_json(capsys):
|
|
153
|
+
"""The --json formatter writes a single line of valid JSON containing the result keys."""
|
|
154
|
+
import json
|
|
155
|
+
from error_translator.cli import print_result_json
|
|
156
|
+
|
|
157
|
+
payload = {
|
|
158
|
+
"explanation": "x is undefined",
|
|
159
|
+
"fix": "Define x before use",
|
|
160
|
+
"matched_error": "NameError: name 'x' is not defined",
|
|
161
|
+
"file": "Unknown File",
|
|
162
|
+
"line": "Unknown Line",
|
|
163
|
+
"code": "",
|
|
164
|
+
"ast_insight": None,
|
|
165
|
+
}
|
|
166
|
+
print_result_json(payload)
|
|
167
|
+
captured = capsys.readouterr().out
|
|
168
|
+
# Single line, valid JSON, contains the key fields
|
|
169
|
+
assert captured.count("\n") == 1
|
|
170
|
+
parsed = json.loads(captured.strip())
|
|
171
|
+
assert parsed == payload
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import ast
|
|
2
|
-
import difflib
|
|
3
|
-
import os
|
|
4
|
-
|
|
5
|
-
# --- 1. THE INDIVIDUAL STRATEGIES (PLUGINS) ---
|
|
6
|
-
|
|
7
|
-
def handle_name_error(file_path: str, extracted_values: list) -> str:
|
|
8
|
-
"""Finds typos for missing variables."""
|
|
9
|
-
missing_var = extracted_values[0]
|
|
10
|
-
|
|
11
|
-
# ... (Imagine your previous AST parsing code is here) ...
|
|
12
|
-
# For brevity, let's assume we found the match:
|
|
13
|
-
closest_match = "maximum_user_connections" # Mocking the AST output
|
|
14
|
-
|
|
15
|
-
if closest_match:
|
|
16
|
-
return f"Did you mean to type '{closest_match}'?"
|
|
17
|
-
return ""
|
|
18
|
-
|
|
19
|
-
def handle_attribute_error(file_path: str, extracted_values: list) -> str:
|
|
20
|
-
"""Finds typos for missing object methods (e.g., .appendd)"""
|
|
21
|
-
obj_type = extracted_values[0]
|
|
22
|
-
missing_attr = extracted_values[1]
|
|
23
|
-
|
|
24
|
-
# ... (AST logic to find valid methods for this object) ...
|
|
25
|
-
closest_match = "append" # Mocking the AST output
|
|
26
|
-
|
|
27
|
-
if closest_match:
|
|
28
|
-
return f"{obj_type} objects don't have '{missing_attr}'. Did you mean '{closest_match}'?"
|
|
29
|
-
return ""
|
|
30
|
-
|
|
31
|
-
def handle_import_error(file_path: str, extracted_values: list) -> str:
|
|
32
|
-
""" Find typos for missing imports """
|
|
33
|
-
missing_module = extracted_values[0]
|
|
34
|
-
|
|
35
|
-
# ... (Imagine your previous AST parsing code is here) ...
|
|
36
|
-
# For brevity, let's assume we found the match:
|
|
37
|
-
closest_match = "maximum_user_connections" # Mocking the AST output
|
|
38
|
-
|
|
39
|
-
if closest_match:
|
|
40
|
-
return f"Did you mean to type '{closest_match}'?"
|
|
41
|
-
return ""
|
|
42
|
-
|
|
43
|
-
# --- 2. THE REGISTRY (THE MAGIC ROUTER) ---
|
|
44
|
-
# We map the string name of the error to the function that handles it.
|
|
45
|
-
AST_REGISTRY = {
|
|
46
|
-
"NameError": handle_name_error,
|
|
47
|
-
"AttributeError": handle_attribute_error,
|
|
48
|
-
"ImportError": handle_import_error,
|
|
49
|
-
# "SyntaxError": handle_syntax_error,
|
|
50
|
-
}
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
import sys
|
|
2
|
-
import argparse
|
|
3
|
-
from .core import translate_error
|
|
4
|
-
from importlib.metadata import version, PackageNotFoundError
|
|
5
|
-
|
|
6
|
-
try:
|
|
7
|
-
VERSION = version("error-translator-cli-v2")
|
|
8
|
-
except PackageNotFoundError:
|
|
9
|
-
VERSION = "unknown (not installed via pip)" # Fallback version if package metadata is not found
|
|
10
|
-
|
|
11
|
-
# ANSI Color Codes
|
|
12
|
-
class Colors:
|
|
13
|
-
RED = '\033[91m'
|
|
14
|
-
GREEN = '\033[92m'
|
|
15
|
-
YELLOW = '\033[93m'
|
|
16
|
-
CYAN = '\033[96m'
|
|
17
|
-
BOLD = '\033[1m'
|
|
18
|
-
RESET = '\033[0m'
|
|
19
|
-
MAGENTA = '\033[95m'
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def print_about():
|
|
23
|
-
"""Prints the about message for the tool."""
|
|
24
|
-
about_text = f"""
|
|
25
|
-
ERROR TRANSLATOR CLI
|
|
26
|
-
=====================
|
|
27
|
-
A lightning-fast, offline tool that translates raw Python tracebacks
|
|
28
|
-
into human-readable explanations with actionable fixes.
|
|
29
|
-
|
|
30
|
-
Authors: Gourabananda Datta
|
|
31
|
-
Repository: https://github.com/gourabanandad/error-translator-cli-v2
|
|
32
|
-
Usage:
|
|
33
|
-
1. Run a script and translate its errors:
|
|
34
|
-
explain-error run your_script.py
|
|
35
|
-
2. Translate an error message directly:
|
|
36
|
-
explain-error "TypeError: unsupported operand type(s) for +: 'int' and 'str'"
|
|
37
|
-
3. Pipe an error log:
|
|
38
|
-
cat error.log | explain-error
|
|
39
|
-
4. Get help:
|
|
40
|
-
explain-error --help
|
|
41
|
-
5. About:
|
|
42
|
-
explain-error --about
|
|
43
|
-
"""
|
|
44
|
-
print(f"\033[96m{about_text}\033[0m")
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def print_result(result: dict):
|
|
48
|
-
"""Prints the translated error to the terminal with colors."""
|
|
49
|
-
print(f"\n{Colors.RED}{Colors.BOLD} Error Detected:{Colors.RESET}")
|
|
50
|
-
print(f"{result.get('matched_error', 'N/A')}")
|
|
51
|
-
|
|
52
|
-
if "file" in result:
|
|
53
|
-
print(f"{Colors.YELLOW} Location: {result['file']} (Line {result['line']}){Colors.RESET}\n")
|
|
54
|
-
if result.get("code"):
|
|
55
|
-
print(f"{Colors.RESET} |")
|
|
56
|
-
print(f"{Colors.RESET} | {Colors.RED}{result['code']}{Colors.RESET}")
|
|
57
|
-
print(f"{Colors.RESET} |\n")
|
|
58
|
-
else:
|
|
59
|
-
print("\n")
|
|
60
|
-
|
|
61
|
-
else:
|
|
62
|
-
print()
|
|
63
|
-
|
|
64
|
-
print(f"{Colors.CYAN}{Colors.BOLD} Explanation:{Colors.RESET}")
|
|
65
|
-
print(f"{result['explanation']}\n")
|
|
66
|
-
|
|
67
|
-
print(f"{Colors.GREEN}{Colors.BOLD} Suggested Fix:{Colors.RESET}")
|
|
68
|
-
print(f"{result['fix']}\n")
|
|
69
|
-
|
|
70
|
-
if result.get("ast_insight"):
|
|
71
|
-
print(f"{Colors.MAGENTA}{Colors.BOLD} AST Insight:{Colors.RESET}")
|
|
72
|
-
print(f"{result['ast_insight']}\n")
|
|
73
|
-
|
|
74
|
-
def run_script(script_name: str):
|
|
75
|
-
"""Runs a python script in the background and catches its errors."""
|
|
76
|
-
import subprocess
|
|
77
|
-
try:
|
|
78
|
-
# Run the script using the current Python environment
|
|
79
|
-
result = subprocess.run(
|
|
80
|
-
[sys.executable, script_name],
|
|
81
|
-
capture_output=True,
|
|
82
|
-
text=True
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
# If the script ran perfectly (Return Code 0), print standard output
|
|
86
|
-
if result.returncode == 0:
|
|
87
|
-
print(result.stdout, end="")
|
|
88
|
-
|
|
89
|
-
# If the script crashed, print whatever succeeded, THEN translate the error
|
|
90
|
-
else:
|
|
91
|
-
if result.stdout:
|
|
92
|
-
print(result.stdout, end="")
|
|
93
|
-
|
|
94
|
-
translation = translate_error(result.stderr)
|
|
95
|
-
print_result(translation)
|
|
96
|
-
|
|
97
|
-
except FileNotFoundError:
|
|
98
|
-
print(f"{Colors.RED}Error: Could not find script '{script_name}'{Colors.RESET}")
|
|
99
|
-
|
|
100
|
-
# Entry point of the program
|
|
101
|
-
def main():
|
|
102
|
-
parser = argparse.ArgumentParser(
|
|
103
|
-
prog="explain-error",
|
|
104
|
-
description="Error Translator — Turn cryptic Python tracebacks into clear, actionable advice.",
|
|
105
|
-
epilog="""
|
|
106
|
-
Examples:
|
|
107
|
-
# Run a Python script and translate any unhandled errors
|
|
108
|
-
explain-error run my_script.py
|
|
109
|
-
|
|
110
|
-
# Translate a raw error string directly
|
|
111
|
-
explain-error "NameError: name 'usr_count' is not defined"
|
|
112
|
-
|
|
113
|
-
# Pipe a traceback from a log file or another command
|
|
114
|
-
cat error.log | explain-error
|
|
115
|
-
|
|
116
|
-
For more information, visit: https://github.com/gourabanandad/error-translator
|
|
117
|
-
""",
|
|
118
|
-
formatter_class=argparse.RawDescriptionHelpFormatter
|
|
119
|
-
)
|
|
120
|
-
|
|
121
|
-
parser.add_argument(
|
|
122
|
-
"-a",
|
|
123
|
-
"--about",
|
|
124
|
-
action="store_true",
|
|
125
|
-
help="Display information about the tool."
|
|
126
|
-
)
|
|
127
|
-
|
|
128
|
-
parser.add_argument(
|
|
129
|
-
"-v",
|
|
130
|
-
"--version",
|
|
131
|
-
action="store_true",
|
|
132
|
-
help="Show the current version of the tool."
|
|
133
|
-
)
|
|
134
|
-
|
|
135
|
-
parser.add_argument(
|
|
136
|
-
"args",
|
|
137
|
-
nargs="*",
|
|
138
|
-
help=(
|
|
139
|
-
"Positional arguments. Use 'run <script.py>' to execute a Python file, "
|
|
140
|
-
"or provide an error string to translate. If no arguments are given and "
|
|
141
|
-
"stdin is not piped, this help message is displayed."
|
|
142
|
-
)
|
|
143
|
-
)
|
|
144
|
-
|
|
145
|
-
parsed_args = parser.parse_args()
|
|
146
|
-
|
|
147
|
-
if parsed_args.about:
|
|
148
|
-
print_about()
|
|
149
|
-
sys.exit(0)
|
|
150
|
-
|
|
151
|
-
if parsed_args.version:
|
|
152
|
-
print(f"Error Translator CLI Version: {Colors.GREEN}{VERSION}{Colors.RESET}")
|
|
153
|
-
sys.exit(0)
|
|
154
|
-
|
|
155
|
-
# 1. Handle Piped Input (e.g., cat error.log | explain-error)
|
|
156
|
-
if not sys.stdin.isatty():
|
|
157
|
-
error_input = sys.stdin.read()
|
|
158
|
-
if error_input.strip():
|
|
159
|
-
print_result(translate_error(error_input))
|
|
160
|
-
return
|
|
161
|
-
|
|
162
|
-
# 2. Print help if no arguments and no piped input
|
|
163
|
-
if not parsed_args.args:
|
|
164
|
-
parser.print_help()
|
|
165
|
-
sys.exit(1)
|
|
166
|
-
|
|
167
|
-
# 3. Check if the user used the "run" command
|
|
168
|
-
if parsed_args.args[0] == "run" and len(parsed_args.args) > 1:
|
|
169
|
-
script_name = parsed_args.args[1]
|
|
170
|
-
run_script(script_name)
|
|
171
|
-
|
|
172
|
-
# 4. Fallback: Treat the input as a raw error string
|
|
173
|
-
else:
|
|
174
|
-
error_input = " ".join(parsed_args.args)
|
|
175
|
-
print_result(translate_error(error_input))
|
|
176
|
-
|
|
177
|
-
if __name__ == "__main__":
|
|
178
|
-
main()
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
from error_translator.core import translate_error
|
|
2
|
-
from pydantic import BaseModel
|
|
3
|
-
from fastapi import FastAPI
|
|
4
|
-
from fastapi.staticfiles import StaticFiles
|
|
5
|
-
from fastapi.responses import FileResponse
|
|
6
|
-
import os
|
|
7
|
-
|
|
8
|
-
from importlib.metadata import version, PackageNotFoundError
|
|
9
|
-
|
|
10
|
-
try:
|
|
11
|
-
VERSION = version("error-translator-cli-v2")
|
|
12
|
-
except PackageNotFoundError:
|
|
13
|
-
VERSION = "unknown (not installed via pip)"
|
|
14
|
-
|
|
15
|
-
app = FastAPI(
|
|
16
|
-
title="Error translator API",
|
|
17
|
-
description="An API that translates Python errors into human-readable English.",
|
|
18
|
-
version=VERSION
|
|
19
|
-
)
|
|
20
|
-
class ErrorRequest(BaseModel):
|
|
21
|
-
traceback_setting: str
|
|
22
|
-
|
|
23
|
-
# API endpoint (existing functionality, unchanged)
|
|
24
|
-
@app.post("/translate")
|
|
25
|
-
def translation_endpoint(request: ErrorRequest):
|
|
26
|
-
translation_result = translate_error(request.traceback_setting)
|
|
27
|
-
return translation_result
|
|
28
|
-
|
|
29
|
-
# Serve the web UI at the root
|
|
30
|
-
@app.get("/")
|
|
31
|
-
def read_root():
|
|
32
|
-
index_path = os.path.join(os.path.dirname(__file__), "static", "index.html")
|
|
33
|
-
if os.path.exists(index_path):
|
|
34
|
-
return FileResponse(index_path)
|
|
35
|
-
return {
|
|
36
|
-
"message": "Error translation API is running. Web UI not found. Please ensure static/index.html exists."
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
# Health check (useful for monitoring)
|
|
40
|
-
@app.get("/health")
|
|
41
|
-
def health_check():
|
|
42
|
-
return {"status": "ok"}
|
|
43
|
-
|
|
44
|
-
# Mount static files directory (CSS, etc.)
|
|
45
|
-
static_path = os.path.join(os.path.dirname(__file__), "static")
|
|
46
|
-
if os.path.exists(static_path):
|
|
47
|
-
app.mount("/static", StaticFiles(directory=static_path), name="static")
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>Error Translator</title>
|
|
7
|
-
<link rel="stylesheet" href="/static/style.css">
|
|
8
|
-
</head>
|
|
9
|
-
<body>
|
|
10
|
-
<div class="container">
|
|
11
|
-
<h1>Error Translator</h1>
|
|
12
|
-
<p class="subtitle">Paste a Python traceback or error message below.</p>
|
|
13
|
-
|
|
14
|
-
<textarea id="errorInput" placeholder="e.g. Traceback (most recent call last): File "app.py", line 14, in <module> total = "Users: " + 42 TypeError: can only concatenate str (not "int") to str"></textarea>
|
|
15
|
-
|
|
16
|
-
<button id="translateBtn">Translate</button>
|
|
17
|
-
|
|
18
|
-
<div id="result" class="result hidden">
|
|
19
|
-
<h3>Explanation</h3>
|
|
20
|
-
<pre id="explanationText"></pre>
|
|
21
|
-
<h3>Suggested Fix</h3>
|
|
22
|
-
<pre id="fixText"></pre>
|
|
23
|
-
</div>
|
|
24
|
-
|
|
25
|
-
<div id="error" class="error hidden"></div>
|
|
26
|
-
</div>
|
|
27
|
-
|
|
28
|
-
<script>
|
|
29
|
-
const input = document.getElementById('errorInput');
|
|
30
|
-
const btn = document.getElementById('translateBtn');
|
|
31
|
-
const resultDiv = document.getElementById('result');
|
|
32
|
-
const explanationText = document.getElementById('explanationText');
|
|
33
|
-
const fixText = document.getElementById('fixText');
|
|
34
|
-
const errorDiv = document.getElementById('error');
|
|
35
|
-
|
|
36
|
-
btn.addEventListener('click', async () => {
|
|
37
|
-
const errorText = input.value.trim();
|
|
38
|
-
if (!errorText) {
|
|
39
|
-
showError('Please enter an error message.');
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
btn.disabled = true;
|
|
44
|
-
btn.textContent = 'Translating...';
|
|
45
|
-
resultDiv.classList.add('hidden');
|
|
46
|
-
errorDiv.classList.add('hidden');
|
|
47
|
-
|
|
48
|
-
try {
|
|
49
|
-
const response = await fetch('/translate', {
|
|
50
|
-
method: 'POST',
|
|
51
|
-
headers: { 'Content-Type': 'application/json' },
|
|
52
|
-
body: JSON.stringify({ traceback_setting: errorText })
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
const data = await response.json();
|
|
56
|
-
|
|
57
|
-
if (response.ok) {
|
|
58
|
-
explanationText.textContent = data.explanation || 'No explanation provided.';
|
|
59
|
-
fixText.textContent = data.fix || 'No fix suggested.';
|
|
60
|
-
resultDiv.classList.remove('hidden');
|
|
61
|
-
} else {
|
|
62
|
-
showError(data.detail || 'Translation failed.');
|
|
63
|
-
}
|
|
64
|
-
} catch (err) {
|
|
65
|
-
showError('Network error. Is the server running?');
|
|
66
|
-
} finally {
|
|
67
|
-
btn.disabled = false;
|
|
68
|
-
btn.textContent = 'Translate';
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
function showError(msg) {
|
|
73
|
-
errorDiv.textContent = msg;
|
|
74
|
-
errorDiv.classList.remove('hidden');
|
|
75
|
-
}
|
|
76
|
-
</script>
|
|
77
|
-
</body>
|
|
78
|
-
</html>
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
body {
|
|
2
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
|
|
3
|
-
max-width: 900px;
|
|
4
|
-
margin: 40px auto;
|
|
5
|
-
padding: 0 20px;
|
|
6
|
-
background-color: #f8f9fa;
|
|
7
|
-
color: #212529;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
.container {
|
|
11
|
-
background: white;
|
|
12
|
-
border-radius: 12px;
|
|
13
|
-
padding: 30px;
|
|
14
|
-
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
h1 {
|
|
18
|
-
margin-top: 0;
|
|
19
|
-
color: #0d6efd;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
.subtitle {
|
|
23
|
-
color: #6c757d;
|
|
24
|
-
margin-bottom: 20px;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
textarea {
|
|
28
|
-
width: 100%;
|
|
29
|
-
height: 200px;
|
|
30
|
-
padding: 15px;
|
|
31
|
-
font-family: 'Courier New', monospace;
|
|
32
|
-
font-size: 14px;
|
|
33
|
-
border: 1px solid #ced4da;
|
|
34
|
-
border-radius: 8px;
|
|
35
|
-
resize: vertical;
|
|
36
|
-
box-sizing: border-box;
|
|
37
|
-
background-color: #fdfdfd;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
button {
|
|
41
|
-
background-color: #0d6efd;
|
|
42
|
-
color: white;
|
|
43
|
-
border: none;
|
|
44
|
-
padding: 12px 24px;
|
|
45
|
-
font-size: 16px;
|
|
46
|
-
border-radius: 6px;
|
|
47
|
-
cursor: pointer;
|
|
48
|
-
margin-top: 15px;
|
|
49
|
-
transition: background-color 0.2s;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
button:hover {
|
|
53
|
-
background-color: #0b5ed7;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
button:disabled {
|
|
57
|
-
background-color: #6c757d;
|
|
58
|
-
cursor: not-allowed;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
.result {
|
|
62
|
-
margin-top: 30px;
|
|
63
|
-
border-top: 1px solid #dee2e6;
|
|
64
|
-
padding-top: 20px;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
.result h3 {
|
|
68
|
-
margin-bottom: 8px;
|
|
69
|
-
color: #198754;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
.result pre {
|
|
73
|
-
background-color: #f1f3f5;
|
|
74
|
-
padding: 15px;
|
|
75
|
-
border-radius: 6px;
|
|
76
|
-
overflow-x: auto;
|
|
77
|
-
white-space: pre-wrap;
|
|
78
|
-
font-family: 'Courier New', monospace;
|
|
79
|
-
font-size: 14px;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
.error {
|
|
83
|
-
margin-top: 20px;
|
|
84
|
-
color: #dc3545;
|
|
85
|
-
background-color: #f8d7da;
|
|
86
|
-
border: 1px solid #f5c2c7;
|
|
87
|
-
padding: 12px;
|
|
88
|
-
border-radius: 6px;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
.hidden {
|
|
92
|
-
display: none;
|
|
93
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
LICENSE
|
|
2
|
-
README.md
|
|
3
|
-
pyproject.toml
|
|
4
|
-
error_translator/__init__.py
|
|
5
|
-
error_translator/ast_handlers.py
|
|
6
|
-
error_translator/auto.py
|
|
7
|
-
error_translator/cli.py
|
|
8
|
-
error_translator/core.py
|
|
9
|
-
error_translator/rules.json
|
|
10
|
-
error_translator/server.py
|
|
11
|
-
error_translator/static/index.html
|
|
12
|
-
error_translator/static/style.css
|
|
13
|
-
error_translator_cli_v2.egg-info/PKG-INFO
|
|
14
|
-
error_translator_cli_v2.egg-info/SOURCES.txt
|
|
15
|
-
error_translator_cli_v2.egg-info/dependency_links.txt
|
|
16
|
-
error_translator_cli_v2.egg-info/entry_points.txt
|
|
17
|
-
error_translator_cli_v2.egg-info/requires.txt
|
|
18
|
-
error_translator_cli_v2.egg-info/top_level.txt
|
|
19
|
-
tests/test_core.py
|
|
File without changes
|
|
File without changes
|
{error_translator_cli_v2-1.1.4 → error_translator_cli_v2-2.0.0/src}/error_translator/__init__.py
RENAMED
|
File without changes
|
{error_translator_cli_v2-1.1.4 → error_translator_cli_v2-2.0.0/src}/error_translator/auto.py
RENAMED
|
File without changes
|
{error_translator_cli_v2-1.1.4 → error_translator_cli_v2-2.0.0/src}/error_translator/rules.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|