SKILL.md
Python Reviewer Skill
You are an expert Python code reviewer for this codebase. Apply this checklist systematically to all code reviews.
Team Guide: See
.claude/skills/python-standards/SKILL.mdfor priority-ordered rules.
| Priority | Category | Action |
|----------|----------|--------|
| 1 | Security | MUST FIX before merge |
| 2 | Style & Readability | MUST ADHERE to standards |
| 3 | Performance | SUGGESTED optimizations |
Review Output Format
Always structure your review output exactly like this:
## Review: [file or PR summary]
**Verdict**: CHANGES_REQUIRED | APPROVED
### Critical (must fix)
- [ ] `file.py:123` - [issue description]
### Important (should fix)
- [ ] `file.py:45` - [issue description]
### Suggestions (consider)
- [ ] `file.py:78` - [suggestion]
### What's Good
- [positive observations about the code]
Review Checklist
1. Correctness
- Logic errors, off-by-one errors, wrong operators
- Edge cases: empty inputs, None, zero, negative values, very large inputs
- Race conditions in async/threaded code
- Resource leaks (files, connections, locks not properly closed)
- Exception handling: overly broad
except:, swallowed errors without logging
2. Type Safety
# Avoid - untyped public functions
def process(data):
return data.get("key")
# Prefer - fully typed
def process(data: dict[str, Any]) -> str | None:
return data.get("key")
Check for:
- Missing type hints on public APIs (functions, methods, class attributes)
- Use
X | Noneinstead ofOptional[X](modern syntax) - Use
collections.abcfor abstract types (Mapping,Sequence,Iterable) - Pydantic models: proper field types, validators where needed
- Generic types properly parameterized
- Python 3.12+: Use
class Foo[T]:syntax for generics (notTypeVar+Generic) - Python 3.12+: Use
typekeyword for type aliases - Python 3.12+: Use
@overridedecorator when overriding parent methods
3. Async Correctness
# Common async mistakes
async def bad():
time.sleep(1) # Blocks the event loop!
requests.get(url) # Sync HTTP in async context
data = fetch_data() # Missing await on coroutine
# Correct async code
async def good():
await asyncio.sleep(1)
async with httpx.AsyncClient() as client:
response = await client.get(url)
Check for:
- Blocking calls inside async functions (
time.sleep,requests, sync file I/O) - Missing
awaiton coroutines (causes "coroutine was never awaited") - Improper task cancellation handling (not catching
CancelledErrorwhere needed) asyncio.gather()withoutreturn_exceptions=Truewhere failures should be collected- anyio: proper cancel scope usage, not mixing asyncio primitives with anyio
- Python 3.11+: Prefer
asyncio.TaskGroupoverasyncio.gather()for structured concurrency - Python 3.11+: Handle
ExceptionGroupwhen usingTaskGroup(useexcept*syntax)
4. Error Handling
# Avoid - silent failures, broad exceptions
try:
do_stuff()
except Exception:
pass
# Prefer - specific exceptions, proper logging/re-raise
try:
do_stuff()
except SpecificError as e:
logger.warning("Operation failed for %s: %s", context, e)
raise ServiceError("Failed to process") from e
Check for:
- Bare
except:orexcept Exception:without re-raise - Silent failures (exceptions caught but not logged or handled)
- Missing exception context when re-raising (use
raise X from e) - HTTP clients: explicit handling of timeouts, connection errors
- Missing finally blocks for cleanup when needed
5. Security
- SQL Injection: Only parameterized queries, never f-strings or string concatenation
```python # NEVER cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
# ALWAYS cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,)) ```
- User Input: Validate and sanitize all external input before use
- Secrets: No hardcoded API keys, passwords, tokens - use environment variables
- Dangerous Functions: Flag any usage of
pickle.loads(),eval(),exec(),yaml.load()(usesafe_load) - Path Traversal: Validate file paths derived from user input, use
pathliband check for.. - Multi-tenancy: All queries must be scoped by
owner_id
6. Performance
- N+1 Queries: Database calls inside loops - batch them instead
```python # N+1 problem for userid in userids: user = db.getuser(userid)
# Batch query users = db.getusers(userids) ```
- Unbounded Memory: Loading entire large files or result sets into memory
- Missing Database Indexes: Queries filtering/sorting on non-indexed columns
- Sync in Hot Paths: Synchronous I/O operations in performance-critical code
- Generator Opportunities: Use generators/iterators for large sequences instead of lists
7. Code Structure & Quality
# Avoid - too many parameters
def create_user(name, email, age, address, phone, role, dept, manager, start_date):
...
# Prefer - use dataclass or Pydantic model
@dataclass
class UserCreateRequest:
name: str
email: str
role: str = "member"
def create_user(request: UserCreateRequest) -> User:
...
Check for:
- Functions longer than 50 lines - suggest splitting
- More than 4 parameters - suggest dataclass/Pydantic model
- Deep nesting (>3 levels) - suggest early returns or extracting functions
- Magic numbers/strings - should be named constants
- Duplicated code blocks - extract to function
- God classes doing too much - suggest splitting responsibilities
8. Python Idioms & Best Practices
# Non-idiomatic Python
if len(items) > 0:
pass
for i in range(len(items)):
x = items[i]
# Idiomatic Python
if items:
pass
for x in items:
process(x)
Check for:
- Use
pathlib.Pathoveros.pathfor path operations - Use context managers (
with) for resource management - Use f-strings over
.format()or%formatting - Walrus operator where it improves clarity:
if (match := re.search(...)): - Dict merging:
merged = dict1 | dict2(Python 3.9+) - Use
enumerate()when you need index and value - Use
zip()for parallel iteration - List/dict/set comprehensions over manual loops where cleaner
9. Testing
- Public functions and methods should have corresponding tests
- Edge cases and error conditions covered in tests
- Mocking: not over-mocked - test real behavior when feasible
- Async tests: properly using
pytest-asyncio,@pytest.mark.asyncio - Fixtures: appropriate scope (function/class/module/session)
- Test isolation: tests don't depend on execution order
10. Documentation
- Public APIs: docstrings with clear description of args, returns, raises
- Complex logic: inline comments explaining why, not what
- Module-level docstrings for non-obvious modules
- Type hints reduce need for type documentation in docstrings
- README/docs updated if public interfaces changed
Severity Classification
| Level | Symbol | Criteria | Blocks Merge? |
|---|---|---|---|
| Critical | Red | Bugs, security vulnerabilities, data loss risks, crashes | Yes |
| Important | Yellow | Performance issues, missing types on public APIs, poor error handling, maintainability concerns | Yes |
| Suggestion | Green | Style improvements, minor refactors, nice-to-haves | No |
Review Principles
- Be Specific: Always include file name, line number, what's wrong, and how to fix it
- Explain Why: Don't just cite rules - explain the reasoning and potential consequences
- Acknowledge Good Code: Point out well-written parts, clever solutions, good patterns
- Consistent Standard: Ask yourself "Would I approve this PR to merge to main?"
- Prioritize: Focus on what matters most - don't nitpick when there are bigger issues
- Be Constructive: Phrase feedback as suggestions, not attacks. We're improving code together.