chore(quality): apply ruff autofixes and formatting (29 fixes, 41 files reformatted)

This commit is contained in:
Agent Zero
2026-06-10 21:31:41 +00:00
parent 054d4041e6
commit 7c12a96cdc
43 changed files with 1096 additions and 524 deletions
+225 -78
View File
@@ -1,11 +1,10 @@
"""Project CRUD endpoints including sub-projects, function groups, and functions."""
from fastapi import APIRouter, Depends, HTTPException, status, Query
from sqlalchemy import select, func, or_
from sqlalchemy import select, func
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload
from app.api.deps import get_current_user, require_permission
from app.api.deps import require_permission
from app.db.session import get_async_session
from app.models import User, Project, SubProject, ProjectFunctionGroup, ProjectFunction
from app.schemas.project import (
@@ -38,7 +37,10 @@ async def list_projects(
page: int = Query(1, ge=1),
size: int = Query(20, ge=1, le=100),
search: str | None = Query(None, description="Search in project name"),
status: str | None = Query(None, description="Filter by status (draft, confirmed, in_progress, completed, cancelled)"),
status: str | None = Query(
None,
description="Filter by status (draft, confirmed, in_progress, completed, cancelled)",
),
current_user: User = Depends(require_permission("projects:read")),
session: AsyncSession = Depends(get_async_session),
):
@@ -57,12 +59,7 @@ async def list_projects(
count_q = select(func.count()).select_from(base_q.subquery())
total = (await session.execute(count_q)).scalar() or 0
q = (
base_q
.order_by(Project.updated_at.desc())
.offset((page - 1) * size)
.limit(size)
)
q = base_q.order_by(Project.updated_at.desc()).offset((page - 1) * size).limit(size)
result = await session.execute(q)
items = result.scalars().all()
@@ -98,11 +95,15 @@ async def get_project(
"""Get a specific project."""
account_id = current_user.account_id
result = await session.execute(
select(Project).where(Project.id == project_id, Project.account_id == account_id)
select(Project).where(
Project.id == project_id, Project.account_id == account_id
)
)
project = result.scalars().first()
if not project:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Project not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Project not found"
)
return ProjectResponse.model_validate(project)
@@ -116,11 +117,15 @@ async def update_project(
"""Update an existing project."""
account_id = current_user.account_id
result = await session.execute(
select(Project).where(Project.id == project_id, Project.account_id == account_id)
select(Project).where(
Project.id == project_id, Project.account_id == account_id
)
)
project = result.scalars().first()
if not project:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Project not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Project not found"
)
update_data = body.model_dump(exclude_unset=True)
for field, value in update_data.items():
@@ -140,11 +145,15 @@ async def delete_project(
"""Delete a project."""
account_id = current_user.account_id
result = await session.execute(
select(Project).where(Project.id == project_id, Project.account_id == account_id)
select(Project).where(
Project.id == project_id, Project.account_id == account_id
)
)
project = result.scalars().first()
if not project:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Project not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Project not found"
)
await session.delete(project)
await session.commit()
@@ -167,10 +176,14 @@ async def list_subprojects(
# Verify project ownership
proj_result = await session.execute(
select(Project.id).where(Project.id == project_id, Project.account_id == account_id)
select(Project.id).where(
Project.id == project_id, Project.account_id == account_id
)
)
if not proj_result.scalars().first():
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Project not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Project not found"
)
base_q = select(SubProject).where(SubProject.project_id == project_id)
count_q = select(func.count()).select_from(base_q.subquery())
@@ -188,7 +201,11 @@ async def list_subprojects(
)
@router.post("/{project_id}/subprojects", response_model=SubProjectResponse, status_code=status.HTTP_201_CREATED)
@router.post(
"/{project_id}/subprojects",
response_model=SubProjectResponse,
status_code=status.HTTP_201_CREATED,
)
async def create_subproject(
project_id: str,
body: SubProjectCreateRequest,
@@ -200,10 +217,14 @@ async def create_subproject(
# Verify project ownership
proj_result = await session.execute(
select(Project.id).where(Project.id == project_id, Project.account_id == account_id)
select(Project.id).where(
Project.id == project_id, Project.account_id == account_id
)
)
if not proj_result.scalars().first():
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Project not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Project not found"
)
# Verify parent subproject if provided
if body.parent_id:
@@ -238,17 +259,25 @@ async def get_subproject(
# Verify project ownership
proj_result = await session.execute(
select(Project.id).where(Project.id == project_id, Project.account_id == account_id)
select(Project.id).where(
Project.id == project_id, Project.account_id == account_id
)
)
if not proj_result.scalars().first():
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Project not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Project not found"
)
result = await session.execute(
select(SubProject).where(SubProject.id == sub_id, SubProject.project_id == project_id)
select(SubProject).where(
SubProject.id == sub_id, SubProject.project_id == project_id
)
)
sub = result.scalars().first()
if not sub:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="SubProject not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="SubProject not found"
)
return SubProjectResponse.model_validate(sub)
@@ -265,17 +294,25 @@ async def update_subproject(
# Verify project ownership
proj_result = await session.execute(
select(Project.id).where(Project.id == project_id, Project.account_id == account_id)
select(Project.id).where(
Project.id == project_id, Project.account_id == account_id
)
)
if not proj_result.scalars().first():
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Project not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Project not found"
)
result = await session.execute(
select(SubProject).where(SubProject.id == sub_id, SubProject.project_id == project_id)
select(SubProject).where(
SubProject.id == sub_id, SubProject.project_id == project_id
)
)
sub = result.scalars().first()
if not sub:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="SubProject not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="SubProject not found"
)
update_data = body.model_dump(exclude_unset=True)
for field, value in update_data.items():
@@ -286,7 +323,9 @@ async def update_subproject(
return SubProjectResponse.model_validate(sub)
@router.delete("/{project_id}/subprojects/{sub_id}", status_code=status.HTTP_204_NO_CONTENT)
@router.delete(
"/{project_id}/subprojects/{sub_id}", status_code=status.HTTP_204_NO_CONTENT
)
async def delete_subproject(
project_id: str,
sub_id: str,
@@ -298,17 +337,25 @@ async def delete_subproject(
# Verify project ownership
proj_result = await session.execute(
select(Project.id).where(Project.id == project_id, Project.account_id == account_id)
select(Project.id).where(
Project.id == project_id, Project.account_id == account_id
)
)
if not proj_result.scalars().first():
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Project not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Project not found"
)
result = await session.execute(
select(SubProject).where(SubProject.id == sub_id, SubProject.project_id == project_id)
select(SubProject).where(
SubProject.id == sub_id, SubProject.project_id == project_id
)
)
sub = result.scalars().first()
if not sub:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="SubProject not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="SubProject not found"
)
await session.delete(sub)
await session.commit()
@@ -318,7 +365,9 @@ async def delete_subproject(
# ===== ProjectFunctionGroup Endpoints =====
@router.get("/{project_id}/function-groups", response_model=ProjectFunctionGroupListResponse)
@router.get(
"/{project_id}/function-groups", response_model=ProjectFunctionGroupListResponse
)
async def list_function_groups(
project_id: str,
page: int = Query(1, ge=1),
@@ -330,16 +379,26 @@ async def list_function_groups(
account_id = current_user.account_id
proj_result = await session.execute(
select(Project.id).where(Project.id == project_id, Project.account_id == account_id)
select(Project.id).where(
Project.id == project_id, Project.account_id == account_id
)
)
if not proj_result.scalars().first():
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Project not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Project not found"
)
base_q = select(ProjectFunctionGroup).where(ProjectFunctionGroup.project_id == project_id)
base_q = select(ProjectFunctionGroup).where(
ProjectFunctionGroup.project_id == project_id
)
count_q = select(func.count()).select_from(base_q.subquery())
total = (await session.execute(count_q)).scalar() or 0
q = base_q.order_by(ProjectFunctionGroup.sort_order).offset((page - 1) * size).limit(size)
q = (
base_q.order_by(ProjectFunctionGroup.sort_order)
.offset((page - 1) * size)
.limit(size)
)
result = await session.execute(q)
items = result.scalars().all()
@@ -351,7 +410,11 @@ async def list_function_groups(
)
@router.post("/{project_id}/function-groups", response_model=ProjectFunctionGroupResponse, status_code=status.HTTP_201_CREATED)
@router.post(
"/{project_id}/function-groups",
response_model=ProjectFunctionGroupResponse,
status_code=status.HTTP_201_CREATED,
)
async def create_function_group(
project_id: str,
body: ProjectFunctionGroupCreateRequest,
@@ -362,10 +425,14 @@ async def create_function_group(
account_id = current_user.account_id
proj_result = await session.execute(
select(Project.id).where(Project.id == project_id, Project.account_id == account_id)
select(Project.id).where(
Project.id == project_id, Project.account_id == account_id
)
)
if not proj_result.scalars().first():
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Project not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Project not found"
)
fg = ProjectFunctionGroup(project_id=project_id, **body.model_dump())
session.add(fg)
@@ -374,7 +441,9 @@ async def create_function_group(
return ProjectFunctionGroupResponse.model_validate(fg)
@router.get("/{project_id}/function-groups/{fg_id}", response_model=ProjectFunctionGroupResponse)
@router.get(
"/{project_id}/function-groups/{fg_id}", response_model=ProjectFunctionGroupResponse
)
async def get_function_group(
project_id: str,
fg_id: str,
@@ -385,10 +454,14 @@ async def get_function_group(
account_id = current_user.account_id
proj_result = await session.execute(
select(Project.id).where(Project.id == project_id, Project.account_id == account_id)
select(Project.id).where(
Project.id == project_id, Project.account_id == account_id
)
)
if not proj_result.scalars().first():
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Project not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Project not found"
)
result = await session.execute(
select(ProjectFunctionGroup).where(
@@ -398,11 +471,15 @@ async def get_function_group(
)
fg = result.scalars().first()
if not fg:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Function group not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Function group not found"
)
return ProjectFunctionGroupResponse.model_validate(fg)
@router.put("/{project_id}/function-groups/{fg_id}", response_model=ProjectFunctionGroupResponse)
@router.put(
"/{project_id}/function-groups/{fg_id}", response_model=ProjectFunctionGroupResponse
)
async def update_function_group(
project_id: str,
fg_id: str,
@@ -414,10 +491,14 @@ async def update_function_group(
account_id = current_user.account_id
proj_result = await session.execute(
select(Project.id).where(Project.id == project_id, Project.account_id == account_id)
select(Project.id).where(
Project.id == project_id, Project.account_id == account_id
)
)
if not proj_result.scalars().first():
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Project not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Project not found"
)
result = await session.execute(
select(ProjectFunctionGroup).where(
@@ -427,7 +508,9 @@ async def update_function_group(
)
fg = result.scalars().first()
if not fg:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Function group not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Function group not found"
)
update_data = body.model_dump(exclude_unset=True)
for field, value in update_data.items():
@@ -438,7 +521,9 @@ async def update_function_group(
return ProjectFunctionGroupResponse.model_validate(fg)
@router.delete("/{project_id}/function-groups/{fg_id}", status_code=status.HTTP_204_NO_CONTENT)
@router.delete(
"/{project_id}/function-groups/{fg_id}", status_code=status.HTTP_204_NO_CONTENT
)
async def delete_function_group(
project_id: str,
fg_id: str,
@@ -449,10 +534,14 @@ async def delete_function_group(
account_id = current_user.account_id
proj_result = await session.execute(
select(Project.id).where(Project.id == project_id, Project.account_id == account_id)
select(Project.id).where(
Project.id == project_id, Project.account_id == account_id
)
)
if not proj_result.scalars().first():
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Project not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Project not found"
)
result = await session.execute(
select(ProjectFunctionGroup).where(
@@ -462,7 +551,9 @@ async def delete_function_group(
)
fg = result.scalars().first()
if not fg:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Function group not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Function group not found"
)
await session.delete(fg)
await session.commit()
@@ -472,7 +563,10 @@ async def delete_function_group(
# ===== ProjectFunction Endpoints =====
@router.get("/{project_id}/function-groups/{fg_id}/functions", response_model=ProjectFunctionListResponse)
@router.get(
"/{project_id}/function-groups/{fg_id}/functions",
response_model=ProjectFunctionListResponse,
)
async def list_project_functions(
project_id: str,
fg_id: str,
@@ -485,10 +579,14 @@ async def list_project_functions(
account_id = current_user.account_id
proj_result = await session.execute(
select(Project.id).where(Project.id == project_id, Project.account_id == account_id)
select(Project.id).where(
Project.id == project_id, Project.account_id == account_id
)
)
if not proj_result.scalars().first():
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Project not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Project not found"
)
# Verify function group belongs to project
fg_result = await session.execute(
@@ -498,13 +596,19 @@ async def list_project_functions(
)
)
if not fg_result.scalars().first():
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Function group not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Function group not found"
)
base_q = select(ProjectFunction).where(ProjectFunction.function_group_id == fg_id)
count_q = select(func.count()).select_from(base_q.subquery())
total = (await session.execute(count_q)).scalar() or 0
q = base_q.order_by(ProjectFunction.sort_order).offset((page - 1) * size).limit(size)
q = (
base_q.order_by(ProjectFunction.sort_order)
.offset((page - 1) * size)
.limit(size)
)
result = await session.execute(q)
items = result.scalars().all()
@@ -516,7 +620,11 @@ async def list_project_functions(
)
@router.post("/{project_id}/function-groups/{fg_id}/functions", response_model=ProjectFunctionResponse, status_code=status.HTTP_201_CREATED)
@router.post(
"/{project_id}/function-groups/{fg_id}/functions",
response_model=ProjectFunctionResponse,
status_code=status.HTTP_201_CREATED,
)
async def create_project_function(
project_id: str,
fg_id: str,
@@ -528,10 +636,14 @@ async def create_project_function(
account_id = current_user.account_id
proj_result = await session.execute(
select(Project.id).where(Project.id == project_id, Project.account_id == account_id)
select(Project.id).where(
Project.id == project_id, Project.account_id == account_id
)
)
if not proj_result.scalars().first():
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Project not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Project not found"
)
fg_result = await session.execute(
select(ProjectFunctionGroup.id).where(
@@ -540,7 +652,9 @@ async def create_project_function(
)
)
if not fg_result.scalars().first():
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Function group not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Function group not found"
)
func_obj = ProjectFunction(function_group_id=fg_id, **body.model_dump())
session.add(func_obj)
@@ -549,7 +663,10 @@ async def create_project_function(
return ProjectFunctionResponse.model_validate(func_obj)
@router.get("/{project_id}/function-groups/{fg_id}/functions/{func_id}", response_model=ProjectFunctionResponse)
@router.get(
"/{project_id}/function-groups/{fg_id}/functions/{func_id}",
response_model=ProjectFunctionResponse,
)
async def get_project_function(
project_id: str,
fg_id: str,
@@ -561,10 +678,14 @@ async def get_project_function(
account_id = current_user.account_id
proj_result = await session.execute(
select(Project.id).where(Project.id == project_id, Project.account_id == account_id)
select(Project.id).where(
Project.id == project_id, Project.account_id == account_id
)
)
if not proj_result.scalars().first():
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Project not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Project not found"
)
fg_result = await session.execute(
select(ProjectFunctionGroup.id).where(
@@ -573,7 +694,9 @@ async def get_project_function(
)
)
if not fg_result.scalars().first():
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Function group not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Function group not found"
)
result = await session.execute(
select(ProjectFunction).where(
@@ -583,11 +706,16 @@ async def get_project_function(
)
func_obj = result.scalars().first()
if not func_obj:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Function not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Function not found"
)
return ProjectFunctionResponse.model_validate(func_obj)
@router.put("/{project_id}/function-groups/{fg_id}/functions/{func_id}", response_model=ProjectFunctionResponse)
@router.put(
"/{project_id}/function-groups/{fg_id}/functions/{func_id}",
response_model=ProjectFunctionResponse,
)
async def update_project_function(
project_id: str,
fg_id: str,
@@ -600,10 +728,14 @@ async def update_project_function(
account_id = current_user.account_id
proj_result = await session.execute(
select(Project.id).where(Project.id == project_id, Project.account_id == account_id)
select(Project.id).where(
Project.id == project_id, Project.account_id == account_id
)
)
if not proj_result.scalars().first():
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Project not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Project not found"
)
fg_result = await session.execute(
select(ProjectFunctionGroup.id).where(
@@ -612,7 +744,9 @@ async def update_project_function(
)
)
if not fg_result.scalars().first():
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Function group not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Function group not found"
)
result = await session.execute(
select(ProjectFunction).where(
@@ -622,7 +756,9 @@ async def update_project_function(
)
func_obj = result.scalars().first()
if not func_obj:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Function not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Function not found"
)
update_data = body.model_dump(exclude_unset=True)
for field, value in update_data.items():
@@ -633,7 +769,10 @@ async def update_project_function(
return ProjectFunctionResponse.model_validate(func_obj)
@router.delete("/{project_id}/function-groups/{fg_id}/functions/{func_id}", status_code=status.HTTP_204_NO_CONTENT)
@router.delete(
"/{project_id}/function-groups/{fg_id}/functions/{func_id}",
status_code=status.HTTP_204_NO_CONTENT,
)
async def delete_project_function(
project_id: str,
fg_id: str,
@@ -645,10 +784,14 @@ async def delete_project_function(
account_id = current_user.account_id
proj_result = await session.execute(
select(Project.id).where(Project.id == project_id, Project.account_id == account_id)
select(Project.id).where(
Project.id == project_id, Project.account_id == account_id
)
)
if not proj_result.scalars().first():
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Project not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Project not found"
)
fg_result = await session.execute(
select(ProjectFunctionGroup.id).where(
@@ -657,7 +800,9 @@ async def delete_project_function(
)
)
if not fg_result.scalars().first():
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Function group not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Function group not found"
)
result = await session.execute(
select(ProjectFunction).where(
@@ -667,7 +812,9 @@ async def delete_project_function(
)
func_obj = result.scalars().first()
if not func_obj:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Function not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Function not found"
)
await session.delete(func_obj)
await session.commit()