kumaran-is

python-dev

0
0
# Install this skill:
npx skills add kumaran-is/claude-code-onboarding --skill "python-dev"

Install specific skill from multi-skill repository

# Description

Patterns and templates for Python 3.14 development with FastAPI, pytest, Pydantic, and modern tooling. Activate when creating Python APIs, scripts, data processing, or tests.

# SKILL.md


name: python-dev
description: Patterns and templates for Python 3.14 development with FastAPI, pytest, Pydantic, and modern tooling. Activate when creating Python APIs, scripts, data processing, or tests.
allowed-tools: Bash, Read, Write, Edit


Python 3.14 Development Skill

Quick Scaffold β€” New Python Project

# Using uv (preferred)
uv init my-service
cd my-service
uv add fastapi uvicorn pydantic pydantic-settings
uv add --dev pytest pytest-asyncio httpx ruff mypy

# Or using pip
mkdir my-service && cd my-service
python -m venv .venv
source .venv/bin/activate    # Windows: .venv\Scripts\activate
pip install fastapi uvicorn pydantic pydantic-settings
pip install -e ".[dev]"

pyproject.toml Template

[project]
name = "my-service"
version = "0.1.0"
requires-python = ">=3.14"
dependencies = [
    "fastapi>=0.115.0",
    "uvicorn[standard]>=0.32.0",
    "pydantic>=2.10.0",
    "pydantic-settings>=2.6.0",
    "sqlalchemy[asyncio]>=2.0.0",
    "asyncpg>=0.30.0",
    "alembic>=1.14.0",
]

[project.optional-dependencies]
dev = [
    "pytest>=8.3.0",
    "pytest-asyncio>=0.24.0",
    "httpx>=0.28.0",
    "ruff>=0.8.0",
    "mypy>=1.13.0",
]

[tool.ruff]
target-version = "py314"
line-length = 100
select = ["E", "F", "I", "N", "UP", "B", "SIM", "RUF"]

[tool.mypy]
python_version = "3.14"
strict = true

[tool.pytest.ini_options]
asyncio_mode = "auto"
testpaths = ["tests"]

FastAPI App Template

# src/my_service/main.py
from fastapi import FastAPI
from contextlib import asynccontextmanager
from .api.routes import user_router, health_router
from .core.config import settings

@asynccontextmanager
async def lifespan(app: FastAPI):
    # Startup
    print(f"Starting {settings.app_name}")
    yield
    # Shutdown
    print("Shutting down")

app = FastAPI(
    title=settings.app_name,
    version="1.0.0",
    lifespan=lifespan,
)

app.include_router(health_router, prefix="/api/v1", tags=["health"])
app.include_router(user_router, prefix="/api/v1/users", tags=["users"])

Pydantic Models Template

# src/my_service/models/user.py
from pydantic import BaseModel, EmailStr, Field
from uuid import UUID, uuid4
from datetime import datetime

class CreateUserRequest(BaseModel):
    email: EmailStr
    name: str = Field(min_length=1, max_length=100)

class UpdateUserRequest(BaseModel):
    name: str | None = Field(default=None, min_length=1, max_length=100)
    email: EmailStr | None = None

class UserResponse(BaseModel):
    id: UUID
    email: str
    name: str
    created_at: datetime
    updated_at: datetime

    model_config = {"from_attributes": True}

Config with pydantic-settings

# src/my_service/core/config.py
from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    app_name: str = "My Service"
    debug: bool = False
    database_url: str = "postgresql+asyncpg://postgres:postgres@localhost:5432/mydb"
    secret_key: str = "change-me"

    model_config = {"env_file": ".env"}

settings = Settings()

Route Handler Template

# src/my_service/api/routes/users.py
from fastapi import APIRouter, HTTPException, Depends
from uuid import UUID
from ...models.user import CreateUserRequest, UserResponse
from ...services.user_service import UserService

router = APIRouter()

@router.get("/", response_model=list[UserResponse])
async def list_users(service: UserService = Depends()) -> list[UserResponse]:
    return await service.find_all()

@router.get("/{user_id}", response_model=UserResponse)
async def get_user(user_id: UUID, service: UserService = Depends()) -> UserResponse:
    user = await service.find_by_id(user_id)
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    return user

@router.post("/", response_model=UserResponse, status_code=201)
async def create_user(request: CreateUserRequest, service: UserService = Depends()) -> UserResponse:
    return await service.create(request)

SQLAlchemy Async Model

# src/my_service/models/db/user.py
from sqlalchemy import String, DateTime
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.dialects.postgresql import UUID as PG_UUID
from uuid import UUID, uuid4
from datetime import datetime, timezone

class UserEntity(Base):
    __tablename__ = "users"

    id: Mapped[UUID] = mapped_column(PG_UUID(as_uuid=True), primary_key=True, default=uuid4)
    email: Mapped[str] = mapped_column(String(255), unique=True, nullable=False)
    name: Mapped[str] = mapped_column(String(100), nullable=False)
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc))
    updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc))

Pytest Template

# tests/test_users.py
import pytest
from httpx import AsyncClient, ASGITransport
from src.my_service.main import app

@pytest.fixture
async def client():
    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://test") as ac:
        yield ac

@pytest.mark.asyncio
async def test_create_user(client: AsyncClient):
    response = await client.post(
        "/api/v1/users",
        json={"email": "[email protected]", "name": "John Doe"},
    )
    assert response.status_code == 201
    data = response.json()
    assert data["email"] == "[email protected]"

@pytest.mark.asyncio
async def test_create_user_invalid_email(client: AsyncClient):
    response = await client.post(
        "/api/v1/users",
        json={"email": "not-valid", "name": "Test"},
    )
    assert response.status_code == 422

Docker Template

FROM python:3.14-slim

WORKDIR /app
RUN pip install uv

COPY pyproject.toml ./
RUN uv sync --no-dev

COPY src/ ./src/
EXPOSE 8000
CMD ["uv", "run", "uvicorn", "src.my_service.main:app", "--host", "0.0.0.0", "--port", "8000"]

Common Commands

# Run dev server
uvicorn src.my_service.main:app --reload --port 8000

# Run tests
pytest -v

# Lint and format
ruff check src/ --fix
ruff format src/

# Type check
mypy src/

# Alembic migrations
alembic init alembic
alembic revision --autogenerate -m "create users table"
alembic upgrade head

# Supported AI Coding Agents

This skill is compatible with the SKILL.md standard and works with all major AI coding agents:

Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.