failwith 0.1.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.
- failwith-0.1.0/CHANGELOG.md +40 -0
- failwith-0.1.0/LICENSE +21 -0
- failwith-0.1.0/MANIFEST.in +5 -0
- failwith-0.1.0/PKG-INFO +197 -0
- failwith-0.1.0/README.md +164 -0
- failwith-0.1.0/pyproject.toml +53 -0
- failwith-0.1.0/setup.cfg +4 -0
- failwith-0.1.0/src/failwith/__init__.py +25 -0
- failwith-0.1.0/src/failwith/core/__init__.py +2 -0
- failwith-0.1.0/src/failwith/core/analyzer.py +55 -0
- failwith-0.1.0/src/failwith/core/formatter.py +227 -0
- failwith-0.1.0/src/failwith/core/interceptor.py +144 -0
- failwith-0.1.0/src/failwith/data/__init__.py +1 -0
- failwith-0.1.0/src/failwith/data/import_map.py +200 -0
- failwith-0.1.0/src/failwith/data/port_map.py +84 -0
- failwith-0.1.0/src/failwith/plugins/__init__.py +1 -0
- failwith-0.1.0/src/failwith/py.typed +0 -0
- failwith-0.1.0/src/failwith/suggestions/__init__.py +83 -0
- failwith-0.1.0/src/failwith/suggestions/base.py +5 -0
- failwith-0.1.0/src/failwith/suggestions/connection.py +170 -0
- failwith-0.1.0/src/failwith/suggestions/filesystem.py +156 -0
- failwith-0.1.0/src/failwith/suggestions/imports.py +141 -0
- failwith-0.1.0/src/failwith/suggestions/misc.py +330 -0
- failwith-0.1.0/src/failwith/suggestions/types.py +349 -0
- failwith-0.1.0/src/failwith/utils/__init__.py +1 -0
- failwith-0.1.0/src/failwith/utils/env.py +121 -0
- failwith-0.1.0/src/failwith/utils/fs.py +104 -0
- failwith-0.1.0/src/failwith/utils/fuzzy.py +48 -0
- failwith-0.1.0/src/failwith.egg-info/PKG-INFO +197 -0
- failwith-0.1.0/src/failwith.egg-info/SOURCES.txt +33 -0
- failwith-0.1.0/src/failwith.egg-info/dependency_links.txt +1 -0
- failwith-0.1.0/src/failwith.egg-info/requires.txt +8 -0
- failwith-0.1.0/src/failwith.egg-info/top_level.txt +1 -0
- failwith-0.1.0/tests/__init__.py +1 -0
- failwith-0.1.0/tests/test_failwith.py +541 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `failwith` will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2026-03-29
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Core `failwith.install()` one-liner activation
|
|
13
|
+
- `failwith.catch()` context manager and decorator
|
|
14
|
+
- `@failwith.register()` custom suggestion handler API
|
|
15
|
+
- 20 built-in error type handlers:
|
|
16
|
+
- `ModuleNotFoundError` with 120+ import→package name mappings
|
|
17
|
+
- `ImportError` with fuzzy name matching and circular import detection
|
|
18
|
+
- `ConnectionRefusedError` with port-aware service suggestions
|
|
19
|
+
- `TimeoutError` and `ConnectionResetError` with network debug tips
|
|
20
|
+
- `FileNotFoundError` with similar file search and directory listing
|
|
21
|
+
- `PermissionError` with ownership and chmod/chown suggestions
|
|
22
|
+
- `KeyError` with fuzzy matching against available keys
|
|
23
|
+
- `AttributeError` with fuzzy matching and NoneType detection
|
|
24
|
+
- `NameError` with scope-aware fuzzy matching
|
|
25
|
+
- `TypeError` with common pattern fixes (str+int, not callable, etc.)
|
|
26
|
+
- `ValueError` with conversion and unpacking suggestions
|
|
27
|
+
- `IndexError` with collection size context
|
|
28
|
+
- `ZeroDivisionError` with zero-valued variable identification
|
|
29
|
+
- `UnicodeDecodeError` / `UnicodeEncodeError` with encoding suggestions
|
|
30
|
+
- `RecursionError` with recursion limit and call chain info
|
|
31
|
+
- `MemoryError` with optimization strategies
|
|
32
|
+
- `SyntaxError` with common fix patterns
|
|
33
|
+
- `json.JSONDecodeError` with error position context
|
|
34
|
+
- `StopIteration` with next() default suggestion
|
|
35
|
+
- `OSError` with errno-specific suggestions (disk full, too many files, port in use)
|
|
36
|
+
- Port→service mapping database (40+ common ports)
|
|
37
|
+
- Environment diagnostics (Python version, venv, OS detection)
|
|
38
|
+
- ANSI color output with graceful plain-text fallback
|
|
39
|
+
- Cross-platform support (Linux, macOS, Windows)
|
|
40
|
+
- Zero runtime dependencies
|
failwith-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yashraj Aware
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
failwith-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: failwith
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Actionable error intelligence for Python — tells you why errors happen and how to fix them.
|
|
5
|
+
Author-email: Yashraj Aware <yashrajaware2003@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Yashraj-Aware/failwith.git
|
|
8
|
+
Project-URL: Repository, https://github.com/Yashraj-Aware/failwith
|
|
9
|
+
Project-URL: Issues, https://github.com/Yashraj-Aware/failwith/issues
|
|
10
|
+
Keywords: errors,traceback,debugging,developer-tools,exceptions,diagnostics
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Software Development :: Debuggers
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.9
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Provides-Extra: rich
|
|
27
|
+
Requires-Dist: rich>=12.0.0; extra == "rich"
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
31
|
+
Requires-Dist: ruff>=0.4.0; extra == "dev"
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# failwith
|
|
35
|
+
|
|
36
|
+
**Actionable error intelligence for Python.**
|
|
37
|
+
|
|
38
|
+
When Python tells you *what* broke, `failwith` tells you *why* and *how to fix it*.
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
pip install failwith
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Quick Start
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
import failwith
|
|
48
|
+
failwith.install()
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
That's it. Every unhandled exception now gets actionable fix suggestions appended below the standard traceback.
|
|
52
|
+
|
|
53
|
+
## What It Looks Like
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
Traceback (most recent call last):
|
|
57
|
+
File "app.py", line 3, in <module>
|
|
58
|
+
import cv2
|
|
59
|
+
ModuleNotFoundError: No module named 'cv2'
|
|
60
|
+
|
|
61
|
+
┌─ 💡 failwith ─────────────────────────────────────────────────┐
|
|
62
|
+
│ │
|
|
63
|
+
│ 'cv2' is from the 'opencv-python' package (import ≠ package) │
|
|
64
|
+
│ │
|
|
65
|
+
│ → Install it: pip install opencv-python │
|
|
66
|
+
│ → Or headless: pip install opencv-python-headless │
|
|
67
|
+
│ → Active venv: .venv │
|
|
68
|
+
│ │
|
|
69
|
+
│ 🔍 Python 3.11.5 | venv: .venv | Ubuntu 24.04 │
|
|
70
|
+
│ │
|
|
71
|
+
└────────────────────────────────────────────────────────────────┘
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Features
|
|
75
|
+
|
|
76
|
+
### 1. 200+ Import Name → Package Name Mappings
|
|
77
|
+
|
|
78
|
+
`cv2` → `opencv-python`, `PIL` → `Pillow`, `sklearn` → `scikit-learn`, `yaml` → `PyYAML`, and 200+ more. Never Google "pip install what?" again.
|
|
79
|
+
|
|
80
|
+
### Context-Aware Suggestions
|
|
81
|
+
|
|
82
|
+
Not pattern matching — actual context analysis. When a `ConnectionRefusedError` hits on port 5432, failwith knows that's PostgreSQL and suggests the right start command for your OS.
|
|
83
|
+
|
|
84
|
+
### 2. Fuzzy Matching for Typos
|
|
85
|
+
|
|
86
|
+
`KeyError`, `AttributeError`, and `NameError` get fuzzy-matched against available keys, attributes, and names. "Did you mean 'username'?" with edit distance.
|
|
87
|
+
|
|
88
|
+
### 3. File System Intelligence
|
|
89
|
+
|
|
90
|
+
`FileNotFoundError` shows similar files in the directory, current working directory, and the closest existing parent path. `PermissionError` shows file ownership and suggests `chmod`/`chown` commands.
|
|
91
|
+
|
|
92
|
+
### 4. Environment Diagnostics
|
|
93
|
+
|
|
94
|
+
Every suggestion includes Python version, venv status, and OS — the three things you always need when debugging.
|
|
95
|
+
|
|
96
|
+
### 5. Zero Dependencies
|
|
97
|
+
|
|
98
|
+
Uses only the Python standard library. No `rich`, no `click`, nothing. Zero friction to adopt.
|
|
99
|
+
|
|
100
|
+
### 6. Never Makes Things Worse
|
|
101
|
+
|
|
102
|
+
If failwith itself encounters an error, it silently degrades. Your original traceback is always printed first, unmodified.
|
|
103
|
+
|
|
104
|
+
## Supported Error Types (v0.1)
|
|
105
|
+
|
|
106
|
+
| Error | What failwith adds |
|
|
107
|
+
|-------|-------------------|
|
|
108
|
+
| `ModuleNotFoundError` | Correct `pip install` command, import↔package mapping |
|
|
109
|
+
| `ImportError` | Fuzzy name matching, circular import detection |
|
|
110
|
+
| `ConnectionRefusedError` | Service name, start commands, Docker suggestions |
|
|
111
|
+
| `TimeoutError` | Network debugging commands |
|
|
112
|
+
| `ConnectionResetError` | Server-side investigation suggestions |
|
|
113
|
+
| `FileNotFoundError` | Similar files, directory listing, working dir |
|
|
114
|
+
| `PermissionError` | File owner, chmod/chown commands |
|
|
115
|
+
| `KeyError` | Fuzzy match against available keys, `.get()` suggestion |
|
|
116
|
+
| `AttributeError` | Fuzzy match against attributes, NoneType detection |
|
|
117
|
+
| `NameError` | Scope-aware fuzzy matching, import suggestions |
|
|
118
|
+
| `TypeError` | Type mismatch fixes (str+int, not callable, etc.) |
|
|
119
|
+
| `ValueError` | Conversion fixes, unpacking mismatch |
|
|
120
|
+
| `IndexError` | Collection size context, safe access |
|
|
121
|
+
| `ZeroDivisionError` | Zero-valued variable identification |
|
|
122
|
+
| `UnicodeDecodeError` | Encoding suggestions, chardet recommendation |
|
|
123
|
+
| `UnicodeEncodeError` | Encoding alternatives, error handling modes |
|
|
124
|
+
| `RecursionError` | Recursion limit, call chain, base case reminder |
|
|
125
|
+
| `MemoryError` | Memory optimization strategies |
|
|
126
|
+
| `SyntaxError` | Common fix patterns (missing colon, Python 2→3) |
|
|
127
|
+
| `JSONDecodeError` | Error position context, common JSON issues |
|
|
128
|
+
| `StopIteration` | `next()` with default, iterator re-creation |
|
|
129
|
+
| `OSError` | Disk space, file descriptor limits, port conflicts |
|
|
130
|
+
|
|
131
|
+
## Advanced Usage
|
|
132
|
+
|
|
133
|
+
### Context Manager
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
with failwith.catch(reraise=False):
|
|
137
|
+
risky_operation()
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Decorator
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
@failwith.catch()
|
|
144
|
+
def my_function():
|
|
145
|
+
risky_operation()
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Custom Suggestions
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
@failwith.register(MyDatabaseError)
|
|
152
|
+
def handle_db_error(exc_type, exc_value, exc_tb, config):
|
|
153
|
+
return failwith.Suggestion(
|
|
154
|
+
title="Database connection failed",
|
|
155
|
+
fixes=[
|
|
156
|
+
"Check DATABASE_URL in your .env file",
|
|
157
|
+
"Run: docker-compose up -d postgres",
|
|
158
|
+
],
|
|
159
|
+
)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Configuration
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
failwith.install(
|
|
166
|
+
theme="dark", # "dark" | "light" | "minimal" | "plain"
|
|
167
|
+
show_locals=False, # show local variable values
|
|
168
|
+
max_suggestions=3, # limit suggestions shown
|
|
169
|
+
)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Environment Variables
|
|
173
|
+
|
|
174
|
+
| Variable | Effect |
|
|
175
|
+
|----------|--------|
|
|
176
|
+
| `NO_COLOR` | Disable colors (standard) |
|
|
177
|
+
| `FAILWITH_NO_COLOR` | Disable colors |
|
|
178
|
+
| `FAILWITH_FORCE_COLOR` | Force colors even in non-TTY |
|
|
179
|
+
|
|
180
|
+
## Contributing
|
|
181
|
+
|
|
182
|
+
Contributions are welcome! The most impactful way to contribute:
|
|
183
|
+
|
|
184
|
+
1. **Add import mappings** — edit `src/failwith/data/import_map.py`
|
|
185
|
+
2. **Improve suggestions** — edit handlers in `src/failwith/suggestions/`
|
|
186
|
+
3. **Add test cases** — real-world error scenarios in `tests/`
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
git clone https://github.com/yashraj/failwith.git
|
|
190
|
+
cd failwith
|
|
191
|
+
pip install -e ".[dev]"
|
|
192
|
+
pytest
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## License
|
|
196
|
+
|
|
197
|
+
MIT
|
failwith-0.1.0/README.md
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# failwith
|
|
2
|
+
|
|
3
|
+
**Actionable error intelligence for Python.**
|
|
4
|
+
|
|
5
|
+
When Python tells you *what* broke, `failwith` tells you *why* and *how to fix it*.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
pip install failwith
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
import failwith
|
|
15
|
+
failwith.install()
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
That's it. Every unhandled exception now gets actionable fix suggestions appended below the standard traceback.
|
|
19
|
+
|
|
20
|
+
## What It Looks Like
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
Traceback (most recent call last):
|
|
24
|
+
File "app.py", line 3, in <module>
|
|
25
|
+
import cv2
|
|
26
|
+
ModuleNotFoundError: No module named 'cv2'
|
|
27
|
+
|
|
28
|
+
┌─ 💡 failwith ─────────────────────────────────────────────────┐
|
|
29
|
+
│ │
|
|
30
|
+
│ 'cv2' is from the 'opencv-python' package (import ≠ package) │
|
|
31
|
+
│ │
|
|
32
|
+
│ → Install it: pip install opencv-python │
|
|
33
|
+
│ → Or headless: pip install opencv-python-headless │
|
|
34
|
+
│ → Active venv: .venv │
|
|
35
|
+
│ │
|
|
36
|
+
│ 🔍 Python 3.11.5 | venv: .venv | Ubuntu 24.04 │
|
|
37
|
+
│ │
|
|
38
|
+
└────────────────────────────────────────────────────────────────┘
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Features
|
|
42
|
+
|
|
43
|
+
### 1. 200+ Import Name → Package Name Mappings
|
|
44
|
+
|
|
45
|
+
`cv2` → `opencv-python`, `PIL` → `Pillow`, `sklearn` → `scikit-learn`, `yaml` → `PyYAML`, and 200+ more. Never Google "pip install what?" again.
|
|
46
|
+
|
|
47
|
+
### Context-Aware Suggestions
|
|
48
|
+
|
|
49
|
+
Not pattern matching — actual context analysis. When a `ConnectionRefusedError` hits on port 5432, failwith knows that's PostgreSQL and suggests the right start command for your OS.
|
|
50
|
+
|
|
51
|
+
### 2. Fuzzy Matching for Typos
|
|
52
|
+
|
|
53
|
+
`KeyError`, `AttributeError`, and `NameError` get fuzzy-matched against available keys, attributes, and names. "Did you mean 'username'?" with edit distance.
|
|
54
|
+
|
|
55
|
+
### 3. File System Intelligence
|
|
56
|
+
|
|
57
|
+
`FileNotFoundError` shows similar files in the directory, current working directory, and the closest existing parent path. `PermissionError` shows file ownership and suggests `chmod`/`chown` commands.
|
|
58
|
+
|
|
59
|
+
### 4. Environment Diagnostics
|
|
60
|
+
|
|
61
|
+
Every suggestion includes Python version, venv status, and OS — the three things you always need when debugging.
|
|
62
|
+
|
|
63
|
+
### 5. Zero Dependencies
|
|
64
|
+
|
|
65
|
+
Uses only the Python standard library. No `rich`, no `click`, nothing. Zero friction to adopt.
|
|
66
|
+
|
|
67
|
+
### 6. Never Makes Things Worse
|
|
68
|
+
|
|
69
|
+
If failwith itself encounters an error, it silently degrades. Your original traceback is always printed first, unmodified.
|
|
70
|
+
|
|
71
|
+
## Supported Error Types (v0.1)
|
|
72
|
+
|
|
73
|
+
| Error | What failwith adds |
|
|
74
|
+
|-------|-------------------|
|
|
75
|
+
| `ModuleNotFoundError` | Correct `pip install` command, import↔package mapping |
|
|
76
|
+
| `ImportError` | Fuzzy name matching, circular import detection |
|
|
77
|
+
| `ConnectionRefusedError` | Service name, start commands, Docker suggestions |
|
|
78
|
+
| `TimeoutError` | Network debugging commands |
|
|
79
|
+
| `ConnectionResetError` | Server-side investigation suggestions |
|
|
80
|
+
| `FileNotFoundError` | Similar files, directory listing, working dir |
|
|
81
|
+
| `PermissionError` | File owner, chmod/chown commands |
|
|
82
|
+
| `KeyError` | Fuzzy match against available keys, `.get()` suggestion |
|
|
83
|
+
| `AttributeError` | Fuzzy match against attributes, NoneType detection |
|
|
84
|
+
| `NameError` | Scope-aware fuzzy matching, import suggestions |
|
|
85
|
+
| `TypeError` | Type mismatch fixes (str+int, not callable, etc.) |
|
|
86
|
+
| `ValueError` | Conversion fixes, unpacking mismatch |
|
|
87
|
+
| `IndexError` | Collection size context, safe access |
|
|
88
|
+
| `ZeroDivisionError` | Zero-valued variable identification |
|
|
89
|
+
| `UnicodeDecodeError` | Encoding suggestions, chardet recommendation |
|
|
90
|
+
| `UnicodeEncodeError` | Encoding alternatives, error handling modes |
|
|
91
|
+
| `RecursionError` | Recursion limit, call chain, base case reminder |
|
|
92
|
+
| `MemoryError` | Memory optimization strategies |
|
|
93
|
+
| `SyntaxError` | Common fix patterns (missing colon, Python 2→3) |
|
|
94
|
+
| `JSONDecodeError` | Error position context, common JSON issues |
|
|
95
|
+
| `StopIteration` | `next()` with default, iterator re-creation |
|
|
96
|
+
| `OSError` | Disk space, file descriptor limits, port conflicts |
|
|
97
|
+
|
|
98
|
+
## Advanced Usage
|
|
99
|
+
|
|
100
|
+
### Context Manager
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
with failwith.catch(reraise=False):
|
|
104
|
+
risky_operation()
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Decorator
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
@failwith.catch()
|
|
111
|
+
def my_function():
|
|
112
|
+
risky_operation()
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Custom Suggestions
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
@failwith.register(MyDatabaseError)
|
|
119
|
+
def handle_db_error(exc_type, exc_value, exc_tb, config):
|
|
120
|
+
return failwith.Suggestion(
|
|
121
|
+
title="Database connection failed",
|
|
122
|
+
fixes=[
|
|
123
|
+
"Check DATABASE_URL in your .env file",
|
|
124
|
+
"Run: docker-compose up -d postgres",
|
|
125
|
+
],
|
|
126
|
+
)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Configuration
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
failwith.install(
|
|
133
|
+
theme="dark", # "dark" | "light" | "minimal" | "plain"
|
|
134
|
+
show_locals=False, # show local variable values
|
|
135
|
+
max_suggestions=3, # limit suggestions shown
|
|
136
|
+
)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Environment Variables
|
|
140
|
+
|
|
141
|
+
| Variable | Effect |
|
|
142
|
+
|----------|--------|
|
|
143
|
+
| `NO_COLOR` | Disable colors (standard) |
|
|
144
|
+
| `FAILWITH_NO_COLOR` | Disable colors |
|
|
145
|
+
| `FAILWITH_FORCE_COLOR` | Force colors even in non-TTY |
|
|
146
|
+
|
|
147
|
+
## Contributing
|
|
148
|
+
|
|
149
|
+
Contributions are welcome! The most impactful way to contribute:
|
|
150
|
+
|
|
151
|
+
1. **Add import mappings** — edit `src/failwith/data/import_map.py`
|
|
152
|
+
2. **Improve suggestions** — edit handlers in `src/failwith/suggestions/`
|
|
153
|
+
3. **Add test cases** — real-world error scenarios in `tests/`
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
git clone https://github.com/yashraj/failwith.git
|
|
157
|
+
cd failwith
|
|
158
|
+
pip install -e ".[dev]"
|
|
159
|
+
pytest
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
MIT
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "failwith"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Actionable error intelligence for Python — tells you why errors happen and how to fix them."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {text = "MIT"}
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Yashraj Aware", email = "yashrajaware2003@gmail.com"},
|
|
14
|
+
]
|
|
15
|
+
keywords = ["errors", "traceback", "debugging", "developer-tools", "exceptions", "diagnostics"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.9",
|
|
22
|
+
"Programming Language :: Python :: 3.10",
|
|
23
|
+
"Programming Language :: Python :: 3.11",
|
|
24
|
+
"Programming Language :: Python :: 3.12",
|
|
25
|
+
"Programming Language :: Python :: 3.13",
|
|
26
|
+
"Topic :: Software Development :: Debuggers",
|
|
27
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
28
|
+
"Typing :: Typed",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.optional-dependencies]
|
|
32
|
+
rich = ["rich>=12.0.0"]
|
|
33
|
+
dev = [
|
|
34
|
+
"pytest>=7.0",
|
|
35
|
+
"pytest-cov>=4.0",
|
|
36
|
+
"ruff>=0.4.0",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
[project.urls]
|
|
40
|
+
Homepage = "https://github.com/Yashraj-Aware/failwith.git"
|
|
41
|
+
Repository = "https://github.com/Yashraj-Aware/failwith"
|
|
42
|
+
Issues = "https://github.com/Yashraj-Aware/failwith/issues"
|
|
43
|
+
|
|
44
|
+
[tool.setuptools.packages.find]
|
|
45
|
+
where = ["src"]
|
|
46
|
+
|
|
47
|
+
[tool.pytest.ini_options]
|
|
48
|
+
testpaths = ["tests"]
|
|
49
|
+
pythonpath = ["src"]
|
|
50
|
+
|
|
51
|
+
[tool.ruff]
|
|
52
|
+
line-length = 100
|
|
53
|
+
target-version = "py39"
|
failwith-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""
|
|
2
|
+
failwith — Actionable error intelligence for Python.
|
|
3
|
+
|
|
4
|
+
When Python tells you what broke, failwith tells you why and how to fix it.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
import failwith
|
|
8
|
+
failwith.install()
|
|
9
|
+
|
|
10
|
+
That's it. Every unhandled exception now gets actionable fix suggestions.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
__version__ = "0.1.0"
|
|
14
|
+
|
|
15
|
+
from failwith.core.interceptor import install, uninstall, catch
|
|
16
|
+
from failwith.suggestions.base import Suggestion, register
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"install",
|
|
20
|
+
"uninstall",
|
|
21
|
+
"catch",
|
|
22
|
+
"register",
|
|
23
|
+
"Suggestion",
|
|
24
|
+
"__version__",
|
|
25
|
+
]
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Exception analyzer — routes exceptions to the appropriate suggestion handler.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from typing import Any, Optional, Type
|
|
8
|
+
|
|
9
|
+
from failwith.suggestions import Suggestion, get_handlers
|
|
10
|
+
|
|
11
|
+
# Import all suggestion modules to trigger registration
|
|
12
|
+
import failwith.suggestions.imports # noqa: F401
|
|
13
|
+
import failwith.suggestions.connection # noqa: F401
|
|
14
|
+
import failwith.suggestions.filesystem # noqa: F401
|
|
15
|
+
import failwith.suggestions.types # noqa: F401
|
|
16
|
+
import failwith.suggestions.misc # noqa: F401
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def analyze_exception(
|
|
20
|
+
exc_type: Type[BaseException],
|
|
21
|
+
exc_value: BaseException,
|
|
22
|
+
exc_tb: Any,
|
|
23
|
+
config: dict,
|
|
24
|
+
) -> Optional[Suggestion]:
|
|
25
|
+
"""
|
|
26
|
+
Analyze an exception and return an actionable Suggestion.
|
|
27
|
+
|
|
28
|
+
Walks the handler registry (custom first, then built-in) and returns
|
|
29
|
+
the first non-None suggestion. If no handler matches, returns None.
|
|
30
|
+
"""
|
|
31
|
+
handlers = get_handlers(exc_type)
|
|
32
|
+
|
|
33
|
+
for handler in handlers:
|
|
34
|
+
try:
|
|
35
|
+
suggestion = handler(exc_type, exc_value, exc_tb, config)
|
|
36
|
+
if suggestion and suggestion.fixes:
|
|
37
|
+
# Trim fixes to max_suggestions
|
|
38
|
+
max_fixes = config.get("max_suggestions", 10)
|
|
39
|
+
if len(suggestion.fixes) > max_fixes:
|
|
40
|
+
suggestion.fixes = suggestion.fixes[:max_fixes]
|
|
41
|
+
|
|
42
|
+
# Attach environment info if not already set
|
|
43
|
+
if suggestion.env_info is None:
|
|
44
|
+
try:
|
|
45
|
+
from failwith.utils.env import get_env_summary
|
|
46
|
+
suggestion.env_info = get_env_summary()
|
|
47
|
+
except Exception:
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
return suggestion
|
|
51
|
+
except Exception:
|
|
52
|
+
# Individual handler failure must never propagate
|
|
53
|
+
continue
|
|
54
|
+
|
|
55
|
+
return None
|