refactor(backend): select() and an inline now everywhere, held by a test

CLAUDE.md's canonical table names SQLAlchemy 2.0 select() and an inline
datetime.now(timezone.utc), and both had drifted: five db.query(...) calls
remained in routes/auth.py and routes/me.py (seven before the demo went),
and four private now helpers stood in sync/videos.py, utils.py (imported
as _now by explore and maintenance), scheduler.py (_now_iso) and the e2e
seed. All are the canonical form now.

Ruff cannot ban a method call on an instance or a function by name, so
tests/test_canonical_patterns.py reads every app module's AST and fails on
a .query(...) call or a now/_now/now_utc helper — seen red on a planted file.
This commit is contained in:
2026-10-05 00:19:39 +02:00
parent ab76166878
commit 24c47d12bd
10 changed files with 111 additions and 59 deletions
+12 -12
View File
@@ -22,10 +22,6 @@ log = logs.get_logger(__name__)
_DURATION_RE = re.compile(r"P(?:(\d+)D)?T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?", re.IGNORECASE)
def _now() -> datetime:
return datetime.now(timezone.utc)
def parse_iso8601_duration(value: str | None) -> int | None:
if not value:
return None
@@ -80,7 +76,7 @@ def apply_rss_feed(db: Session, channel: Channel, entries: list[dict]) -> int:
time. DB-only — must run on the session's own thread; the network fetch
(fetch_channel_feed) is kept separate so callers like run_rss_poll can parallelise it."""
inserted = insert_stubs(db, entries)
channel.last_rss_at = _now()
channel.last_rss_at = datetime.now(timezone.utc)
db.add(channel)
db.commit()
return inserted
@@ -96,7 +92,9 @@ def stub_from_playlist_item(item: dict, channel_id: str) -> dict | None:
# published_at is NOT NULL (migration 0068); fall back to now() for the rare item that carries no
# date at all, so the bulk stub insert never writes a NULL. The enrich pass replaces it if the
# video's own snippet later yields a real publish date.
published = parse_dt(content.get("videoPublishedAt") or snippet.get("publishedAt")) or _now()
published = parse_dt(
content.get("videoPublishedAt") or snippet.get("publishedAt")
) or datetime.now(timezone.utc)
return {
"id": video_id,
"channel_id": channel_id,
@@ -124,12 +122,14 @@ def backfill_channel_recent(db: Session, yt: YouTubeClient, channel: Channel) ->
"""First pass: newest videos up to the configured count or age cutoff. Records a
resume cursor for the later deep backfill."""
if not channel.uploads_playlist_id:
channel.recent_synced_at = _now()
channel.recent_synced_at = datetime.now(timezone.utc)
db.add(channel)
db.commit()
return 0
cutoff = _now() - timedelta(days=sysconfig.get_int(db, "backfill_recent_max_days"))
cutoff = datetime.now(timezone.utc) - timedelta(
days=sysconfig.get_int(db, "backfill_recent_max_days")
)
collected: list[dict] = []
page_token: str | None = None
next_cursor: str | None = None
@@ -164,7 +164,7 @@ def backfill_channel_recent(db: Session, yt: YouTubeClient, channel: Channel) ->
break
next_cursor = page_token # whole page consumed, more pages remain
channel.recent_synced_at = _now()
channel.recent_synced_at = datetime.now(timezone.utc)
channel.backfill_cursor = next_cursor
channel.backfill_done = done
inserted = insert_stubs(db, collected)
@@ -264,7 +264,7 @@ def apply_video_details(video: Video, item: dict) -> None:
if snippet_published:
video.published_at = snippet_published
elif not video.published_at:
video.published_at = _now()
video.published_at = datetime.now(timezone.utc)
video.thumbnail_url = best_thumbnail(snippet.get("thumbnails")) or video.thumbnail_url
video.duration_seconds = parse_iso8601_duration(content.get("duration"))
video.view_count = int(stats["viewCount"]) if stats.get("viewCount") else None
@@ -296,7 +296,7 @@ def _apply_video_batch(
if not videos:
return 0
items = {it["id"]: it for it in yt.get_videos([v.id for v in videos])}
now = _now()
now = datetime.now(timezone.utc)
applied = 0
for video in videos:
item = items.get(video.id)
@@ -312,7 +312,7 @@ def _apply_video_batch(
def _mark_enriched(video: Video) -> None:
# Unavailable (deleted/private): stamp so we don't keep retrying.
video.enriched_at = _now()
video.enriched_at = datetime.now(timezone.utc)
def enrich_pending(db: Session, yt: YouTubeClient, limit: int | None = None) -> int: