Python
Skill aps08/fullstack-clean-architecture/.agents/skills/python
Read to code, just run Docker compose.
npx -y skills add aps08/fullstack-clean-architecture --skill pythonAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Enforces FastAPI, Dependency Injection, and general Python coding standards based on the repository structure.
SKILL.md
5.0 KB, as published. Nobody here has run it
Python & FastAPI Coding & Architecture Guidelines
Use this skill when extending the Python backend, writing routes, services, or repositories, or working with core server logic.
1. FastAPI & Dependency Injection
We use dependency-injector for wiring application components together.
-
Wiring: The container is defined in
server/app/core/container.pyand wired inserver/app/main.py. -
Dependency injection in Routes:
-
Decorate endpoints with
@inject(fromdependency_injector.wiring). -
Create clean dependency type aliases using
AnnotatedandDepends(Provide[Container.service_name]). -
Example:
TodoServiceDep = Annotated[TodoService, Depends(Provide[Container.todo_service])] @router.get("/todos/") @inject async def list_todos(service: TodoServiceDep): ...
-
-
No Direct Instantiation: Do not manually instantiate services or repositories; resolve them via the container.
2. FastAPI Route & Handler Best Practices
Use Annotated
Always prefer the Annotated style for parameter and dependency declarations.
from typing import Annotated
from fastapi import Path, Query
@router.get("/items/{item_id}")
async def read_item(
item_id: Annotated[UUID, Path(description="The item ID")],
q: Annotated[str | None, Query(max_length=50)] = None,
):
...
Return Types & response_model
- Specify explicit return type annotations (
-> Model) for FastAPI validation, filtering, and serialization (running Pydantic's Rust-based serialization). - If the returned object differs from the API response contract (e.g. returning a database model that needs filtering/serialization to a public schema), use
response_modelon the router decorator instead:
@router.get("/todos/{todo_id}", response_model=Todo)
async def get_todo(todo_id: UUID) -> Any:
...
No Ellipsis (...) for Required Fields
Do not use ... as a default value for required fields or query parameters.
# CORRECT
async def create_item(item: Item, project_id: Annotated[int, Query()]): ...
# INCORRECT
async def create_item(item: Item, project_id: Annotated[int, Query(...)]): ...
Declaring APIRouters
Prefer defining path prefixes and tags on the router itself, rather than in include_router():
router = APIRouter(prefix="/todos", tags=["todos"])
Async vs Sync Handlers
- Use
async defonly when callingawait-compatible non-blocking code. - If a route calls blocking code (like synchronous DB queries or filesystem operations), use standard
definstead ofasync defso FastAPI runs it in an external threadpool.
Do not use Pydantic RootModel
Instead, use regular type annotations with Annotated and validation utilities:
@router.post("/items/")
async def create_items(items: Annotated[list[int], Field(min_length=1), Body()]):
return items
One HTTP Method Per Function
Keep handler functions dedicated to a single HTTP operation. Do not use @router.api_route for multiple methods in a single function.
3. Layered Architecture
Always structure backend logic using the established 3-layer architecture:
- Routes/Endpoints (
app/routes): Parse requests, validate inputs via Pydantic, call services, and handle HTTP routing. Keep business logic out of this layer. - Services (
app/services): Implement business logic, orchestration, and validation checks. Inherit fromBaseServicefor CRUD operations. - Repositories (
app/repositories): Handle raw database persistence and queries using SQLAlchemy. Inherit fromBaseRepository.
4. Database Scopes & Transactions
- Scoped Sessions: Uses
async_scoped_sessionkeyed by a unique request-based UUID context variable. - Transactions:
- Service-level or middleware-level functions run within
async with db.session_scope():to ensure automatic rollback on failure and commit on success. - Always perform queries asynchronously (e.g.
await session.execute(...)).
- Service-level or middleware-level functions run within
- Timezones: Use timezone-aware datetime objects (
TIMESTAMP(timezone=True)) or Pydantic UTC validation.
5. Code Quality & Type Safety
- Type Annotations: Annotate all function signatures and variables. Use
Annotated,TypeVar, andGenericfor generic classes like repositories. - Pydantic Models: Define explicit request/response schemas under
app/schemas/.- Ensure they map accurately to database models.
- Configure
model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True, from_attributes=True)for camelCase serialization support.
- Error Handling: Centralize errors using specific exceptions defined in
app/core/exceptions.py(e.g.NotFoundError,DuplicatedError).
6. Background Tasks
- Always use
BackgroundTaskswhen sending emails or other long-running tasks to prevent user delays in response to user requests.