cleodin

python-patterns

1
1
# Install this skill:
npx skills add cleodin/antigravity-awesome-skills --skill "python-patterns"

Install specific skill from multi-skill repository

# Description

Python development principles and decision-making. Framework selection, async patterns, type hints, project structure. Teaches thinking, not copying.

# SKILL.md


name: python-patterns
description: Python development principles and decision-making. Framework selection, async patterns, type hints, project structure. Teaches thinking, not copying.
allowed-tools: Read, Write, Edit, Glob, Grep


Python Patterns

Python development principles and decision-making for 2025.
Learn to THINK, not memorize patterns.


⚠️ How to Use This Skill

This skill teaches decision-making principles, not fixed code to copy.

  • ASK user for framework preference when unclear
  • Choose async vs sync based on CONTEXT
  • Don't default to same framework every time

1. Framework Selection (2025)

Decision Tree

What are you building?
β”‚
β”œβ”€β”€ API-first / Microservices
β”‚   └── FastAPI (async, modern, fast)
β”‚
β”œβ”€β”€ Full-stack web / CMS / Admin
β”‚   └── Django (batteries-included)
β”‚
β”œβ”€β”€ Simple / Script / Learning
β”‚   └── Flask (minimal, flexible)
β”‚
β”œβ”€β”€ AI/ML API serving
β”‚   └── FastAPI (Pydantic, async, uvicorn)
β”‚
└── Background workers
    └── Celery + any framework

Comparison Principles

Factor FastAPI Django Flask
Best for APIs, microservices Full-stack, CMS Simple, learning
Async Native Django 5.0+ Via extensions
Admin Manual Built-in Via extensions
ORM Choose your own Django ORM Choose your own
Learning curve Low Medium Low

Selection Questions to Ask:

  1. Is this API-only or full-stack?
  2. Need admin interface?
  3. Team familiar with async?
  4. Existing infrastructure?

2. Async vs Sync Decision

When to Use Async

async def is better when:
β”œβ”€β”€ I/O-bound operations (database, HTTP, file)
β”œβ”€β”€ Many concurrent connections
β”œβ”€β”€ Real-time features
β”œβ”€β”€ Microservices communication
└── FastAPI/Starlette/Django ASGI

def (sync) is better when:
β”œβ”€β”€ CPU-bound operations
β”œβ”€β”€ Simple scripts
β”œβ”€β”€ Legacy codebase
β”œβ”€β”€ Team unfamiliar with async
└── Blocking libraries (no async version)

The Golden Rule

I/O-bound β†’ async (waiting for external)
CPU-bound β†’ sync + multiprocessing (computing)

Don't:
β”œβ”€β”€ Mix sync and async carelessly
β”œβ”€β”€ Use sync libraries in async code
└── Force async for CPU work

Async Library Selection

Need Async Library
HTTP client httpx
PostgreSQL asyncpg
Redis aioredis / redis-py async
File I/O aiofiles
Database ORM SQLAlchemy 2.0 async, Tortoise

3. Type Hints Strategy

When to Type

Always type:
β”œβ”€β”€ Function parameters
β”œβ”€β”€ Return types
β”œβ”€β”€ Class attributes
β”œβ”€β”€ Public APIs

Can skip:
β”œβ”€β”€ Local variables (let inference work)
β”œβ”€β”€ One-off scripts
β”œβ”€β”€ Tests (usually)

Common Type Patterns

# These are patterns, understand them:

# Optional β†’ might be None
from typing import Optional
def find_user(id: int) -> Optional[User]: ...

# Union β†’ one of multiple types
def process(data: str | dict) -> None: ...

# Generic collections
def get_items() -> list[Item]: ...
def get_mapping() -> dict[str, int]: ...

# Callable
from typing import Callable
def apply(fn: Callable[[int], str]) -> str: ...

Pydantic for Validation

When to use Pydantic:
β”œβ”€β”€ API request/response models
β”œβ”€β”€ Configuration/settings
β”œβ”€β”€ Data validation
β”œβ”€β”€ Serialization

Benefits:
β”œβ”€β”€ Runtime validation
β”œβ”€β”€ Auto-generated JSON schema
β”œβ”€β”€ Works with FastAPI natively
└── Clear error messages

4. Project Structure Principles

Structure Selection

Small project / Script:
β”œβ”€β”€ main.py
β”œβ”€β”€ utils.py
└── requirements.txt

Medium API:
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ main.py
β”‚   β”œβ”€β”€ models/
β”‚   β”œβ”€β”€ routes/
β”‚   β”œβ”€β”€ services/
β”‚   └── schemas/
β”œβ”€β”€ tests/
└── pyproject.toml

Large application:
β”œβ”€β”€ src/
β”‚   └── myapp/
β”‚       β”œβ”€β”€ core/
β”‚       β”œβ”€β”€ api/
β”‚       β”œβ”€β”€ services/
β”‚       β”œβ”€β”€ models/
β”‚       └── ...
β”œβ”€β”€ tests/
└── pyproject.toml

FastAPI Structure Principles

Organize by feature or layer:

By layer:
β”œβ”€β”€ routes/ (API endpoints)
β”œβ”€β”€ services/ (business logic)
β”œβ”€β”€ models/ (database models)
β”œβ”€β”€ schemas/ (Pydantic models)
└── dependencies/ (shared deps)

By feature:
β”œβ”€β”€ users/
β”‚   β”œβ”€β”€ routes.py
β”‚   β”œβ”€β”€ service.py
β”‚   └── schemas.py
└── products/
    └── ...

5. Django Principles (2025)

Django Async (Django 5.0+)

Django supports async:
β”œβ”€β”€ Async views
β”œβ”€β”€ Async middleware
β”œβ”€β”€ Async ORM (limited)
└── ASGI deployment

When to use async in Django:
β”œβ”€β”€ External API calls
β”œβ”€β”€ WebSocket (Channels)
β”œβ”€β”€ High-concurrency views
└── Background task triggering

Django Best Practices

Model design:
β”œβ”€β”€ Fat models, thin views
β”œβ”€β”€ Use managers for common queries
β”œβ”€β”€ Abstract base classes for shared fields

Views:
β”œβ”€β”€ Class-based for complex CRUD
β”œβ”€β”€ Function-based for simple endpoints
β”œβ”€β”€ Use viewsets with DRF

Queries:
β”œβ”€β”€ select_related() for FKs
β”œβ”€β”€ prefetch_related() for M2M
β”œβ”€β”€ Avoid N+1 queries
└── Use .only() for specific fields

6. FastAPI Principles

async def vs def in FastAPI

Use async def when:
β”œβ”€β”€ Using async database drivers
β”œβ”€β”€ Making async HTTP calls
β”œβ”€β”€ I/O-bound operations
└── Want to handle concurrency

Use def when:
β”œβ”€β”€ Blocking operations
β”œβ”€β”€ Sync database drivers
β”œβ”€β”€ CPU-bound work
└── FastAPI runs in threadpool automatically

Dependency Injection

Use dependencies for:
β”œβ”€β”€ Database sessions
β”œβ”€β”€ Current user / Auth
β”œβ”€β”€ Configuration
β”œβ”€β”€ Shared resources

Benefits:
β”œβ”€β”€ Testability (mock dependencies)
β”œβ”€β”€ Clean separation
β”œβ”€β”€ Automatic cleanup (yield)

Pydantic v2 Integration

# FastAPI + Pydantic are tightly integrated:

# Request validation
@app.post("/users")
async def create(user: UserCreate) -> UserResponse:
    # user is already validated
    ...

# Response serialization
# Return type becomes response schema

7. Background Tasks

Selection Guide

Solution Best For
BackgroundTasks Simple, in-process tasks
Celery Distributed, complex workflows
ARQ Async, Redis-based
RQ Simple Redis queue
Dramatiq Actor-based, simpler than Celery

When to Use Each

FastAPI BackgroundTasks:
β”œβ”€β”€ Quick operations
β”œβ”€β”€ No persistence needed
β”œβ”€β”€ Fire-and-forget
└── Same process

Celery/ARQ:
β”œβ”€β”€ Long-running tasks
β”œβ”€β”€ Need retry logic
β”œβ”€β”€ Distributed workers
β”œβ”€β”€ Persistent queue
└── Complex workflows

8. Error Handling Principles

Exception Strategy

In FastAPI:
β”œβ”€β”€ Create custom exception classes
β”œβ”€β”€ Register exception handlers
β”œβ”€β”€ Return consistent error format
└── Log without exposing internals

Pattern:
β”œβ”€β”€ Raise domain exceptions in services
β”œβ”€β”€ Catch and transform in handlers
└── Client gets clean error response

Error Response Philosophy

Include:
β”œβ”€β”€ Error code (programmatic)
β”œβ”€β”€ Message (human readable)
β”œβ”€β”€ Details (field-level when applicable)
└── NOT stack traces (security)

9. Testing Principles

Testing Strategy

Type Purpose Tools
Unit Business logic pytest
Integration API endpoints pytest + httpx/TestClient
E2E Full workflows pytest + DB

Async Testing

# Use pytest-asyncio for async tests

import pytest
from httpx import AsyncClient

@pytest.mark.asyncio
async def test_endpoint():
    async with AsyncClient(app=app, base_url="http://test") as client:
        response = await client.get("/users")
        assert response.status_code == 200

Fixtures Strategy

Common fixtures:
β”œβ”€β”€ db_session β†’ Database connection
β”œβ”€β”€ client β†’ Test client
β”œβ”€β”€ authenticated_user β†’ User with token
└── sample_data β†’ Test data setup

10. Decision Checklist

Before implementing:

  • [ ] Asked user about framework preference?
  • [ ] Chosen framework for THIS context? (not just default)
  • [ ] Decided async vs sync?
  • [ ] Planned type hint strategy?
  • [ ] Defined project structure?
  • [ ] Planned error handling?
  • [ ] Considered background tasks?

11. Anti-Patterns to Avoid

❌ DON'T:

  • Default to Django for simple APIs (FastAPI may be better)
  • Use sync libraries in async code
  • Skip type hints for public APIs
  • Put business logic in routes/views
  • Ignore N+1 queries
  • Mix async and sync carelessly

βœ… DO:

  • Choose framework based on context
  • Ask about async requirements
  • Use Pydantic for validation
  • Separate concerns (routes β†’ services β†’ repos)
  • Test critical paths

Remember: Python patterns are about decision-making for YOUR specific context. Don't copy codeβ€”think about what serves your application best.

# 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.