8000 feat(python): add an opinionated swallowed-exception guide by LiinaSuoniemi · Pull Request #70 · habit-hooks/habit-hooks · GitHub
[go: up one dir, main page]

Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions docs/habit-mapper.spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,55 @@ habit-mapper
biome: prefer `===`/`!==` over loose equality.
```

### The python plugin ships an opinionated swallowed-exception guide

`swallowed-exception` comes only from ruff (`BLE001`), so it is python-only. The
python plugin ships its own guide for it, so a `["python"]` config coaches it
directly with no `generic` present. The guide inlines its own line listing rather
than the generic `includes/line_level_issues.md`, so it never depends on `generic`
being installed. It is `suggested`, so it coaches but the run stays green.

📄.habit-hooks/config.toml
```toml
plugins = ["python"]
```

⌨️
```json
[
{
"smell": "swallowed-exception",
"language": "python",
"details": {},
"issues": [
{ "key": "src/loader.py:4", "details": { "file": "src/loader.py", "line": 4 } }
]
}
]
```

```bash
habit-mapper
```

🖥️ ✅
```text
── swallowed-exception (1 issue) ──

A broad `except` (`except:`, `except Exception`, `except BaseException`) that discards the error silently is hiding a failure you have not understood, not handling one you planned for. Before you write it, name the specific error you expect and why. That one sentence is usually the fix.

src/loader.py:4
Work through it in order:

1. **Catch only what you can name.** `ValueError`, `KeyError`, `TimeoutError`, whatever the call really raises. If you cannot name it, you are guessing, and every other error should stay free to surface where someone can see it.
2. **Make the decision visible.** Recover from it, add context and re-raise (`raise ... from err`), or, at a boundary that has to stay alive, log the full traceback (`logging.exception(...)`) and continue. Logging and returning a default is a real option, not automatically a swallow.
3. **The test is not whether you re-raised.** Ask one question: if this fires at 3am, will anyone know it happened, and will they know why? What turns a catch into a swallow is doing it blindly: a wide catch, no named error, nothing logged, the failure gone without a trace. If the answer is no, it is still a swallow, however you dressed it up.

Narrowing the type or adding `# noqa` only to quiet ruff is not a fix if the error is still discarded.

If you are unsure whether this catch is a real decision or a reflex, check with a human before you keep it.
```

### An unknown smell escalates with the default guidance

A smell with no catalogue entry has no tuned guide. It defaults to `enforced`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
A broad `except` (`except:`, `except Exception`, `except BaseException`) that discards the error silently is hiding a failure you have not understood, not handling one you planned for. Before you write it, name the specific error you expect and why. That one sentence is usually the fix.

{% for issue in issues -%}
{{ issue.details.file }}:{{ issue.details.line }}{% if issue.details.content %} {{ issue.details.content }}{% endif %}
{% endfor -%}
Work through it in order:

1. **Catch only what you can name.** `ValueError`, `KeyError`, `TimeoutError`, whatever the call really raises. If you cannot name it, you are guessing, and every other error should stay free to surface where someone can see it.
2. **Make the decision visible.** Recover from it, add context and re-raise (`raise ... from err`), or, at a boundary that has to stay alive, log the full traceback (`logging.exception(...)`) and continue. Logging and returning a default is a real option, not automatically a swallow.
3. **The test is not whether you re-raised.** Ask one question: if this fires at 3am, will anyone know it happened, and will they know why? What turns a catch into a swallow is doing it blindly: a wide catch, no named error, nothing logged, the failure gone without a trace. If the answer is no, it is still a swallow, however you dressed it up.

Narrowing the type or adding `# noqa` only to quiet ruff is not a fix if the error is still discarded.

If you are unsure whether this catch is a real decision or a reflex, check with a human before you keep it.
Loading
0