
python-dev-guidelines
by NmBoyd
Setup for claude code
SKILL.md
name: python-dev-guidelines description: Python development guidelines for modern Python projects. Use when creating Python modules, classes, functions, scripts, or working with type hints, pytest, packaging (pip/poetry), virtual environments, async/await, data classes, or Python best practices. Covers project structure, typing, testing patterns, error handling, logging, and Pythonic idioms.
Python Development Guidelines
Purpose
Establish consistency and best practices for Python development, covering modern Python 3.12+ patterns, type safety, testing, and project organization.
Standards Overview
| Category | Standard |
|---|---|
| Python | 3.12+, FastAPI, async/await preferred |
| Formatting | ruff (96-char lines, double quotes, sorted imports) |
| Typing | Strict (Pydantic v2 models preferred); from __future__ import annotations |
| Naming | snake_case (functions/variables), PascalCase (classes), SCREAMING_SNAKE (constants) |
| Error Handling | Typed exceptions; context managers for resources |
| Documentation | Google-style docstrings for public functions/classes |
| Testing | Separate test files matching source file patterns |
When to Use This Skill
Automatically activates when working on:
- Creating or modifying Python files (
.py) - Writing classes, functions, or modules
- Setting up Python projects (pyproject.toml, setup.py)
- Writing tests with pytest
- Working with type hints and mypy
- Async/await patterns with FastAPI
- Package management (pip, poetry, conda)
Quick Start
New Python Project Checklist
- Python version: 3.12+ specified in
.python-version - Project structure: src layout or flat layout
- pyproject.toml: Modern packaging config with ruff
- Type hints: Strict typing with
from __future__ import annotations - Tests: pytest with fixtures, matching source patterns
- Linting: ruff (96-char lines, double quotes, sorted imports)
- Virtual env: venv, poetry, or conda
- Documentation: Google-style docstrings
- Exceptions: Hierarchical exceptions in
exceptions.py
New Module Checklist
-
from __future__ import annotationsat top - Module docstring (Google-style)
- Type hints on all public functions
-
__all__export list (if applicable) - Unit tests in
tests/mirror structure - Error handling with typed exceptions from
exceptions.py
Project Structure
Recommended Layout (src-layout)
project/
├── src/
│ └── mypackage/
│ ├── __init__.py
│ ├── exceptions.py # Hierarchical typed exceptions
│ ├── core/
│ │ ├── __init__.py
│ │ └── module.py
│ ├── utils/
│ │ ├── __init__.py
│ │ └── helpers.py
│ └── py.typed # PEP 561 marker
├── tests/
│ ├── conftest.py # Shared fixtures
│ ├── test_core/
│ │ └── test_module.py # Mirrors src/mypackage/core/module.py
│ └── test_utils/
│ └── test_helpers.py # Mirrors src/mypackage/utils/helpers.py
├── pyproject.toml
├── ruff.toml # ruff config (96-char, double quotes)
├── README.md
└── .python-version # 3.12+
Alternative: Flat Layout (smaller projects)
project/
├── mypackage/
│ ├── __init__.py
│ └── module.py
├── tests/
│ └── test_module.py
├── pyproject.toml
└── README.md
Core Principles (7 Key Rules)
1. Type Everything Public (Strict Typing)
from __future__ import annotations # Always at top of file
# ❌ NEVER: Untyped public functions
def process_data(data):
return data.upper()
# ✅ ALWAYS: Full type annotations
def process_data(data: str) -> str:
"""Process input data.
Args:
data: The input string to process.
Returns:
The processed uppercase string.
"""
return data.upper()
2. Use Pydantic v2 for Data Models (Preferred)
from __future__ import annotations
from pydantic import BaseModel, EmailStr, Field
# ✅ Pydantic v2 for validation (preferred)
class UserCreate(BaseModel):
"""User creation model with validation."""
name: str = Field(..., min_length=1, max_length=100)
email: EmailStr
class UserResponse(BaseModel):
"""User response model."""
id: int
name: str
email: str
# For simple internal data without validation, dataclasses are acceptable
from dataclasses import dataclass
@dataclass
class InternalConfig:
timeout: int = 30
retries: int = 3
3. Handle Errors with Typed Hierarchical Exceptions
# exceptions.py - Define hierarchical typed exceptions
from __future__ import annotations
class AppError(Exception):
"""Base exception for application errors."""
def __init__(self, message: str) -> None:
self.message = message
super().__init__(message)
class ValidationError(AppError):
"""Raised when validation fails."""
pass
class NotFoundError(AppError):
"""Raised when resource not found."""
pass
class DatabaseError(AppError):
"""Raised when database operation fails."""
pass
# Usage - catch specific exceptions, not general Exception
from mypackage.exceptions import ValidationError, NotFoundError
async def get_user(user_id: int) -> User:
"""Get user by ID.
Args:
user_id: The user's unique identifier.
Returns:
The user object.
Raises:
NotFoundError: If user does not exist.
"""
user = await db.find(user_id)
if not user:
raise NotFoundError(f"User {user_id} not found")
return user
4. Use Context Managers for Resources
from __future__ import annotations
from contextlib import asynccontextmanager, contextmanager
# ❌ NEVER: Manual resource management
f = open("file.txt")
data = f.read()
f.close()
# ✅ ALWAYS: Context managers
with open("file.txt") as f:
data = f.read()
# ✅ Sync context manager
@contextmanager
def database_transaction():
"""Manage database transaction with automatic cleanup."""
conn = get_connection()
try:
yield conn
conn.commit()
except Exception:
conn.rollback()
raise
finally:
conn.close()
# ✅ Async - use try/finally to ensure cleanup
@asynccontextmanager
async def async_db_session():
"""Manage async database session with cleanup."""
session = await create_session()
try:
yield session
await session.commit()
except Exception:
await session.rollback()
raise
finally:
await session.close()
5. Prefer Composition Over Inheritance
# ❌ Avoid deep inheritance
class Animal: ...
class Mammal(Animal): ...
class Dog(Mammal): ...
# ✅ Prefer composition and protocols
from typing import Protocol
class Walker(Protocol):
def walk(self) -> None: ...
class Dog:
def __init__(self, legs: int = 4):
self.legs = legs
def walk(self) -> None:
print(f"Walking on {self.legs} legs")
6. Use Logging, Not Print
import logging
logger = logging.getLogger(__name__)
# ❌ NEVER
print(f"Processing {item}")
# ✅ ALWAYS
logger.info("Processing %s", item)
logger.error("Failed to process", exc_info=True)
7. Write Testable Code
# ❌ Hard to test: hidden dependencies
def send_email(user_id: int) -> None:
user = database.get_user(user_id) # Hidden dependency
smtp.send(user.email, "Hello") # Hidden dependency
# ✅ Easy to test: explicit dependencies
def send_email(
user: User,
email_sender: EmailSender
) -> None:
email_sender.send(user.email, "Hello")
Type Hints Quick Reference
from __future__ import annotations
from typing import TypeVar, Generic
from collections.abc import Callable
# Basic types (Python 3.12+)
values: list[int] = [1, 2, 3]
mapping: dict[str, int] = {"a": 1}
value: str | None = None # Union syntax
# Callable and Generics
handler: Callable[[int, str], bool]
T = TypeVar("T")
class Container(Generic[T]):
def __init__(self, value: T) -> None:
self.value = value
Testing Patterns
# tests/test_user_service.py - mirrors src/mypackage/services/user_service.py
from __future__ import annotations
import pytest
from mypackage.services import UserService
from mypackage.exceptions import ValidationError
class TestUserService:
"""Tests for UserService."""
def test_create_user_success(self, mock_database):
"""Should create user with valid data."""
service = UserService(mock_database)
user = service.create(name="Test", email="test@example.com")
assert user.name == "Test"
def test_create_user_invalid_email_raises(self, mock_database):
"""Should raise ValidationError for invalid email."""
service = UserService(mock_database)
with pytest.raises(ValidationError, match="invalid email"):
service.create(name="Test", email="not-an-email")
Anti-Patterns to Avoid
❌ Mutable default arguments (def foo(items=[]))
❌ Bare except: clauses - catch specific exceptions
❌ Catching general Exception - use typed exceptions
❌ from module import *
❌ Global mutable state
❌ Ignoring type checker errors
❌ print() instead of logging
❌ String concatenation in loops (use join)
❌ Not using if __name__ == "__main__":
❌ Missing from __future__ import annotations
Async Patterns (FastAPI Preferred)
from __future__ import annotations
from fastapi import FastAPI, HTTPException, status
from mypackage.exceptions import ValidationError
app = FastAPI()
# ✅ FastAPI endpoint with proper error handling
@app.post("/users", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
async def create_user(user: UserCreate) -> UserResponse:
"""Create a new user."""
try:
return await user_service.create(user)
except ValidationError as e:
raise HTTPException(status_code=400, detail=str(e)) from e
# ✅ Async error handling with exception chaining (from e)
async def process_data(data: dict) -> Result:
"""Process data with proper exception handling."""
try:
return await do_processing(data)
except KeyError as e:
raise ValidationError(f"Missing required field: {e}") from e
# ✅ Concurrent operations
async def process_items(items: list[str]) -> list[dict]:
return await asyncio.gather(*[fetch_data(item) for item in items])
Resource Files
style-guide.md
Google Python Style Guide + PEP 8 practices, naming, docstrings, imports
Related Skills
- cpp-dev-guidelines - C++ development patterns
- error-tracking - Sentry integration for Python
- skill-developer - Creating and managing skills
Skill Status: COMPLETE ✅ Line Count: < 450 ✅ Progressive Disclosure: Resource files for details ✅
スコア
総合スコア
リポジトリの品質指標に基づく評価
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
3ヶ月以内に更新がある
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
レビュー
レビュー機能は近日公開予定です