butwhy 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.
butwhy-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 why contributors
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.
butwhy-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,367 @@
1
+ Metadata-Version: 2.4
2
+ Name: butwhy
3
+ Version: 0.1.0
4
+ Summary: Stop guessing. Start understanding. Your Python errors, explained.
5
+ Author: butwhy contributors
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/yourname/butwhy
8
+ Project-URL: Repository, https://github.com/yourname/butwhy
9
+ Project-URL: Issues, https://github.com/yourname/butwhy/issues
10
+ Project-URL: Changelog, https://github.com/yourname/butwhy/blob/main/CHANGELOG.md
11
+ Keywords: error,debugging,traceback,ai,explanation,developer-tools,cli,llm,openai,anthropic,ollama,butwhy
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: Implementation :: CPython
23
+ Classifier: Topic :: Software Development :: Debuggers
24
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
25
+ Classifier: Topic :: Utilities
26
+ Classifier: Typing :: Typed
27
+ Requires-Python: >=3.9
28
+ Description-Content-Type: text/markdown
29
+ License-File: LICENSE
30
+ Provides-Extra: dev
31
+ Requires-Dist: pytest>=7.0; extra == "dev"
32
+ Requires-Dist: pytest-cov; extra == "dev"
33
+ Requires-Dist: build; extra == "dev"
34
+ Requires-Dist: twine; extra == "dev"
35
+ Dynamic: license-file
36
+
37
+ <div align="center">
38
+
39
+ # butwhy
40
+
41
+ **Stop guessing. Start understanding.**
42
+
43
+ Your Python errors, explained — in plain English.
44
+
45
+ `pip install butwhy` → `import butwhy` → done.
46
+
47
+ [![PyPI](https://img.shields.io/pypi/v/butwhy)](https://pypi.org/project/butwhy/)
48
+ [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
49
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
50
+ [![CI](https://github.com/yourname/butwhy/actions/workflows/ci.yml/badge.svg)](https://github.com/yourname/butwhy/actions)
51
+ [![Zero Dependencies](https://img.shields.io/badge/dependencies-0-green.svg)](#)
52
+
53
+ </div>
54
+
55
+ ---
56
+
57
+ ## The 30-second pitch
58
+
59
+ You know how Python tracebacks look like this:
60
+
61
+ ```
62
+ Traceback (most recent call last):
63
+ File "demo.py", line 2, in <module>
64
+ result = data.split(",")
65
+ AttributeError: 'NoneType' object has no attribute 'split'
66
+ ```
67
+
68
+ And then you spend 5 minutes on Google figuring out what went wrong?
69
+
70
+ **`why` turns that into this:**
71
+
72
+ ```
73
+ ============================================================
74
+ AttributeError: 'NoneType' object has no attribute 'split'
75
+ at demo.py:2
76
+ ============================================================
77
+
78
+ [pattern match · 93%]
79
+
80
+ Summary:
81
+ Calling .split() on None
82
+
83
+ Cause:
84
+ The variable data is None, not a string.
85
+ This usually means a function returned None (maybe it
86
+ forgot a return statement), or a lookup failed silently.
87
+
88
+ Variables at error:
89
+ data = None (NoneType)
90
+
91
+ Fix:
92
+ Add a None check: if data is not None: data.split(",")
93
+ Or trace back to find why data is None.
94
+
95
+ ============================================================
96
+ ```
97
+
98
+ **One import. Zero config. Instant understanding.**
99
+
100
+ ---
101
+
102
+ ## Quick start
103
+
104
+ ```bash
105
+ pip install butwhy
106
+ ```
107
+
108
+ ```python
109
+ import butwhy # That's it. Errors are now explained.
110
+
111
+ data = None
112
+ result = data.split(",") # Boom — why explains it
113
+ ```
114
+
115
+
116
+
117
+ ### Want AI-powered deep explanations?
118
+
119
+ Set one environment variable and why upgrades automatically:
120
+
121
+ ```bash
122
+ export OPENAI_API_KEY=sk-... # or ANTHROPIC_API_KEY
123
+ ```
124
+
125
+ No API key? **why still works** — it falls back to built-in pattern matching that covers 12+ common error types with zero dependencies.
126
+
127
+ ### Prefer a local model? (No API key, fully offline)
128
+
129
+ ```bash
130
+ # Install Ollama: https://ollama.com
131
+ ollama pull qwen2.5-coder:7b
132
+
133
+ export BUTWHY_PROVIDER=ollama
134
+ ```
135
+
136
+ ---
137
+
138
+ ## Three ways to use why
139
+
140
+ ### 1. Global (recommended) — `import butwhy`
141
+
142
+ ```python
143
+ import butwhy
144
+
145
+ # Every uncaught exception in your script is now explained
146
+ 1 / 0
147
+ ```
148
+
149
+ ### 2. Context manager — `with butwhy.trace()`
150
+
151
+ ```python
152
+ import butwhy
153
+
154
+ with butwhy.trace():
155
+ # Only errors inside this block are explained
156
+ risky_operation()
157
+ ```
158
+
159
+ ### 3. Decorator — `@butwhy.explain`
160
+
161
+ ```python
162
+ import butwhy
163
+
164
+ @butwhy.explain
165
+ def divide(a, b):
166
+ return a / b
167
+
168
+ divide(10, 0) # Error is explained, then re-raised
169
+ ```
170
+
171
+ ---
172
+
173
+ ## butwhy.fix() — Don't just explain, *fix*
174
+
175
+ After an error, call `butwhy.fix()` to get an AI-generated patch:
176
+
177
+ ```python
178
+ import butwhy
179
+
180
+ data = None
181
+ result = data.split(",") # crashes
182
+
183
+ # In interactive mode:
184
+ >>> butwhy.fix()
185
+
186
+ Suggested fix for demo.py:2
187
+ --------------------------------------------------
188
+ - result = data.split(",")
189
+ + if data is not None:
190
+ + result = data.split(",")
191
+ + else:
192
+ + result = []
193
+ --------------------------------------------------
194
+
195
+ Apply this fix? [y/N] y
196
+ Applied fix to demo.py:2
197
+ ```
198
+
199
+ *Requires an AI provider (OpenAI/Anthropic/Ollama).*
200
+
201
+ ---
202
+
203
+ ## butwhy.this — The Zen of Why
204
+
205
+ ```python
206
+ >>> import butwhy
207
+ >>> butwhy.this
208
+ ```
209
+
210
+ ```
211
+ The Zen of Why, by why
212
+
213
+ Errors are not failures, they are teachers.
214
+ The traceback tells you what; why tells you why.
215
+ A good message answers the question before you ask it.
216
+ Read the variables, not just the line numbers.
217
+ ...
218
+ ```
219
+
220
+ ---
221
+
222
+ ## Jupyter / IPython support
223
+
224
+ ```python
225
+ # In a notebook:
226
+ %load_ext why
227
+
228
+ # Or just:
229
+ import butwhy
230
+
231
+ # Now all cell errors are explained inline
232
+ ```
233
+
234
+ ---
235
+
236
+ ## Configuration
237
+
238
+ All settings via environment variables — no config file needed:
239
+
240
+ | Variable | Default | Description |
241
+ |---|---|---|
242
+ | `OPENAI_API_KEY` | — | OpenAI API key (enables AI explanations) |
243
+ | `ANTHROPIC_API_KEY` | — | Anthropic API key (enables AI explanations) |
244
+ | `BUTWHY_PROVIDER` | `auto` | `auto` / `openai` / `anthropic` / `ollama` / `patterns` |
245
+ | `BUTWHY_LANGUAGE` | `en` | `en` / `zh` (Chinese) |
246
+ | `BUTWHY_MODEL` | — | Override the model name for the active provider |
247
+ | `BUTWHY_TIMEOUT` | `30` | API timeout in seconds |
248
+ | `OLLAMA_URL` | `http://localhost:11434` | Ollama server URL |
249
+ | `OLLAMA_MODEL` | `qwen2.5-coder:7b` | Ollama model to use |
250
+ | `BUTWHY_AUTOSTART` | `1` | Set to `0` to disable auto-install of the hook |
251
+ | `BUTWHY_NO_COLOR` | — | Set to disable colored output |
252
+ | `NO_COLOR` | — | Standard no-color env var (respected) |
253
+
254
+ ### Programmatic config
255
+
256
+ ```python
257
+ import butwhy
258
+
259
+ butwhy.set_config(butwhy.WhyConfig(
260
+ provider="openai",
261
+ openai_api_key="sk-...",
262
+ language="zh", # Chinese explanations
263
+ show_source=True,
264
+ show_vars=True,
265
+ cache=True,
266
+ ))
267
+ ```
268
+
269
+ ---
270
+
271
+ ## How it works
272
+
273
+ `why` uses a **three-layer fallback** to ensure you always get a useful explanation:
274
+
275
+ | Layer | When | How | Quality |
276
+ |---|---|---|---|
277
+ | **AI explanation** | API key available | Sends error + source context + variables to LLM | Best — covers everything, gives specific fixes |
278
+ | **Pattern matching** | No API key (or AI failed) | Heuristic matching on 12+ common error types | Good — covers the errors you hit daily |
279
+ | **Enhanced traceback** | No pattern matched | Colored output with variables and source context | Fallback — still better than default |
280
+
281
+ **Key design principles:**
282
+
283
+ - **Zero dependencies** — pure Python stdlib. No rich, no httpx, no openai SDK. Just `urllib` and friends.
284
+ - **Never crashes** — if the AI fails, pattern matching takes over. If that fails, you still get a prettier traceback.
285
+ - **Privacy-aware** — your code only goes to an LLM if you explicitly set an API key. Pattern matching is 100% local.
286
+ - **Caching** — repeated errors don't re-call the API. Cached for 7 days.
287
+
288
+ ---
289
+
290
+ ## Comparison
291
+
292
+ | Feature | `why` | rich | better-exceptions | stackprinter | Copilot |
293
+ |---|---|---|---|---|---|
294
+ | Works without API key | ✅ | ✅ | ✅ | ✅ | ❌ |
295
+ | AI-powered explanations | ✅ | ❌ | ❌ | ❌ | ✅ |
296
+ | `import` and done | ✅ | ❌ | ❌ | ❌ | ❌ |
297
+ | Local model support | ✅ Ollama | — | — | — | ❌ |
298
+ | Zero dependencies | ✅ | ❌ | ❌ | ❌ | — |
299
+ | Variable values in output | ✅ | ✅ | ✅ | ✅ | ❌ |
300
+ | Auto-fix (`butwhy.fix()`) | ✅ | ❌ | ❌ | ❌ | ✅ |
301
+ | Works in CI/CD & servers | ✅ | ✅ | ✅ | ✅ | ❌ |
302
+ | Chinese explanations | ✅ | ❌ | ❌ | ❌ | ✅ |
303
+ | Jupyter magic | ✅ | ❌ | ❌ | ❌ | ❌ |
304
+
305
+ ---
306
+
307
+ ## Supported error types (pattern matching)
308
+
309
+ The built-in pattern matcher covers these error types without any API key:
310
+
311
+ - `NameError` — undefined variable
312
+ - `TypeError` — wrong type operations
313
+ - `ValueError` — invalid values (int conversion, unpacking)
314
+ - `IndexError` — list index out of range
315
+ - `KeyError` — missing dictionary key
316
+ - `AttributeError` — wrong attribute/method (including NoneType)
317
+ - `ZeroDivisionError` — division by zero
318
+ - `ImportError` / `ModuleNotFoundError` — missing modules (with install hints)
319
+ - `FileNotFoundError` — file path issues
320
+ - `SyntaxError` — common syntax mistakes
321
+ - `RecursionError` — infinite recursion
322
+ - `UnicodeDecodeError` — encoding issues
323
+ - `IndentationError` / `TabError` — indentation problems
324
+
325
+ More patterns are added regularly. With an AI provider, *all* error types are covered.
326
+
327
+ ---
328
+
329
+ ## Examples
330
+
331
+ See the [`examples/`](examples/) directory for runnable demos:
332
+
333
+ - `basic.py` — common errors with pattern matching
334
+ - `with_ai.py` — AI-powered deep explanations
335
+ - `jupyter_demo.ipynb` — notebook usage
336
+ - `fix_demo.py` — auto-fix workflow
337
+
338
+ ---
339
+
340
+ ## Contributing
341
+
342
+ Contributions welcome! Especially:
343
+
344
+ - New pattern matchers for error types not yet covered
345
+ - Translations for `BUTWHY_LANGUAGE`
346
+ - Bug reports and edge cases
347
+
348
+ ```bash
349
+ git clone https://github.com/yourname/butwhy.git
350
+ cd butwhy
351
+ pip install -e ".[dev]"
352
+ pytest
353
+ ```
354
+
355
+ ---
356
+
357
+ ## License
358
+
359
+ MIT — see [LICENSE](LICENSE).
360
+
361
+ ---
362
+
363
+ <div align="center">
364
+
365
+ **`import butwhy`** — because every error deserves an explanation.
366
+
367
+ </div>
butwhy-0.1.0/README.md ADDED
@@ -0,0 +1,331 @@
1
+ <div align="center">
2
+
3
+ # butwhy
4
+
5
+ **Stop guessing. Start understanding.**
6
+
7
+ Your Python errors, explained — in plain English.
8
+
9
+ `pip install butwhy` → `import butwhy` → done.
10
+
11
+ [![PyPI](https://img.shields.io/pypi/v/butwhy)](https://pypi.org/project/butwhy/)
12
+ [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
13
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
14
+ [![CI](https://github.com/yourname/butwhy/actions/workflows/ci.yml/badge.svg)](https://github.com/yourname/butwhy/actions)
15
+ [![Zero Dependencies](https://img.shields.io/badge/dependencies-0-green.svg)](#)
16
+
17
+ </div>
18
+
19
+ ---
20
+
21
+ ## The 30-second pitch
22
+
23
+ You know how Python tracebacks look like this:
24
+
25
+ ```
26
+ Traceback (most recent call last):
27
+ File "demo.py", line 2, in <module>
28
+ result = data.split(",")
29
+ AttributeError: 'NoneType' object has no attribute 'split'
30
+ ```
31
+
32
+ And then you spend 5 minutes on Google figuring out what went wrong?
33
+
34
+ **`why` turns that into this:**
35
+
36
+ ```
37
+ ============================================================
38
+ AttributeError: 'NoneType' object has no attribute 'split'
39
+ at demo.py:2
40
+ ============================================================
41
+
42
+ [pattern match · 93%]
43
+
44
+ Summary:
45
+ Calling .split() on None
46
+
47
+ Cause:
48
+ The variable data is None, not a string.
49
+ This usually means a function returned None (maybe it
50
+ forgot a return statement), or a lookup failed silently.
51
+
52
+ Variables at error:
53
+ data = None (NoneType)
54
+
55
+ Fix:
56
+ Add a None check: if data is not None: data.split(",")
57
+ Or trace back to find why data is None.
58
+
59
+ ============================================================
60
+ ```
61
+
62
+ **One import. Zero config. Instant understanding.**
63
+
64
+ ---
65
+
66
+ ## Quick start
67
+
68
+ ```bash
69
+ pip install butwhy
70
+ ```
71
+
72
+ ```python
73
+ import butwhy # That's it. Errors are now explained.
74
+
75
+ data = None
76
+ result = data.split(",") # Boom — why explains it
77
+ ```
78
+
79
+
80
+
81
+ ### Want AI-powered deep explanations?
82
+
83
+ Set one environment variable and why upgrades automatically:
84
+
85
+ ```bash
86
+ export OPENAI_API_KEY=sk-... # or ANTHROPIC_API_KEY
87
+ ```
88
+
89
+ No API key? **why still works** — it falls back to built-in pattern matching that covers 12+ common error types with zero dependencies.
90
+
91
+ ### Prefer a local model? (No API key, fully offline)
92
+
93
+ ```bash
94
+ # Install Ollama: https://ollama.com
95
+ ollama pull qwen2.5-coder:7b
96
+
97
+ export BUTWHY_PROVIDER=ollama
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Three ways to use why
103
+
104
+ ### 1. Global (recommended) — `import butwhy`
105
+
106
+ ```python
107
+ import butwhy
108
+
109
+ # Every uncaught exception in your script is now explained
110
+ 1 / 0
111
+ ```
112
+
113
+ ### 2. Context manager — `with butwhy.trace()`
114
+
115
+ ```python
116
+ import butwhy
117
+
118
+ with butwhy.trace():
119
+ # Only errors inside this block are explained
120
+ risky_operation()
121
+ ```
122
+
123
+ ### 3. Decorator — `@butwhy.explain`
124
+
125
+ ```python
126
+ import butwhy
127
+
128
+ @butwhy.explain
129
+ def divide(a, b):
130
+ return a / b
131
+
132
+ divide(10, 0) # Error is explained, then re-raised
133
+ ```
134
+
135
+ ---
136
+
137
+ ## butwhy.fix() — Don't just explain, *fix*
138
+
139
+ After an error, call `butwhy.fix()` to get an AI-generated patch:
140
+
141
+ ```python
142
+ import butwhy
143
+
144
+ data = None
145
+ result = data.split(",") # crashes
146
+
147
+ # In interactive mode:
148
+ >>> butwhy.fix()
149
+
150
+ Suggested fix for demo.py:2
151
+ --------------------------------------------------
152
+ - result = data.split(",")
153
+ + if data is not None:
154
+ + result = data.split(",")
155
+ + else:
156
+ + result = []
157
+ --------------------------------------------------
158
+
159
+ Apply this fix? [y/N] y
160
+ Applied fix to demo.py:2
161
+ ```
162
+
163
+ *Requires an AI provider (OpenAI/Anthropic/Ollama).*
164
+
165
+ ---
166
+
167
+ ## butwhy.this — The Zen of Why
168
+
169
+ ```python
170
+ >>> import butwhy
171
+ >>> butwhy.this
172
+ ```
173
+
174
+ ```
175
+ The Zen of Why, by why
176
+
177
+ Errors are not failures, they are teachers.
178
+ The traceback tells you what; why tells you why.
179
+ A good message answers the question before you ask it.
180
+ Read the variables, not just the line numbers.
181
+ ...
182
+ ```
183
+
184
+ ---
185
+
186
+ ## Jupyter / IPython support
187
+
188
+ ```python
189
+ # In a notebook:
190
+ %load_ext why
191
+
192
+ # Or just:
193
+ import butwhy
194
+
195
+ # Now all cell errors are explained inline
196
+ ```
197
+
198
+ ---
199
+
200
+ ## Configuration
201
+
202
+ All settings via environment variables — no config file needed:
203
+
204
+ | Variable | Default | Description |
205
+ |---|---|---|
206
+ | `OPENAI_API_KEY` | — | OpenAI API key (enables AI explanations) |
207
+ | `ANTHROPIC_API_KEY` | — | Anthropic API key (enables AI explanations) |
208
+ | `BUTWHY_PROVIDER` | `auto` | `auto` / `openai` / `anthropic` / `ollama` / `patterns` |
209
+ | `BUTWHY_LANGUAGE` | `en` | `en` / `zh` (Chinese) |
210
+ | `BUTWHY_MODEL` | — | Override the model name for the active provider |
211
+ | `BUTWHY_TIMEOUT` | `30` | API timeout in seconds |
212
+ | `OLLAMA_URL` | `http://localhost:11434` | Ollama server URL |
213
+ | `OLLAMA_MODEL` | `qwen2.5-coder:7b` | Ollama model to use |
214
+ | `BUTWHY_AUTOSTART` | `1` | Set to `0` to disable auto-install of the hook |
215
+ | `BUTWHY_NO_COLOR` | — | Set to disable colored output |
216
+ | `NO_COLOR` | — | Standard no-color env var (respected) |
217
+
218
+ ### Programmatic config
219
+
220
+ ```python
221
+ import butwhy
222
+
223
+ butwhy.set_config(butwhy.WhyConfig(
224
+ provider="openai",
225
+ openai_api_key="sk-...",
226
+ language="zh", # Chinese explanations
227
+ show_source=True,
228
+ show_vars=True,
229
+ cache=True,
230
+ ))
231
+ ```
232
+
233
+ ---
234
+
235
+ ## How it works
236
+
237
+ `why` uses a **three-layer fallback** to ensure you always get a useful explanation:
238
+
239
+ | Layer | When | How | Quality |
240
+ |---|---|---|---|
241
+ | **AI explanation** | API key available | Sends error + source context + variables to LLM | Best — covers everything, gives specific fixes |
242
+ | **Pattern matching** | No API key (or AI failed) | Heuristic matching on 12+ common error types | Good — covers the errors you hit daily |
243
+ | **Enhanced traceback** | No pattern matched | Colored output with variables and source context | Fallback — still better than default |
244
+
245
+ **Key design principles:**
246
+
247
+ - **Zero dependencies** — pure Python stdlib. No rich, no httpx, no openai SDK. Just `urllib` and friends.
248
+ - **Never crashes** — if the AI fails, pattern matching takes over. If that fails, you still get a prettier traceback.
249
+ - **Privacy-aware** — your code only goes to an LLM if you explicitly set an API key. Pattern matching is 100% local.
250
+ - **Caching** — repeated errors don't re-call the API. Cached for 7 days.
251
+
252
+ ---
253
+
254
+ ## Comparison
255
+
256
+ | Feature | `why` | rich | better-exceptions | stackprinter | Copilot |
257
+ |---|---|---|---|---|---|
258
+ | Works without API key | ✅ | ✅ | ✅ | ✅ | ❌ |
259
+ | AI-powered explanations | ✅ | ❌ | ❌ | ❌ | ✅ |
260
+ | `import` and done | ✅ | ❌ | ❌ | ❌ | ❌ |
261
+ | Local model support | ✅ Ollama | — | — | — | ❌ |
262
+ | Zero dependencies | ✅ | ❌ | ❌ | ❌ | — |
263
+ | Variable values in output | ✅ | ✅ | ✅ | ✅ | ❌ |
264
+ | Auto-fix (`butwhy.fix()`) | ✅ | ❌ | ❌ | ❌ | ✅ |
265
+ | Works in CI/CD & servers | ✅ | ✅ | ✅ | ✅ | ❌ |
266
+ | Chinese explanations | ✅ | ❌ | ❌ | ❌ | ✅ |
267
+ | Jupyter magic | ✅ | ❌ | ❌ | ❌ | ❌ |
268
+
269
+ ---
270
+
271
+ ## Supported error types (pattern matching)
272
+
273
+ The built-in pattern matcher covers these error types without any API key:
274
+
275
+ - `NameError` — undefined variable
276
+ - `TypeError` — wrong type operations
277
+ - `ValueError` — invalid values (int conversion, unpacking)
278
+ - `IndexError` — list index out of range
279
+ - `KeyError` — missing dictionary key
280
+ - `AttributeError` — wrong attribute/method (including NoneType)
281
+ - `ZeroDivisionError` — division by zero
282
+ - `ImportError` / `ModuleNotFoundError` — missing modules (with install hints)
283
+ - `FileNotFoundError` — file path issues
284
+ - `SyntaxError` — common syntax mistakes
285
+ - `RecursionError` — infinite recursion
286
+ - `UnicodeDecodeError` — encoding issues
287
+ - `IndentationError` / `TabError` — indentation problems
288
+
289
+ More patterns are added regularly. With an AI provider, *all* error types are covered.
290
+
291
+ ---
292
+
293
+ ## Examples
294
+
295
+ See the [`examples/`](examples/) directory for runnable demos:
296
+
297
+ - `basic.py` — common errors with pattern matching
298
+ - `with_ai.py` — AI-powered deep explanations
299
+ - `jupyter_demo.ipynb` — notebook usage
300
+ - `fix_demo.py` — auto-fix workflow
301
+
302
+ ---
303
+
304
+ ## Contributing
305
+
306
+ Contributions welcome! Especially:
307
+
308
+ - New pattern matchers for error types not yet covered
309
+ - Translations for `BUTWHY_LANGUAGE`
310
+ - Bug reports and edge cases
311
+
312
+ ```bash
313
+ git clone https://github.com/yourname/butwhy.git
314
+ cd butwhy
315
+ pip install -e ".[dev]"
316
+ pytest
317
+ ```
318
+
319
+ ---
320
+
321
+ ## License
322
+
323
+ MIT — see [LICENSE](LICENSE).
324
+
325
+ ---
326
+
327
+ <div align="center">
328
+
329
+ **`import butwhy`** — because every error deserves an explanation.
330
+
331
+ </div>