claude-skills/engineering-team/skills/code-reviewer/languages/python.md
fouad 14c645ba16 refactor(code-reviewer): — universal rules + per-language files
- Extract commun languages rules in a separate rules/universal.md containing all cross-language rules in one place
- Move language-specific rules inline into each languages/*.md file,
  organised into consistent sections: Security / Async / Resource
  Management / Exception Handling / Performance / Idioms
- Add Java support: languages/java.md with full section coverage
- Every review now requires exactly 2 file reads: universal.md +
  one language file
- Add "Adding a new language" guide to SKILL.md: one file to create,
  nothing else changes
2026-05-25 13:15:37 +01:00

94 lines
3.3 KiB
Markdown

---
language: python
extensions: [".py"]
---
# Python — Language-Specific Review Notes
Load this file alongside `rules/universal.md`. Universal rules are not repeated here — only Python-specific rules and idioms.
---
## PR Analyzer — Python Risk Signals
- `print()` statements left in production code
- `# noqa` and `# type: ignore` comments — verify they are justified
- `eval()` / `exec()` with any user-controlled input
- `pickle` used to deserialize untrusted data
- Hardcoded credentials or tokens in source
---
## Code Quality — Python Checks
- Bare `except:` or `except Exception:` swallowing silently
- Mutable default arguments (`def foo(items=[])`) — shared across calls
- `import *` — pollutes namespace and hides dependencies
- Missing type hints on public functions and methods
- `assert` used for runtime validation — stripped by `-O` flag
---
## Security
- Flag `eval()` / `exec()` with any user-controlled input
- Flag `pickle.loads()` on untrusted data — use `json` or `msgpack`
- Flag `subprocess` calls with `shell=True` and user input
- Flag `flask.render_template_string()` with user data (SSTI)
- Flag `SECRET_KEY` / `DEBUG = True` committed to source
---
## Async
- Flag `asyncio.get_event_loop().run_until_complete()` inside an already-running loop
- Flag mixing `threading` and `asyncio` without a clear bridge (`run_in_executor`)
- Flag CPU-bound work inside an `async def` without offloading to `ProcessPoolExecutor`
- Flag `time.sleep()` inside async functions — use `await asyncio.sleep()`
---
## Resource Management
- Flag `open()` not used as a context manager (`with open(...) as f`)
- Flag `requests.Session` created per-request instead of shared/reused
- Flag database connections not closed or returned to a pool on all paths
- Flag large files read entirely into memory with `.read()` — prefer streaming / chunked reads
---
## Exception Handling
- Flag bare `except:` — catches `BaseException` including `KeyboardInterrupt` and `SystemExit`
- Flag `except Exception: pass` — silently swallows errors
- Flag re-raising with `raise e` instead of `raise` — loses the original traceback
- Flag `except` clause too broad when the `try` block covers multiple operations with different failure modes — split them
---
## Performance
- Flag `+` string concatenation in loops — use `"".join()`
- Flag repeated `re.compile()` inside a loop — compile once at module level
- Flag `list.append()` in a loop where a list comprehension would be more efficient
- Flag `in` membership tests on `list` where the collection is large — use `set`
- Flag loading entire large files into memory — prefer streaming or chunked reads
---
## Idioms and Best Practices
### Type Safety
- All public functions and methods should have type annotations
- Prefer `X | None` (Python 3.10+) over `Optional[X]`
- Use `TypedDict` or `dataclass` over plain `dict` for structured data
### Modern Python (3.10+)
- Prefer `match` statements over long `if/elif` chains
- Prefer `dataclass` or `NamedTuple` over plain classes for data carriers
- Prefer `pathlib.Path` over `os.path` for file operations
- Prefer f-strings over `.format()` or `%` formatting
### None Safety
- Prefer explicit `if x is None` over falsy checks when `0` or `""` are valid values
- Flag functions returning `None` implicitly — make it explicit or raise