Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

5 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🐍 Python Exception-Handling Audit Lab

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.

CI Python Tests License


🎯 What This Lab Teaches

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

πŸ“ Repo Structure

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

πŸš€ Quick Start (macOS / Linux)

# 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-update

Expected output:

30 passed in 0.20s βœ…

πŸ”¬ The Three Lab Files Explained

File 1 β€” original/file1_bare_except.py πŸ”΄

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.

File 2 β€” original/file2_no_handling.py πŸ”΄

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 changes

What goes wrong: The program hangs indefinitely on network issues; schema changes crash it silently.

File 3 β€” original/file3_mixed.py 🟑

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")

πŸ§ͺ Snapshot Testing

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-update

Normal runs (compares against committed snapshots):

pytest tests/ -v

If 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.

πŸ” Key Findings

❌ Unraisable Exceptions (AI Got These Wrong)

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

βœ… Missed Realistic Exceptions (AI Missed These)

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

πŸ“‹ Validation Process (for your own code)

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

πŸƒ Running on macOS β€” Step by Step

# 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

🀝 Contributing

  1. Fork the repo
  2. Create a branch: git checkout -b fix/my-finding
  3. Add a test in tests/test_failure_injection.py that proves your finding
  4. Run pytest tests/ -v --snapshot-update
  5. Open a PR with a clear description of what exception is wrong and why

πŸ“š References


πŸ“„ License

MIT β€” use freely for learning, teaching, or portfolio projects.


βœ… Verified on macOS (Local Run Proof)

All 30 tests confirmed passing on a real MacBook Pro β€” Python 3.10.5, pytest 9.1.0.

Step 1 β€” Install dependencies

Install dependencies

Step 2 β€” First run: write snapshots (--snapshot-update)

Snapshot update run β€” 30 passed

Step 3 β€” Clean run: validate against snapshots

Clean test run β€” 30 passed in 0.13s

Platform: darwin Β· Python 3.10.5 Β· pytest 9.1.0 Β· pluggy 1.6.0

About

AI-assisted Python exception-handling audit lab with failure-injection tests and snapshot testing

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages