chore(backend): deprecation sweep — Pydantic V1 -> V2, utcnow -> tz-aware
Two low-risk Pydantic V1 idioms that will be hard errors in V3:
- Query(regex=...) -> Query(pattern=...) (audit_routes, control_generator_routes)
- class Config: from_attributes=True -> model_config = ConfigDict(...)
in source_policy_router.py (schemas.py is intentionally skipped — it is
the Phase 1 schema-split target and the ConfigDict conversion is most
efficient to do during that split).
Naive -> aware datetime sweep across 47 files:
- datetime.utcnow() -> datetime.now(timezone.utc)
- default=datetime.utcnow -> default=lambda: datetime.now(timezone.utc)
- onupdate=datetime.utcnow -> onupdate=lambda: datetime.now(timezone.utc)
All SQLAlchemy DateTime columns in the project already declare
timezone=True, so the DB schema expects aware datetimes. Before this
commit, the in-Python side was generating naive values and the driver
was silently coercing them. This is a latent-bug fix, not a behavior
change at the DB boundary.
Verified:
- 173/173 pytest compliance/tests/ pass (same as baseline)
- tests/contracts/test_openapi_baseline.py passes (360 paths,
484 operations unchanged)
- DeprecationWarning count dropped from 158 -> 35
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,7 @@ Provides CRUD operations and business logic queries for all compliance entities.
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
from datetime import datetime, date
|
||||
from datetime import datetime, date, timezone
|
||||
from typing import List, Optional, Dict, Any
|
||||
|
||||
from sqlalchemy.orm import Session as DBSession, selectinload, joinedload
|
||||
@@ -86,7 +86,7 @@ class RegulationRepository:
|
||||
for key, value in kwargs.items():
|
||||
if hasattr(regulation, key):
|
||||
setattr(regulation, key, value)
|
||||
regulation.updated_at = datetime.utcnow()
|
||||
regulation.updated_at = datetime.now(timezone.utc)
|
||||
self.db.commit()
|
||||
self.db.refresh(regulation)
|
||||
return regulation
|
||||
@@ -425,7 +425,7 @@ class ControlRepository:
|
||||
control.status = status
|
||||
if status_notes:
|
||||
control.status_notes = status_notes
|
||||
control.updated_at = datetime.utcnow()
|
||||
control.updated_at = datetime.now(timezone.utc)
|
||||
self.db.commit()
|
||||
self.db.refresh(control)
|
||||
return control
|
||||
@@ -435,10 +435,10 @@ class ControlRepository:
|
||||
control = self.get_by_control_id(control_id)
|
||||
if not control:
|
||||
return None
|
||||
control.last_reviewed_at = datetime.utcnow()
|
||||
control.last_reviewed_at = datetime.now(timezone.utc)
|
||||
from datetime import timedelta
|
||||
control.next_review_at = datetime.utcnow() + timedelta(days=control.review_frequency_days)
|
||||
control.updated_at = datetime.utcnow()
|
||||
control.next_review_at = datetime.now(timezone.utc) + timedelta(days=control.review_frequency_days)
|
||||
control.updated_at = datetime.now(timezone.utc)
|
||||
self.db.commit()
|
||||
self.db.refresh(control)
|
||||
return control
|
||||
@@ -450,7 +450,7 @@ class ControlRepository:
|
||||
.filter(
|
||||
or_(
|
||||
ControlDB.next_review_at is None,
|
||||
ControlDB.next_review_at <= datetime.utcnow()
|
||||
ControlDB.next_review_at <= datetime.now(timezone.utc)
|
||||
)
|
||||
)
|
||||
.order_by(ControlDB.next_review_at)
|
||||
@@ -624,7 +624,7 @@ class EvidenceRepository:
|
||||
if not evidence:
|
||||
return None
|
||||
evidence.status = status
|
||||
evidence.updated_at = datetime.utcnow()
|
||||
evidence.updated_at = datetime.now(timezone.utc)
|
||||
self.db.commit()
|
||||
self.db.refresh(evidence)
|
||||
return evidence
|
||||
@@ -749,7 +749,7 @@ class RiskRepository:
|
||||
risk.residual_likelihood, risk.residual_impact
|
||||
)
|
||||
|
||||
risk.updated_at = datetime.utcnow()
|
||||
risk.updated_at = datetime.now(timezone.utc)
|
||||
self.db.commit()
|
||||
self.db.refresh(risk)
|
||||
return risk
|
||||
@@ -860,9 +860,9 @@ class AuditExportRepository:
|
||||
export.compliance_score = compliance_score
|
||||
|
||||
if status == ExportStatusEnum.COMPLETED:
|
||||
export.completed_at = datetime.utcnow()
|
||||
export.completed_at = datetime.now(timezone.utc)
|
||||
|
||||
export.updated_at = datetime.utcnow()
|
||||
export.updated_at = datetime.now(timezone.utc)
|
||||
self.db.commit()
|
||||
self.db.refresh(export)
|
||||
return export
|
||||
@@ -1156,11 +1156,11 @@ class AuditSessionRepository:
|
||||
|
||||
session.status = status
|
||||
if status == AuditSessionStatusEnum.IN_PROGRESS and not session.started_at:
|
||||
session.started_at = datetime.utcnow()
|
||||
session.started_at = datetime.now(timezone.utc)
|
||||
elif status == AuditSessionStatusEnum.COMPLETED:
|
||||
session.completed_at = datetime.utcnow()
|
||||
session.completed_at = datetime.now(timezone.utc)
|
||||
|
||||
session.updated_at = datetime.utcnow()
|
||||
session.updated_at = datetime.now(timezone.utc)
|
||||
self.db.commit()
|
||||
self.db.refresh(session)
|
||||
return session
|
||||
@@ -1183,7 +1183,7 @@ class AuditSessionRepository:
|
||||
if completed_items is not None:
|
||||
session.completed_items = completed_items
|
||||
|
||||
session.updated_at = datetime.utcnow()
|
||||
session.updated_at = datetime.now(timezone.utc)
|
||||
self.db.commit()
|
||||
self.db.refresh(session)
|
||||
return session
|
||||
@@ -1207,9 +1207,9 @@ class AuditSessionRepository:
|
||||
total_requirements = query.scalar() or 0
|
||||
|
||||
session.status = AuditSessionStatusEnum.IN_PROGRESS
|
||||
session.started_at = datetime.utcnow()
|
||||
session.started_at = datetime.now(timezone.utc)
|
||||
session.total_items = total_requirements
|
||||
session.updated_at = datetime.utcnow()
|
||||
session.updated_at = datetime.now(timezone.utc)
|
||||
|
||||
self.db.commit()
|
||||
self.db.refresh(session)
|
||||
@@ -1344,7 +1344,7 @@ class AuditSignOffRepository:
|
||||
if sign and signed_by:
|
||||
signoff.create_signature(signed_by)
|
||||
|
||||
signoff.updated_at = datetime.utcnow()
|
||||
signoff.updated_at = datetime.now(timezone.utc)
|
||||
self.db.commit()
|
||||
self.db.refresh(signoff)
|
||||
|
||||
@@ -1376,7 +1376,7 @@ class AuditSignOffRepository:
|
||||
signoff.notes = notes
|
||||
if sign and signed_by:
|
||||
signoff.create_signature(signed_by)
|
||||
signoff.updated_at = datetime.utcnow()
|
||||
signoff.updated_at = datetime.now(timezone.utc)
|
||||
else:
|
||||
# Create new
|
||||
signoff = AuditSignOffDB(
|
||||
@@ -1416,7 +1416,7 @@ class AuditSignOffRepository:
|
||||
).first()
|
||||
if session:
|
||||
session.completed_items = completed
|
||||
session.updated_at = datetime.utcnow()
|
||||
session.updated_at = datetime.now(timezone.utc)
|
||||
self.db.commit()
|
||||
|
||||
def get_checklist(
|
||||
|
||||
Reference in New Issue
Block a user