Merge pull request #1146 from jamiepine/prep/pr-659

fix: replace deprecated datetime.utcnow() with datetime.now(UTC) throughout
This commit is contained in:
capy-ai-staging[bot]
2026-10-04 00:05:36 +00:00
committed by GitHub
12 changed files with 62 additions and 62 deletions
+18 -18
View File
@@ -1,6 +1,6 @@
"""ORM model definitions for the voicebox SQLite database.""" """ORM model definitions for the voicebox SQLite database."""
from datetime import datetime from datetime import UTC, datetime
import uuid import uuid
from sqlalchemy import Column, String, Integer, Float, DateTime, Text, ForeignKey, Boolean, JSON from sqlalchemy import Column, String, Integer, Float, DateTime, Text, ForeignKey, Boolean, JSON
@@ -44,8 +44,8 @@ class VoiceProfile(Base):
# cloning metadata above). # cloning metadata above).
personality = Column(Text, nullable=True) personality = Column(Text, nullable=True)
created_at = Column(DateTime, default=datetime.utcnow) created_at = Column(DateTime, default=lambda: datetime.now(UTC))
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) updated_at = Column(DateTime, default=lambda: datetime.now(UTC), onupdate=lambda: datetime.now(UTC))
class ProfileSample(Base): class ProfileSample(Base):
@@ -82,7 +82,7 @@ class Generation(Base):
# profile's personality LLM before TTS. Future sources (bulk import, # profile's personality LLM before TTS. Future sources (bulk import,
# agent replies, etc.) can extend this. # agent replies, etc.) can extend this.
source = Column(String, nullable=False, default="manual") source = Column(String, nullable=False, default="manual")
created_at = Column(DateTime, default=datetime.utcnow, index=True) created_at = Column(DateTime, default=lambda: datetime.now(UTC), index=True)
class Story(Base): class Story(Base):
@@ -93,8 +93,8 @@ class Story(Base):
id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4())) id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4()))
name = Column(String, nullable=False) name = Column(String, nullable=False)
description = Column(Text) description = Column(Text)
created_at = Column(DateTime, default=datetime.utcnow) created_at = Column(DateTime, default=lambda: datetime.now(UTC))
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) updated_at = Column(DateTime, default=lambda: datetime.now(UTC), onupdate=lambda: datetime.now(UTC))
class StoryItem(Base): class StoryItem(Base):
@@ -111,7 +111,7 @@ class StoryItem(Base):
trim_start_ms = Column(Integer, nullable=False, default=0) trim_start_ms = Column(Integer, nullable=False, default=0)
trim_end_ms = Column(Integer, nullable=False, default=0) trim_end_ms = Column(Integer, nullable=False, default=0)
volume = Column(Float, nullable=False, default=1.0) volume = Column(Float, nullable=False, default=1.0)
created_at = Column(DateTime, default=datetime.utcnow) created_at = Column(DateTime, default=lambda: datetime.now(UTC))
class Project(Base): class Project(Base):
@@ -122,8 +122,8 @@ class Project(Base):
id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4())) id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4()))
name = Column(String, nullable=False) name = Column(String, nullable=False)
data = Column(Text) data = Column(Text)
created_at = Column(DateTime, default=datetime.utcnow) created_at = Column(DateTime, default=lambda: datetime.now(UTC))
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) updated_at = Column(DateTime, default=lambda: datetime.now(UTC), onupdate=lambda: datetime.now(UTC))
class GenerationVersion(Base): class GenerationVersion(Base):
@@ -138,7 +138,7 @@ class GenerationVersion(Base):
effects_chain = Column(Text, nullable=True) effects_chain = Column(Text, nullable=True)
source_version_id = Column(String, ForeignKey("generation_versions.id"), nullable=True) source_version_id = Column(String, ForeignKey("generation_versions.id"), nullable=True)
is_default = Column(Boolean, default=False) is_default = Column(Boolean, default=False)
created_at = Column(DateTime, default=datetime.utcnow) created_at = Column(DateTime, default=lambda: datetime.now(UTC))
class EffectPreset(Base): class EffectPreset(Base):
@@ -152,7 +152,7 @@ class EffectPreset(Base):
effects_chain = Column(Text, nullable=False) effects_chain = Column(Text, nullable=False)
is_builtin = Column(Boolean, default=False) is_builtin = Column(Boolean, default=False)
sort_order = Column(Integer, default=100) sort_order = Column(Integer, default=100)
created_at = Column(DateTime, default=datetime.utcnow) created_at = Column(DateTime, default=lambda: datetime.now(UTC))
class AudioChannel(Base): class AudioChannel(Base):
@@ -163,7 +163,7 @@ class AudioChannel(Base):
id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4())) id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4()))
name = Column(String, nullable=False) name = Column(String, nullable=False)
is_default = Column(Boolean, default=False) is_default = Column(Boolean, default=False)
created_at = Column(DateTime, default=datetime.utcnow) created_at = Column(DateTime, default=lambda: datetime.now(UTC))
class ChannelDeviceMapping(Base): class ChannelDeviceMapping(Base):
@@ -218,7 +218,7 @@ class CaptureSettings(Base):
chord_toggle_to_talk_keys = Column( chord_toggle_to_talk_keys = Column(
JSON, nullable=False, default=default_toggle_to_talk_chord JSON, nullable=False, default=default_toggle_to_talk_chord
) )
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) updated_at = Column(DateTime, default=lambda: datetime.now(UTC), onupdate=lambda: datetime.now(UTC))
class GenerationSettings(Base): class GenerationSettings(Base):
@@ -231,7 +231,7 @@ class GenerationSettings(Base):
crossfade_ms = Column(Integer, nullable=False, default=50) crossfade_ms = Column(Integer, nullable=False, default=50)
normalize_audio = Column(Boolean, nullable=False, default=True) normalize_audio = Column(Boolean, nullable=False, default=True)
autoplay_on_generate = Column(Boolean, nullable=False, default=True) autoplay_on_generate = Column(Boolean, nullable=False, default=True)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) updated_at = Column(DateTime, default=lambda: datetime.now(UTC), onupdate=lambda: datetime.now(UTC))
class CloudSettings(Base): class CloudSettings(Base):
@@ -253,7 +253,7 @@ class CloudSettings(Base):
device_name = Column(String, nullable=True) device_name = Column(String, nullable=True)
account_user_id = Column(String, nullable=True) account_user_id = Column(String, nullable=True)
connected_at = Column(DateTime, nullable=True) connected_at = Column(DateTime, nullable=True)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) updated_at = Column(DateTime, default=lambda: datetime.now(UTC), onupdate=lambda: datetime.now(UTC))
class MCPClientBinding(Base): class MCPClientBinding(Base):
@@ -276,8 +276,8 @@ class MCPClientBinding(Base):
# (rewrite) before TTS by default. Callers can still override per call. # (rewrite) before TTS by default. Callers can still override per call.
default_personality = Column(Boolean, nullable=False, default=False) default_personality = Column(Boolean, nullable=False, default=False)
last_seen_at = Column(DateTime, nullable=True) last_seen_at = Column(DateTime, nullable=True)
created_at = Column(DateTime, default=datetime.utcnow) created_at = Column(DateTime, default=lambda: datetime.now(UTC))
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) updated_at = Column(DateTime, default=lambda: datetime.now(UTC), onupdate=lambda: datetime.now(UTC))
class Capture(Base): class Capture(Base):
@@ -300,4 +300,4 @@ class Capture(Base):
stt_model = Column(String, nullable=True) stt_model = Column(String, nullable=True)
llm_model = Column(String, nullable=True) llm_model = Column(String, nullable=True)
refinement_flags = Column(Text, nullable=True) # JSON blob refinement_flags = Column(Text, nullable=True) # JSON blob
created_at = Column(DateTime, default=datetime.utcnow, index=True) created_at = Column(DateTime, default=lambda: datetime.now(UTC), index=True)
+2 -2
View File
@@ -4,7 +4,7 @@ import io
import json as _json import json as _json
import logging import logging
import tempfile import tempfile
from datetime import datetime from datetime import UTC, datetime
from pathlib import Path from pathlib import Path
from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile
@@ -356,7 +356,7 @@ async def update_profile_effects(
else: else:
profile.effects_chain = None profile.effects_chain = None
profile.updated_at = datetime.utcnow() profile.updated_at = datetime.now(UTC)
db.commit() db.commit()
db.refresh(profile) db.refresh(profile)
+3 -3
View File
@@ -1,6 +1,6 @@
"""Task and cache management endpoints.""" """Task and cache management endpoints."""
from datetime import datetime from datetime import UTC, datetime
from fastapi import APIRouter from fastapi import APIRouter
@@ -91,9 +91,9 @@ async def get_active_tasks():
try: try:
started_at = datetime.fromisoformat(timestamp_str.replace("Z", "+00:00")) started_at = datetime.fromisoformat(timestamp_str.replace("Z", "+00:00"))
except (ValueError, AttributeError): except (ValueError, AttributeError):
started_at = datetime.utcnow() started_at = datetime.now(UTC)
else: else:
started_at = datetime.utcnow() started_at = datetime.now(UTC)
active_downloads.append( active_downloads.append(
models.ActiveDownloadTask( models.ActiveDownloadTask(
+2 -2
View File
@@ -3,7 +3,7 @@ Audio channel management module.
""" """
from typing import List, Optional from typing import List, Optional
from datetime import datetime from datetime import UTC, datetime
import uuid import uuid
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
@@ -81,7 +81,7 @@ async def create_channel(
id=str(uuid.uuid4()), id=str(uuid.uuid4()),
name=data.name, name=data.name,
is_default=False, is_default=False,
created_at=datetime.utcnow(), created_at=datetime.now(UTC),
) )
db.add(channel) db.add(channel)
db.flush() db.flush()
+2 -2
View File
@@ -140,13 +140,13 @@ def _get_or_create_row(db: Session) -> DBCloudSettings:
def _store_key(db: Session, *, api_key: str, device_name: str | None, account_user_id: str | None): def _store_key(db: Session, *, api_key: str, device_name: str | None, account_user_id: str | None):
from datetime import datetime from datetime import UTC, datetime
row = _get_or_create_row(db) row = _get_or_create_row(db)
row.api_key = api_key row.api_key = api_key
row.device_name = device_name row.device_name = device_name
row.account_user_id = account_user_id row.account_user_id = account_user_id
row.connected_at = datetime.utcnow() row.connected_at = datetime.now(UTC)
db.commit() db.commit()
+2 -2
View File
@@ -347,7 +347,7 @@ async def import_generation_from_zip(file_bytes: bytes, db: Session) -> dict:
from pathlib import Path from pathlib import Path
import tempfile import tempfile
import shutil import shutil
from datetime import datetime from datetime import UTC, datetime
from .. import config from .. import config
zip_buffer = io.BytesIO(file_bytes) zip_buffer = io.BytesIO(file_bytes)
@@ -432,7 +432,7 @@ async def import_generation_from_zip(file_bytes: bytes, db: Session) -> dict:
duration=generation_data["duration"], duration=generation_data["duration"],
seed=generation_data.get("seed"), seed=generation_data.get("seed"),
instruct=generation_data.get("instruct"), instruct=generation_data.get("instruct"),
created_at=datetime.utcnow(), created_at=datetime.now(UTC),
) )
db.add(db_generation) db.add(db_generation)
+2 -2
View File
@@ -3,7 +3,7 @@ Generation history management module.
""" """
from typing import List, Optional, Tuple from typing import List, Optional, Tuple
from datetime import datetime from datetime import UTC, datetime
import uuid import uuid
import shutil import shutil
from pathlib import Path from pathlib import Path
@@ -124,7 +124,7 @@ async def create_generation(
model_size=model_size, model_size=model_size,
status=status, status=status,
source=source, source=source,
created_at=datetime.utcnow(), created_at=datetime.now(UTC),
) )
db.add(db_generation) db.add(db_generation)
+7 -7
View File
@@ -4,7 +4,7 @@ import json as _json
import logging import logging
import shutil import shutil
import uuid import uuid
from datetime import datetime from datetime import UTC, datetime
from pathlib import Path from pathlib import Path
from sqlalchemy import func from sqlalchemy import func
@@ -183,8 +183,8 @@ async def create_profile(
design_prompt=data.design_prompt, design_prompt=data.design_prompt,
default_engine=default_engine, default_engine=default_engine,
personality=data.personality, personality=data.personality,
created_at=datetime.utcnow(), created_at=datetime.now(UTC),
updated_at=datetime.utcnow(), updated_at=datetime.now(UTC),
) )
db.add(db_profile) db.add(db_profile)
@@ -244,7 +244,7 @@ async def add_profile_sample(
db.add(db_sample) db.add(db_sample)
profile.updated_at = datetime.utcnow() profile.updated_at = datetime.now(UTC)
db.commit() db.commit()
db.refresh(db_sample) db.refresh(db_sample)
@@ -403,7 +403,7 @@ async def update_profile(
profile.personality = data.personality profile.personality = data.personality
if data.default_engine is not None: if data.default_engine is not None:
profile.default_engine = data.default_engine or None # empty string → NULL profile.default_engine = data.default_engine or None # empty string → NULL
profile.updated_at = datetime.utcnow() profile.updated_at = datetime.now(UTC)
db.commit() db.commit()
db.refresh(profile) db.refresh(profile)
@@ -672,7 +672,7 @@ async def upload_avatar(
process_avatar(image_path, str(output_path)) process_avatar(image_path, str(output_path))
profile.avatar_path = config.to_storage_path(output_path) profile.avatar_path = config.to_storage_path(output_path)
profile.updated_at = datetime.utcnow() profile.updated_at = datetime.now(UTC)
db.commit() db.commit()
db.refresh(profile) db.refresh(profile)
@@ -703,7 +703,7 @@ async def delete_avatar(
avatar_path.unlink() avatar_path.unlink()
profile.avatar_path = None profile.avatar_path = None
profile.updated_at = datetime.utcnow() profile.updated_at = datetime.now(UTC)
db.commit() db.commit()
+17 -17
View File
@@ -3,7 +3,7 @@ Story management module.
""" """
from typing import List, Optional from typing import List, Optional
from datetime import datetime from datetime import UTC, datetime
import uuid import uuid
import tempfile import tempfile
from pathlib import Path from pathlib import Path
@@ -96,8 +96,8 @@ async def create_story(
id=str(uuid.uuid4()), id=str(uuid.uuid4()),
name=data.name, name=data.name,
description=data.description, description=data.description,
created_at=datetime.utcnow(), created_at=datetime.now(UTC),
updated_at=datetime.utcnow(), updated_at=datetime.now(UTC),
) )
db.add(db_story) db.add(db_story)
@@ -206,7 +206,7 @@ async def update_story(
story.name = data.name story.name = data.name
story.description = data.description story.description = data.description
story.updated_at = datetime.utcnow() story.updated_at = datetime.now(UTC)
db.commit() db.commit()
db.refresh(story) db.refresh(story)
@@ -314,13 +314,13 @@ async def add_item_to_story(
generation_id=data.generation_id, generation_id=data.generation_id,
start_time_ms=start_time_ms, start_time_ms=start_time_ms,
track=track, track=track,
created_at=datetime.utcnow(), created_at=datetime.now(UTC),
) )
db.add(item) db.add(item)
# Update story updated_at # Update story updated_at
story.updated_at = datetime.utcnow() story.updated_at = datetime.now(UTC)
db.commit() db.commit()
db.refresh(item) db.refresh(item)
@@ -373,7 +373,7 @@ async def move_story_item(
# Update story updated_at # Update story updated_at
story = db.query(DBStory).filter_by(id=story_id).first() story = db.query(DBStory).filter_by(id=story_id).first()
if story: if story:
story.updated_at = datetime.utcnow() story.updated_at = datetime.now(UTC)
db.commit() db.commit()
db.refresh(item) db.refresh(item)
@@ -417,7 +417,7 @@ async def remove_item_from_story(
# Update story updated_at # Update story updated_at
story = db.query(DBStory).filter_by(id=story_id).first() story = db.query(DBStory).filter_by(id=story_id).first()
if story: if story:
story.updated_at = datetime.utcnow() story.updated_at = datetime.now(UTC)
db.commit() db.commit()
return True return True
@@ -470,7 +470,7 @@ async def trim_story_item(
# Update story updated_at # Update story updated_at
story = db.query(DBStory).filter_by(id=story_id).first() story = db.query(DBStory).filter_by(id=story_id).first()
if story: if story:
story.updated_at = datetime.utcnow() story.updated_at = datetime.now(UTC)
db.commit() db.commit()
db.refresh(item) db.refresh(item)
@@ -503,7 +503,7 @@ async def update_story_item_volume(
story = db.query(DBStory).filter_by(id=story_id).first() story = db.query(DBStory).filter_by(id=story_id).first()
if story: if story:
story.updated_at = datetime.utcnow() story.updated_at = datetime.now(UTC)
db.commit() db.commit()
db.refresh(item) db.refresh(item)
@@ -576,7 +576,7 @@ async def split_story_item(
trim_start_ms=absolute_split_ms, trim_start_ms=absolute_split_ms,
trim_end_ms=current_trim_end, trim_end_ms=current_trim_end,
volume=getattr(item, "volume", 1.0), volume=getattr(item, "volume", 1.0),
created_at=datetime.utcnow(), created_at=datetime.now(UTC),
) )
db.add(new_item) db.add(new_item)
@@ -584,7 +584,7 @@ async def split_story_item(
# Update story updated_at # Update story updated_at
story = db.query(DBStory).filter_by(id=story_id).first() story = db.query(DBStory).filter_by(id=story_id).first()
if story: if story:
story.updated_at = datetime.utcnow() story.updated_at = datetime.now(UTC)
db.commit() db.commit()
db.refresh(item) db.refresh(item)
@@ -650,7 +650,7 @@ async def duplicate_story_item(
trim_start_ms=current_trim_start, trim_start_ms=current_trim_start,
trim_end_ms=current_trim_end, trim_end_ms=current_trim_end,
volume=getattr(original_item, "volume", 1.0), volume=getattr(original_item, "volume", 1.0),
created_at=datetime.utcnow(), created_at=datetime.now(UTC),
) )
db.add(new_item) db.add(new_item)
@@ -658,7 +658,7 @@ async def duplicate_story_item(
# Update story updated_at # Update story updated_at
story = db.query(DBStory).filter_by(id=story_id).first() story = db.query(DBStory).filter_by(id=story_id).first()
if story: if story:
story.updated_at = datetime.utcnow() story.updated_at = datetime.now(UTC)
db.commit() db.commit()
db.refresh(new_item) db.refresh(new_item)
@@ -700,7 +700,7 @@ async def update_story_item_times(
item_map[update.generation_id].start_time_ms = update.start_time_ms item_map[update.generation_id].start_time_ms = update.start_time_ms
# Update story updated_at # Update story updated_at
story.updated_at = datetime.utcnow() story.updated_at = datetime.now(UTC)
db.commit() db.commit()
return True return True
@@ -764,7 +764,7 @@ async def reorder_story_items(
updated_items.append(_build_item_detail(item, generation, profile_name, db)) updated_items.append(_build_item_detail(item, generation, profile_name, db))
# Update story updated_at # Update story updated_at
story.updated_at = datetime.utcnow() story.updated_at = datetime.now(UTC)
db.commit() db.commit()
return updated_items return updated_items
@@ -823,7 +823,7 @@ async def set_story_item_version(
# Update story updated_at # Update story updated_at
story = db.query(DBStory).filter_by(id=story_id).first() story = db.query(DBStory).filter_by(id=story_id).first()
if story: if story:
story.updated_at = datetime.utcnow() story.updated_at = datetime.now(UTC)
db.commit() db.commit()
db.refresh(item) db.refresh(item)
+3 -3
View File
@@ -3,7 +3,7 @@ Task tracking for active downloads and generations.
""" """
from typing import Optional, Dict, List from typing import Optional, Dict, List
from datetime import datetime from datetime import UTC, datetime
from dataclasses import dataclass, field from dataclasses import dataclass, field
@@ -12,7 +12,7 @@ class DownloadTask:
"""Represents an active download task.""" """Represents an active download task."""
model_name: str model_name: str
status: str = "downloading" # downloading, extracting, complete, error status: str = "downloading" # downloading, extracting, complete, error
started_at: datetime = field(default_factory=datetime.utcnow) started_at: datetime = field(default_factory=lambda: datetime.now(UTC))
error: Optional[str] = None error: Optional[str] = None
@@ -22,7 +22,7 @@ class GenerationTask:
task_id: str task_id: str
profile_id: str profile_id: str
text_preview: str # First 50 chars of text text_preview: str # First 50 chars of text
started_at: datetime = field(default_factory=datetime.utcnow) started_at: datetime = field(default_factory=lambda: datetime.now(UTC))
class TaskManager: class TaskManager:
+2 -2
View File
@@ -28,7 +28,7 @@ class Generation(Base):
status = Column(String, default="completed") # pending | completed | failed status = Column(String, default="completed") # pending | completed | failed
error = Column(Text, nullable=True) error = Column(Text, nullable=True)
is_favorited = Column(Boolean, default=False) is_favorited = Column(Boolean, default=False)
created_at = Column(DateTime, default=datetime.utcnow) created_at = Column(DateTime, default=lambda: datetime.now(UTC))
``` ```
Each generation can also have multiple **generation versions** — processed variants with different effects chains applied. The original (`clean`) version plus any number of processed versions live in a separate `generation_versions` table. See [Effects Pipeline](/developer/effects-pipeline). Each generation can also have multiple **generation versions** — processed variants with different effects chains applied. The original (`clean`) version plus any number of processed versions live in a separate `generation_versions` table. See [Effects Pipeline](/developer/effects-pipeline).
@@ -71,7 +71,7 @@ async def create_generation(
duration=duration, duration=duration,
seed=seed, seed=seed,
instruct=instruct, instruct=instruct,
created_at=datetime.utcnow(), created_at=datetime.now(UTC),
) )
db.add(db_generation) db.add(db_generation)
@@ -44,8 +44,8 @@ class VoiceProfile(Base):
design_prompt = Column(Text, nullable=True) # text description — only for designed (reserved) design_prompt = Column(Text, nullable=True) # text description — only for designed (reserved)
default_engine = Column(String, nullable=True) # auto-selected engine, locked for preset default_engine = Column(String, nullable=True) # auto-selected engine, locked for preset
created_at = Column(DateTime, default=datetime.utcnow) created_at = Column(DateTime, default=lambda: datetime.now(UTC))
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) updated_at = Column(DateTime, default=lambda: datetime.now(UTC), onupdate=lambda: datetime.now(UTC))
``` ```
The `voice_type` column discriminates the three flavors: The `voice_type` column discriminates the three flavors: