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.
Files changed (35) hide show
  1. failwith-0.1.0/CHANGELOG.md +40 -0
  2. failwith-0.1.0/LICENSE +21 -0
  3. failwith-0.1.0/MANIFEST.in +5 -0
  4. failwith-0.1.0/PKG-INFO +197 -0
  5. failwith-0.1.0/README.md +164 -0
  6. failwith-0.1.0/pyproject.toml +53 -0
  7. failwith-0.1.0/setup.cfg +4 -0
  8. failwith-0.1.0/src/failwith/__init__.py +25 -0
  9. failwith-0.1.0/src/failwith/core/__init__.py +2 -0
  10. failwith-0.1.0/src/failwith/core/analyzer.py +55 -0
  11. failwith-0.1.0/src/failwith/core/formatter.py +227 -0
  12. failwith-0.1.0/src/failwith/core/interceptor.py +144 -0
  13. failwith-0.1.0/src/failwith/data/__init__.py +1 -0
  14. failwith-0.1.0/src/failwith/data/import_map.py +200 -0
  15. failwith-0.1.0/src/failwith/data/port_map.py +84 -0
  16. failwith-0.1.0/src/failwith/plugins/__init__.py +1 -0
  17. failwith-0.1.0/src/failwith/py.typed +0 -0
  18. failwith-0.1.0/src/failwith/suggestions/__init__.py +83 -0
  19. failwith-0.1.0/src/failwith/suggestions/base.py +5 -0
  20. failwith-0.1.0/src/failwith/suggestions/connection.py +170 -0
  21. failwith-0.1.0/src/failwith/suggestions/filesystem.py +156 -0
  22. failwith-0.1.0/src/failwith/suggestions/imports.py +141 -0
  23. failwith-0.1.0/src/failwith/suggestions/misc.py +330 -0
  24. failwith-0.1.0/src/failwith/suggestions/types.py +349 -0
  25. failwith-0.1.0/src/failwith/utils/__init__.py +1 -0
  26. failwith-0.1.0/src/failwith/utils/env.py +121 -0
  27. failwith-0.1.0/src/failwith/utils/fs.py +104 -0
  28. failwith-0.1.0/src/failwith/utils/fuzzy.py +48 -0
  29. failwith-0.1.0/src/failwith.egg-info/PKG-INFO +197 -0
  30. failwith-0.1.0/src/failwith.egg-info/SOURCES.txt +33 -0
  31. failwith-0.1.0/src/failwith.egg-info/dependency_links.txt +1 -0
  32. failwith-0.1.0/src/failwith.egg-info/requires.txt +8 -0
  33. failwith-0.1.0/src/failwith.egg-info/top_level.txt +1 -0
  34. failwith-0.1.0/tests/__init__.py +1 -0
  35. 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.
@@ -0,0 +1,5 @@
1
+ include LICENSE
2
+ include README.md
3
+ include CHANGELOG.md
4
+ recursive-include src *.py
5
+ recursive-include tests *.py
@@ -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
@@ -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"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -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,2 @@
1
+ # Core package
2
+
@@ -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