From pr-review-toolkit
Python architecture skill — focus on system design, architectural trade-offs, structural patterns, and high-level technical decisions. Covers: advanced type system, async/await, Pydantic, testing, error handling, structured logging, and state-of-the-art best practices. Use when: (1) Designing Python system architecture, (2) Evaluating trade-offs and technical decisions, (3) Applying architectural patterns and high-level design. Triggers: /arch-py, /arch, Python architecture, system design, design decisions, architectural patterns.
How this skill is triggered — by the user, by Claude, or both
Slash command
/pr-review-toolkit:arch-pyThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
**Verifiability and Transparency:**
references/python/async-patterns.mdreferences/python/concurrency.mdreferences/python/context-managers.mdreferences/python/dataclasses.mdreferences/python/decorators.mdreferences/python/error-handling.mdreferences/python/generators.mdreferences/python/logging.mdreferences/python/packaging.mdreferences/python/pydantic.mdreferences/python/type-system.mdVerifiability and Transparency:
Labeling Unverified Content:
[Inference] - For inferences based on patterns[Speculation] - For speculation or hypotheses[Unverified] - For information that cannot be confirmedClarifications:
Statements about LLMs:
[Inference] or [Unverified].Corrections:
Input Preservation:
Architecture and System Design:
Problem Decomposition:
Language:
Always use explicit typing on all variables and functions:
from typing import Optional
def process_items(items: list[str], limit: int = 10) -> dict[str, int]:
return {item: len(item) for item in items[:limit]}
Format all code in the black library style:
def long_function_name(
parameter_one: str,
parameter_two: int,
parameter_three: list[str] | None = None,
) -> dict[str, Any]:
"""Function with properly formatted parameters."""
pass
Overview of each state-of-the-art Python concept. For details and advanced examples, consult the reference files indicated.
When to use: Clear contracts, structural duck typing, reusable generic types.
Python 3.10+ offers: Protocol (structural duck typing), TypeVar/Generic (generic code), Literal (specific values), TypedDict (typed dicts), X | Y (modern union).
from typing import Protocol, TypeVar, Generic, Literal
class Readable(Protocol):
def read(self) -> str: ...
T = TypeVar("T")
class Container(Generic[T]):
def __init__(self, value: T) -> None:
self.value = value
Status = Literal["pending", "done", "failed"]
def process(status: Status, data: str | None = None) -> str:
return f"{status}: {data or 'empty'}"
Reference: references/python/type-system.md
When to use: I/O-bound operations (APIs, databases, network, files).
Asyncio enables concurrent I/O without blocking: async def (coroutines), await (waits for operation), asyncio.gather() (parallelizes).
import asyncio
import httpx
async def fetch_data(url: str) -> dict:
async with httpx.AsyncClient() as client:
response = await client.get(url)
return response.json()
async def fetch_all(urls: list[str]) -> list[dict]:
return await asyncio.gather(*[fetch_data(url) for url in urls])
Reference: references/python/async-patterns.md
When to use: Data structures with clear representation, comparison, optional immutability.
Eliminates boilerplate: @dataclass generates __init__, __repr__, __eq__; frozen=True (immutable); slots=True (less memory).
from dataclasses import dataclass, field
@dataclass(frozen=True, slots=True)
class Point:
x: float
y: float
label: str = ""
tags: list[str] = field(default_factory=list)
def distance_from_origin(self) -> float:
return (self.x**2 + self.y**2) ** 0.5
Reference: references/python/dataclasses.md
When to use: Resource management (files, connections, locks), setup/teardown, transactions.
Guarantee cleanup even with exceptions: with (usage), @contextmanager (simple creation), __enter__/__exit__ (manual).
from contextlib import contextmanager
from typing import Iterator
@contextmanager
def managed_connection(host: str) -> Iterator[Connection]:
conn = Connection(host)
try:
conn.open()
yield conn
finally:
conn.close()
with managed_connection("localhost") as conn:
conn.execute("SELECT 1")
Reference: references/python/context-managers.md
When to use: Cross-cutting concerns (logging, caching, auth), modify behavior without altering code.
Functions that wrap others: @functools.cache (memoization), @property (computed attributes), custom decorators.
from functools import wraps, cache
from typing import Callable, TypeVar
T = TypeVar("T")
def retry(times: int = 3) -> Callable[[Callable[..., T]], Callable[..., T]]:
def decorator(func: Callable[..., T]) -> Callable[..., T]:
@wraps(func)
def wrapper(*args, **kwargs) -> T:
for attempt in range(times):
try:
return func(*args, **kwargs)
except Exception:
if attempt == times - 1:
raise
raise RuntimeError("Unreachable")
return wrapper
return decorator
Reference: references/python/decorators.md
When to use: External data validation (APIs, configs, files), serialization, documented schemas.
Standard for validation: @field_validator (custom validation), @computed_field (derived fields), FastAPI integration.
from pydantic import BaseModel, field_validator, computed_field
class User(BaseModel):
name: str
email: str
age: int
@field_validator("email")
@classmethod
def validate_email(cls, v: str) -> str:
if "@" not in v:
raise ValueError("Invalid email")
return v.lower()
@computed_field
@property
def is_adult(self) -> bool:
return self.age >= 18
Reference: references/python/pydantic.md
When to use: Always; create hierarchies for specific domain errors.
Well-structured exceptions: custom hierarchy, clear messages, use for exceptional cases (not normal flow).
class AppError(Exception):
"""Base exception for application errors."""
class ValidationError(AppError):
"""Raised when data validation fails."""
class NotFoundError(AppError):
"""Raised when requested resource is not found."""
def __init__(self, resource: str, id: str) -> None:
super().__init__(f"{resource} with id '{id}' not found")
self.resource = resource
self.id = id
Reference: references/python/error-handling.md
When to use: Always. Tests are an integral part of development.
Standard framework: fixtures (reusable setup), @pytest.mark.parametrize (multiple cases), simple assertions.
import pytest
@pytest.fixture
def premium_user() -> User:
return User(name="Test", tier="premium")
@pytest.mark.parametrize("price,expected", [(100.0, 90.0), (50.0, 45.0), (0.0, 0.0)])
def test_discount(premium_user: User, price: float, expected: float) -> None:
result = calculate_discount(premium_user, price)
assert result == pytest.approx(expected)
Reference: references/testing/pytest.md
When to use: Production and debugging; essential for observability.
Structlog produces JSON logs: automatic context, customizable processors, integration with standard logging.
import structlog
logger = structlog.get_logger()
def process_order(order_id: str, user_id: str) -> None:
log = logger.bind(order_id=order_id, user_id=user_id)
log.info("processing_started")
try:
# ... process ...
log.info("processing_completed", status="success")
except Exception as e:
log.error("processing_failed", error=str(e))
raise
Reference: references/python/logging.md
When to use: Any app that needs external configuration (envvars, files).
Pydantic-settings: loads from env vars, integrated validation, .env and secrets support.
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_prefix="APP_", env_file=".env")
database_url: str
debug: bool = False
max_connections: int = 10
settings = Settings() # Loads from APP_DATABASE_URL, etc.
Reference: references/python/configuration.md
When to use: Large data volumes, transformation pipelines, memory savings.
Values on demand: yield (produces incrementally), generator expressions, itertools.
from typing import Iterator
from pathlib import Path
def read_chunks(path: Path, size: int = 8192) -> Iterator[str]:
with open(path) as f:
while chunk := f.read(size):
yield chunk
def process_lines(path: Path) -> Iterator[str]:
for chunk in read_chunks(path):
for line in chunk.splitlines():
if line.strip():
yield line.upper()
Reference: references/python/generators.md
When to use: Choice based on workload type - I/O-bound vs CPU-bound.
Three models: asyncio (I/O, single-thread, cooperative), threading (I/O, multi-thread, GIL), multiprocessing (CPU, bypasses GIL).
import asyncio
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
# asyncio for I/O-bound (preferred)
results = await asyncio.gather(*tasks)
# threading for legacy I/O-bound
with ThreadPoolExecutor(max_workers=4) as ex:
results = list(ex.map(io_func, items))
# multiprocessing for CPU-bound
with ProcessPoolExecutor() as ex:
results = list(ex.map(cpu_func, items))
Reference: references/python/concurrency.md
When to use: Distributed projects or those with managed dependencies.
pyproject.toml (PEP 621): replaces setup.py/setup.cfg, centralized config, modern build systems.
[project]
name = "mypackage"
version = "0.1.0"
requires-python = ">=3.10"
dependencies = ["pydantic>=2.0", "httpx>=0.24"]
[project.optional-dependencies]
dev = ["pytest>=7.0", "ruff>=0.1"]
[tool.ruff]
line-length = 88
[tool.pytest.ini_options]
testpaths = ["tests"]
Reference: references/python/packaging.md
| Category | Tool | Purpose | Command |
|---|---|---|---|
| Lint | ruff | Ultra-fast linter | ruff check . --fix |
| Format | black | Opinionated formatter | black . |
| Types | mypy | Type checker | mypy src/ |
| Test | pytest | Testing framework | pytest |
| Coverage | pytest-cov | Coverage | pytest --cov=src |
| Hooks | pre-commit | Git hooks | pre-commit install |
Reference: references/tooling/setup.md
ANALYZE → DESIGN → TYPE → IMPLEMENT → VALIDATE → REVIEW
Provides UI/UX resources: 50+ styles, color palettes, font pairings, guidelines, charts for web/mobile across React, Next.js, Vue, Svelte, Tailwind, React Native, Flutter. Aids planning, building, reviewing interfaces.
Fetches up-to-date documentation from Context7 for libraries and frameworks like React, Next.js, Prisma. Use for setup questions, API references, and code examples.
npx claudepluginhub olimpus-soft/olimpus-claude-skills --plugin pr-review-toolkit