style: apply black and isort formatting across entire codebase

- Standardize quote style (single to double quotes)
- Reorder and group imports alphabetically
- Fix line breaks and indentation for consistency
- Apply PEP 8 formatting standards

Also updated Makefile to exclude both venv and .venv from code quality checks.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-28 19:30:17 +01:00
parent 13f0094743
commit 21c13ca39b
236 changed files with 8450 additions and 6545 deletions

View File

@@ -3,25 +3,27 @@ Code Quality API Endpoints
RESTful API for architecture validation and violation management
"""
from typing import Optional
from datetime import datetime
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from pydantic import BaseModel, Field
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from pydantic import BaseModel, Field
from sqlalchemy.orm import Session
from app.api.deps import get_current_admin_api
from app.core.database import get_db
from app.services.code_quality_service import code_quality_service
from app.api.deps import get_current_admin_api
from models.database.user import User
router = APIRouter()
# Pydantic Models for API
class ScanResponse(BaseModel):
"""Response model for a scan"""
id: int
timestamp: str
total_files: int
@@ -38,6 +40,7 @@ class ScanResponse(BaseModel):
class ViolationResponse(BaseModel):
"""Response model for a violation"""
id: int
scan_id: int
rule_id: str
@@ -61,6 +64,7 @@ class ViolationResponse(BaseModel):
class ViolationListResponse(BaseModel):
"""Response model for paginated violations list"""
violations: list[ViolationResponse]
total: int
page: int
@@ -70,34 +74,42 @@ class ViolationListResponse(BaseModel):
class ViolationDetailResponse(ViolationResponse):
"""Response model for single violation with relationships"""
assignments: list = []
comments: list = []
class AssignViolationRequest(BaseModel):
"""Request model for assigning a violation"""
user_id: int = Field(..., description="User ID to assign to")
due_date: Optional[datetime] = Field(None, description="Due date for resolution")
priority: str = Field("medium", description="Priority level (low, medium, high, critical)")
priority: str = Field(
"medium", description="Priority level (low, medium, high, critical)"
)
class ResolveViolationRequest(BaseModel):
"""Request model for resolving a violation"""
resolution_note: str = Field(..., description="Note about the resolution")
class IgnoreViolationRequest(BaseModel):
"""Request model for ignoring a violation"""
reason: str = Field(..., description="Reason for ignoring")
class AddCommentRequest(BaseModel):
"""Request model for adding a comment"""
comment: str = Field(..., min_length=1, description="Comment text")
class DashboardStatsResponse(BaseModel):
"""Response model for dashboard statistics"""
total_violations: int
errors: int
warnings: int
@@ -116,10 +128,10 @@ class DashboardStatsResponse(BaseModel):
# API Endpoints
@router.post("/scan", response_model=ScanResponse)
async def trigger_scan(
db: Session = Depends(get_db),
current_user: User = Depends(get_current_admin_api)
db: Session = Depends(get_db), current_user: User = Depends(get_current_admin_api)
):
"""
Trigger a new architecture scan
@@ -127,7 +139,9 @@ async def trigger_scan(
Requires authentication. Runs the validator script and stores results.
"""
try:
scan = code_quality_service.run_scan(db, triggered_by=f"manual:{current_user.username}")
scan = code_quality_service.run_scan(
db, triggered_by=f"manual:{current_user.username}"
)
return ScanResponse(
id=scan.id,
@@ -138,7 +152,7 @@ async def trigger_scan(
warnings=scan.warnings,
duration_seconds=scan.duration_seconds,
triggered_by=scan.triggered_by,
git_commit_hash=scan.git_commit_hash
git_commit_hash=scan.git_commit_hash,
)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Scan failed: {str(e)}")
@@ -148,7 +162,7 @@ async def trigger_scan(
async def list_scans(
limit: int = Query(30, ge=1, le=100, description="Number of scans to return"),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_admin_api)
current_user: User = Depends(get_current_admin_api),
):
"""
Get scan history
@@ -167,7 +181,7 @@ async def list_scans(
warnings=scan.warnings,
duration_seconds=scan.duration_seconds,
triggered_by=scan.triggered_by,
git_commit_hash=scan.git_commit_hash
git_commit_hash=scan.git_commit_hash,
)
for scan in scans
]
@@ -175,15 +189,23 @@ async def list_scans(
@router.get("/violations", response_model=ViolationListResponse)
async def list_violations(
scan_id: Optional[int] = Query(None, description="Filter by scan ID (defaults to latest)"),
severity: Optional[str] = Query(None, description="Filter by severity (error, warning)"),
status: Optional[str] = Query(None, description="Filter by status (open, assigned, resolved, ignored)"),
scan_id: Optional[int] = Query(
None, description="Filter by scan ID (defaults to latest)"
),
severity: Optional[str] = Query(
None, description="Filter by severity (error, warning)"
),
status: Optional[str] = Query(
None, description="Filter by status (open, assigned, resolved, ignored)"
),
rule_id: Optional[str] = Query(None, description="Filter by rule ID"),
file_path: Optional[str] = Query(None, description="Filter by file path (partial match)"),
file_path: Optional[str] = Query(
None, description="Filter by file path (partial match)"
),
page: int = Query(1, ge=1, description="Page number"),
page_size: int = Query(50, ge=1, le=200, description="Items per page"),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_admin_api)
current_user: User = Depends(get_current_admin_api),
):
"""
Get violations with filtering and pagination
@@ -200,7 +222,7 @@ async def list_violations(
rule_id=rule_id,
file_path=file_path,
limit=page_size,
offset=offset
offset=offset,
)
total_pages = (total + page_size - 1) // page_size
@@ -223,14 +245,14 @@ async def list_violations(
resolved_at=v.resolved_at.isoformat() if v.resolved_at else None,
resolved_by=v.resolved_by,
resolution_note=v.resolution_note,
created_at=v.created_at.isoformat()
created_at=v.created_at.isoformat(),
)
for v in violations
],
total=total,
page=page,
page_size=page_size,
total_pages=total_pages
total_pages=total_pages,
)
@@ -238,7 +260,7 @@ async def list_violations(
async def get_violation(
violation_id: int,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_admin_api)
current_user: User = Depends(get_current_admin_api),
):
"""
Get single violation with details
@@ -253,12 +275,12 @@ async def get_violation(
# Format assignments
assignments = [
{
'id': a.id,
'user_id': a.user_id,
'assigned_at': a.assigned_at.isoformat(),
'assigned_by': a.assigned_by,
'due_date': a.due_date.isoformat() if a.due_date else None,
'priority': a.priority
"id": a.id,
"user_id": a.user_id,
"assigned_at": a.assigned_at.isoformat(),
"assigned_by": a.assigned_by,
"due_date": a.due_date.isoformat() if a.due_date else None,
"priority": a.priority,
}
for a in violation.assignments
]
@@ -266,10 +288,10 @@ async def get_violation(
# Format comments
comments = [
{
'id': c.id,
'user_id': c.user_id,
'comment': c.comment,
'created_at': c.created_at.isoformat()
"id": c.id,
"user_id": c.user_id,
"comment": c.comment,
"created_at": c.created_at.isoformat(),
}
for c in violation.comments
]
@@ -287,12 +309,14 @@ async def get_violation(
suggestion=violation.suggestion,
status=violation.status,
assigned_to=violation.assigned_to,
resolved_at=violation.resolved_at.isoformat() if violation.resolved_at else None,
resolved_at=(
violation.resolved_at.isoformat() if violation.resolved_at else None
),
resolved_by=violation.resolved_by,
resolution_note=violation.resolution_note,
created_at=violation.created_at.isoformat(),
assignments=assignments,
comments=comments
comments=comments,
)
@@ -301,7 +325,7 @@ async def assign_violation(
violation_id: int,
request: AssignViolationRequest,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_admin_api)
current_user: User = Depends(get_current_admin_api),
):
"""
Assign violation to a developer
@@ -315,17 +339,19 @@ async def assign_violation(
user_id=request.user_id,
assigned_by=current_user.id,
due_date=request.due_date,
priority=request.priority
priority=request.priority,
)
return {
'id': assignment.id,
'violation_id': assignment.violation_id,
'user_id': assignment.user_id,
'assigned_at': assignment.assigned_at.isoformat(),
'assigned_by': assignment.assigned_by,
'due_date': assignment.due_date.isoformat() if assignment.due_date else None,
'priority': assignment.priority
"id": assignment.id,
"violation_id": assignment.violation_id,
"user_id": assignment.user_id,
"assigned_at": assignment.assigned_at.isoformat(),
"assigned_by": assignment.assigned_by,
"due_date": (
assignment.due_date.isoformat() if assignment.due_date else None
),
"priority": assignment.priority,
}
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
@@ -336,7 +362,7 @@ async def resolve_violation(
violation_id: int,
request: ResolveViolationRequest,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_admin_api)
current_user: User = Depends(get_current_admin_api),
):
"""
Mark violation as resolved
@@ -348,15 +374,17 @@ async def resolve_violation(
db,
violation_id=violation_id,
resolved_by=current_user.id,
resolution_note=request.resolution_note
resolution_note=request.resolution_note,
)
return {
'id': violation.id,
'status': violation.status,
'resolved_at': violation.resolved_at.isoformat() if violation.resolved_at else None,
'resolved_by': violation.resolved_by,
'resolution_note': violation.resolution_note
"id": violation.id,
"status": violation.status,
"resolved_at": (
violation.resolved_at.isoformat() if violation.resolved_at else None
),
"resolved_by": violation.resolved_by,
"resolution_note": violation.resolution_note,
}
except ValueError as e:
raise HTTPException(status_code=404, detail=str(e))
@@ -369,7 +397,7 @@ async def ignore_violation(
violation_id: int,
request: IgnoreViolationRequest,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_admin_api)
current_user: User = Depends(get_current_admin_api),
):
"""
Mark violation as ignored (won't fix)
@@ -381,15 +409,17 @@ async def ignore_violation(
db,
violation_id=violation_id,
ignored_by=current_user.id,
reason=request.reason
reason=request.reason,
)
return {
'id': violation.id,
'status': violation.status,
'resolved_at': violation.resolved_at.isoformat() if violation.resolved_at else None,
'resolved_by': violation.resolved_by,
'resolution_note': violation.resolution_note
"id": violation.id,
"status": violation.status,
"resolved_at": (
violation.resolved_at.isoformat() if violation.resolved_at else None
),
"resolved_by": violation.resolved_by,
"resolution_note": violation.resolution_note,
}
except ValueError as e:
raise HTTPException(status_code=404, detail=str(e))
@@ -402,7 +432,7 @@ async def add_comment(
violation_id: int,
request: AddCommentRequest,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_admin_api)
current_user: User = Depends(get_current_admin_api),
):
"""
Add comment to violation
@@ -414,15 +444,15 @@ async def add_comment(
db,
violation_id=violation_id,
user_id=current_user.id,
comment=request.comment
comment=request.comment,
)
return {
'id': comment.id,
'violation_id': comment.violation_id,
'user_id': comment.user_id,
'comment': comment.comment,
'created_at': comment.created_at.isoformat()
"id": comment.id,
"violation_id": comment.violation_id,
"user_id": comment.user_id,
"comment": comment.comment,
"created_at": comment.created_at.isoformat(),
}
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
@@ -430,8 +460,7 @@ async def add_comment(
@router.get("/stats", response_model=DashboardStatsResponse)
async def get_dashboard_stats(
db: Session = Depends(get_db),
current_user: User = Depends(get_current_admin_api)
db: Session = Depends(get_db), current_user: User = Depends(get_current_admin_api)
):
"""
Get dashboard statistics