AI catches the unraisable; you catch what AI missed.
A hands-on lab that teaches you to audit Python exception handling using AI as a first-pass tool β then validates every suggestion against the real docs.
| Skill | Description |
|---|---|
| AI auditing | Use Claude/ChatGPT as a fast first pass for exception reviews |
| Validation | Cross-check every AI suggestion against docs.python.org |
| Unraisable detection | Prove when an exception cannot fire on a given code path |
| Failure injection | Mock network calls and feed malformed input to test error paths |
| Snapshot testing | Lock expected outputs so regressions are caught automatically |
python-exception-audit-lab/
β
βββ original/ # The 3 buggy lab files (study these first)
β βββ file1_bare_except.py # π΄ Bare except everywhere (over-catching)
β βββ file2_no_handling.py # π΄ No exception handling at all
β βββ file3_mixed.py # π‘ Mixed quality (correct + wrong + obsolete)
β
βββ refactored/ # β
Fixed versions with validated exception handling
β βββ file1_refactored.py
β βββ file2_refactored.py
β βββ file3_refactored.py
β
βββ tests/
β βββ test_failure_injection.py # 30 tests using mocks + malformed input
β βββ snapshots/ # Committed golden outputs
β βββ fetch_weather_success.txt
β βββ summarize_valid_output.txt
β βββ ...
β
βββ docs/
β βββ findings.md # Full audit report: unraisable + missed exceptions
β
βββ conftest.py # Pytest config: sys.path + snapshot fixture
βββ requirements.txt
βββ .github/workflows/ci.yml # Runs on Python 3.10, 3.11, 3.12
# 1. Clone
git clone https://github.com/iamwaqarjaved/python-exception-audit-lab.git
cd python-exception-audit-lab
# 2. Create a virtual environment
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
# 3. Install dependencies
pip install -r requirements.txt
# 4. Run all tests
pytest tests/ -v
# 5. Update snapshots (after intentional changes)
pytest tests/ -v --snapshot-updateExpected output:
30 passed in 0.20s β
Uses bare except: on every single try block. This is the most dangerous pattern:
# BAD β swallows KeyboardInterrupt, SystemExit, everything
try:
with open(CONFIG_PATH, "r") as f:
data = json.load(f)
return data
except:
return {}What goes wrong: Ctrl-C stops working. Background threads can't signal the process. Real errors become invisible.
Calls the Open-Meteo weather API with no timeout and no error handling:
response = requests.get(url, params=params) # hangs forever on slow network
data = response.json()
return data["current_weather"]["temperature"] # KeyError if API schema changesWhat goes wrong: The program hangs indefinitely on network issues; schema changes crash it silently.
Has exception handling, but with three critical mistakes:
except ValueError: # β requests never raises ValueError β it raises JSONDecodeError
return {}
except IOError: # β IOError is an obsolete alias for OSError since Python 3.3
return {}And this silent dead-code bug:
except FileNotFoundError: # β open() in 'w' mode CREATES the file β FNF never fires here
print("Could not save results")Snapshots lock the expected output of key functions so regressions are caught automatically.
tests/snapshots/
fetch_weather_success.txt β "31.5"
summarize_valid_output.txt β "7-day avg max: 30.0Β°C"
fetch_weather_schema_error_msg.txt β "Unexpected API schema β missing key 'current_weather'"
...
First-time setup (writes snapshots):
pytest tests/ -v --snapshot-updateNormal runs (compares against committed snapshots):
pytest tests/ -vIf a snapshot doesn't match, pytest tells you exactly what changed:
Snapshot mismatch for 'summarize_valid_output':
Expected: '7-day avg max: 30.0Β°C'
Got: '7-day average: 30.0Β°C'
Re-run with --snapshot-update to accept new output.
| Exception | Where Suggested | Why It Cannot Raise |
|---|---|---|
TypeError |
open(CONFIG_PATH) |
CONFIG_PATH is a hard-coded str literal; open() only raises TypeError for non-path-like types |
FileNotFoundError |
open(path, 'w') |
Write mode uses O_CREAT β the OS creates the file if absent |
OverflowError |
float(string) |
Python string β float conversion never overflows; only C-level doubles can |
EnvironmentError |
os.environ[key] |
EnvironmentError is an OSError alias; dict-style env access only raises KeyError |
UnicodeDecodeError |
response.json() |
requests decodes internally; the caller never handles raw bytes |
| Exception | Where | Why It Matters |
|---|---|---|
requests.exceptions.Timeout |
requests.get() with no timeout= |
Without timeout=N, the call hangs forever on a slow server |
KeyError |
data["current_weather"]["temperature"] |
API schema can change; assumes a fixed response structure |
ZeroDivisionError |
sum(temps) / len(temps) |
Empty forecast list β division by zero |
Use this checklist before trusting any AI exception audit:
For every external boundary (file I/O, HTTP, subprocess, DB):
β‘ Resource absent? β FileNotFoundError, KeyError
β‘ No permission? β PermissionError (OSError subclass)
β‘ Wrong format? β json.JSONDecodeError, ValueError
β‘ Timeout? β requests.exceptions.Timeout (requires timeout= param!)
β‘ Schema changed? β KeyError on dict access
β‘ Version correct? β IOError obsolete since Python 3.3; JSONDecodeError since requests 2.28
β‘ Is this value always a str? β Then TypeError cannot raise
β‘ Is this file always opened in 'w'? β Then FileNotFoundError cannot raise
# Check Python version (need 3.10+)
python3 --version
# Clone and enter repo
git clone https://github.com/iamwaqarjaved/python-exception-audit-lab.git
cd python-exception-audit-lab
# Create isolated environment
python3 -m venv .venv
source .venv/bin/activate
# Install
pip install -r requirements.txt
# First run β generates snapshots
pytest tests/ -v --snapshot-update
# Subsequent runs β validates against snapshots
pytest tests/ -v
# Run with coverage (optional)
pip install pytest-cov
pytest tests/ -v --cov=refactored --cov-report=term-missing- Fork the repo
- Create a branch:
git checkout -b fix/my-finding - Add a test in
tests/test_failure_injection.pythat proves your finding - Run
pytest tests/ -v --snapshot-update - Open a PR with a clear description of what exception is wrong and why
- Python Exception Hierarchy
- Python
open()docs - requests Exception Docs
- PEP 3151 β OSError/IOError unification
- requests 2.28 changelog β JSONDecodeError
MIT β use freely for learning, teaching, or portfolio projects.
All 30 tests confirmed passing on a real MacBook Pro β Python 3.10.5, pytest 9.1.0.
Platform: darwin Β· Python 3.10.5 Β· pytest 9.1.0 Β· pluggy 1.6.0


