Initial commit
This commit is contained in:
220
skills/python-reviewer/SKILL.md
Normal file
220
skills/python-reviewer/SKILL.md
Normal file
@@ -0,0 +1,220 @@
|
||||
---
|
||||
name: python-reviewer
|
||||
description: |
|
||||
WHEN: General Python code review, PEP8 compliance, type hints, Pythonic patterns
|
||||
WHAT: PEP8/style check + Type hint validation + Pythonic idioms + Error handling + Documentation
|
||||
WHEN NOT: FastAPI → fastapi-reviewer, Django → django-reviewer, Data science → python-data-reviewer
|
||||
---
|
||||
|
||||
# Python Reviewer Skill
|
||||
|
||||
## Purpose
|
||||
Reviews Python code for style, idioms, type safety, and best practices.
|
||||
|
||||
## When to Use
|
||||
- Python code review requests
|
||||
- PEP8 compliance check
|
||||
- Type hint review
|
||||
- "Is this Pythonic?" questions
|
||||
- General Python project review
|
||||
|
||||
## Project Detection
|
||||
- `requirements.txt`, `pyproject.toml`, `setup.py`, `setup.cfg`
|
||||
- `.py` files in project
|
||||
- `__init__.py` module structure
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Analyze Project
|
||||
```
|
||||
**Python Version**: 3.11+
|
||||
**Package Manager**: pip/poetry/uv
|
||||
**Type Checking**: mypy/pyright
|
||||
**Linter**: ruff/flake8/pylint
|
||||
**Formatter**: black/ruff
|
||||
```
|
||||
|
||||
### Step 2: Select Review Areas
|
||||
**AskUserQuestion:**
|
||||
```
|
||||
"Which areas to review?"
|
||||
Options:
|
||||
- Full Python review (recommended)
|
||||
- PEP8/Style compliance
|
||||
- Type hints and safety
|
||||
- Error handling patterns
|
||||
- Performance and idioms
|
||||
multiSelect: true
|
||||
```
|
||||
|
||||
## Detection Rules
|
||||
|
||||
### PEP8 & Style
|
||||
| Check | Recommendation | Severity |
|
||||
|-------|----------------|----------|
|
||||
| Line > 88 chars | Break line or refactor | LOW |
|
||||
| Missing docstring | Add module/function docstring | MEDIUM |
|
||||
| Import order wrong | Use isort or ruff | LOW |
|
||||
| Inconsistent naming | snake_case for functions/vars | MEDIUM |
|
||||
|
||||
```python
|
||||
# BAD: Inconsistent naming
|
||||
def getUserName(userId):
|
||||
pass
|
||||
|
||||
# GOOD: PEP8 naming
|
||||
def get_user_name(user_id: int) -> str:
|
||||
pass
|
||||
```
|
||||
|
||||
### Type Hints
|
||||
| Check | Recommendation | Severity |
|
||||
|-------|----------------|----------|
|
||||
| Missing return type | Add -> ReturnType | MEDIUM |
|
||||
| Any type overuse | Use specific types | MEDIUM |
|
||||
| Optional without None check | Add None handling | HIGH |
|
||||
| Missing generic types | Use list[T], dict[K,V] | LOW |
|
||||
|
||||
```python
|
||||
# BAD: No type hints
|
||||
def process(data):
|
||||
return data.get("name")
|
||||
|
||||
# GOOD: Full type hints
|
||||
def process(data: dict[str, Any]) -> str | None:
|
||||
return data.get("name")
|
||||
```
|
||||
|
||||
### Pythonic Idioms
|
||||
| Check | Recommendation | Severity |
|
||||
|-------|----------------|----------|
|
||||
| Manual loop for list | Use list comprehension | LOW |
|
||||
| if x == True | Use if x | LOW |
|
||||
| Manual dict iteration | Use .items(), .keys(), .values() | LOW |
|
||||
| try/except pass | Handle or log exception | HIGH |
|
||||
| Mutable default arg | Use None default | CRITICAL |
|
||||
|
||||
```python
|
||||
# BAD: Mutable default argument
|
||||
def append_to(item, target=[]):
|
||||
target.append(item)
|
||||
return target
|
||||
|
||||
# GOOD: None default
|
||||
def append_to(item, target: list | None = None) -> list:
|
||||
if target is None:
|
||||
target = []
|
||||
target.append(item)
|
||||
return target
|
||||
|
||||
# BAD: Manual loop
|
||||
result = []
|
||||
for x in items:
|
||||
if x > 0:
|
||||
result.append(x * 2)
|
||||
|
||||
# GOOD: List comprehension
|
||||
result = [x * 2 for x in items if x > 0]
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
| Check | Recommendation | Severity |
|
||||
|-------|----------------|----------|
|
||||
| Bare except | Catch specific exceptions | HIGH |
|
||||
| except Exception | Be more specific | MEDIUM |
|
||||
| No logging in except | Add logging | MEDIUM |
|
||||
| Missing finally | Add cleanup if needed | LOW |
|
||||
|
||||
```python
|
||||
# BAD: Bare except
|
||||
try:
|
||||
process()
|
||||
except:
|
||||
pass
|
||||
|
||||
# GOOD: Specific exception with logging
|
||||
try:
|
||||
process()
|
||||
except ValueError as e:
|
||||
logger.error(f"Invalid value: {e}")
|
||||
raise
|
||||
except IOError as e:
|
||||
logger.warning(f"IO error: {e}")
|
||||
return None
|
||||
```
|
||||
|
||||
### Modern Python (3.10+)
|
||||
| Check | Recommendation | Severity |
|
||||
|-------|----------------|----------|
|
||||
| Union[X, Y] | Use X \| Y | LOW |
|
||||
| Optional[X] | Use X \| None | LOW |
|
||||
| Dict, List from typing | Use dict, list builtin | LOW |
|
||||
| No match statement | Consider match for complex branching | LOW |
|
||||
|
||||
```python
|
||||
# OLD: typing imports
|
||||
from typing import Optional, Union, List, Dict
|
||||
|
||||
def func(x: Optional[int]) -> Union[str, None]:
|
||||
pass
|
||||
|
||||
# MODERN: Built-in syntax (3.10+)
|
||||
def func(x: int | None) -> str | None:
|
||||
pass
|
||||
|
||||
# Match statement (3.10+)
|
||||
match status:
|
||||
case 200:
|
||||
return "OK"
|
||||
case 404:
|
||||
return "Not Found"
|
||||
case _:
|
||||
return "Unknown"
|
||||
```
|
||||
|
||||
## Response Template
|
||||
```
|
||||
## Python Code Review Results
|
||||
|
||||
**Project**: [name]
|
||||
**Python**: 3.11 | **Tools**: ruff, mypy, pytest
|
||||
|
||||
### Style & PEP8
|
||||
| Status | File | Issue |
|
||||
|--------|------|-------|
|
||||
| LOW | utils.py:45 | Line exceeds 88 characters |
|
||||
|
||||
### Type Hints
|
||||
| Status | File | Issue |
|
||||
|--------|------|-------|
|
||||
| MEDIUM | service.py:23 | Missing return type annotation |
|
||||
|
||||
### Pythonic Idioms
|
||||
| Status | File | Issue |
|
||||
|--------|------|-------|
|
||||
| CRITICAL | models.py:12 | Mutable default argument |
|
||||
|
||||
### Error Handling
|
||||
| Status | File | Issue |
|
||||
|--------|------|-------|
|
||||
| HIGH | api.py:67 | Bare except clause |
|
||||
|
||||
### Recommended Actions
|
||||
1. [ ] Fix mutable default arguments
|
||||
2. [ ] Add specific exception handling
|
||||
3. [ ] Add type hints to public functions
|
||||
4. [ ] Run ruff --fix for style issues
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
1. **Type Hints**: Use for all public APIs
|
||||
2. **Docstrings**: Google or NumPy style
|
||||
3. **Error Handling**: Specific exceptions, always log
|
||||
4. **Testing**: pytest with fixtures
|
||||
5. **Tooling**: ruff (lint+format), mypy (types)
|
||||
|
||||
## Integration
|
||||
- `fastapi-reviewer`: FastAPI specific patterns
|
||||
- `django-reviewer`: Django specific patterns
|
||||
- `python-data-reviewer`: Pandas/NumPy patterns
|
||||
- `security-scanner`: Python security checks
|
||||
Reference in New Issue
Block a user