fix: add unbuffered python output in dev runner, cursor pattern in analytics

- dev_run.sh: add -u flag so log output is not buffered (real-time visibility)
- analytics.py: use explicit cursor() with try/finally close instead of
  calling execute() directly on the connection (thread-safe cursor lifecycle)
- .sops.yaml: add second age public key for local dev decryption access
- content/__init__.py: whitespace-only formatting fix

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Deeman
2026-02-24 19:29:51 +01:00
parent 3a169d9443
commit 3dc7a7fc02
4 changed files with 14 additions and 9 deletions

View File

@@ -1,3 +1,3 @@
creation_rules: creation_rules:
- path_regex: \.env\..+\.sops$ - path_regex: \.env\..+\.sops$
age: age1f5002gj4s78jju45jd28kuejtcfhn5cdujz885fl7z2p9ym68pnsgky87a age: age1f5002gj4s78jju45jd28kuejtcfhn5cdujz885fl7z2p9ym68pnsgky87a,age1wjepykv3glvsrtegu25tevg7vyn3ngpl607u3yjc9ucay04s045s796msw

View File

@@ -165,8 +165,8 @@ echo ""
echo "Press Ctrl-C to stop all processes." echo "Press Ctrl-C to stop all processes."
echo "" echo ""
run_with_label "$COLOR_APP" "app " uv run python -m padelnomics.app run_with_label "$COLOR_APP" "app " uv run python -u -m padelnomics.app
run_with_label "$COLOR_WORKER" "worker" uv run python -m padelnomics.worker run_with_label "$COLOR_WORKER" "worker" uv run python -u -m padelnomics.worker
run_with_label "$COLOR_CSS" "css " make css-watch run_with_label "$COLOR_CSS" "css " make css-watch
wait wait

View File

@@ -51,9 +51,13 @@ async def fetch_analytics(sql: str, params: list | None = None) -> list[dict[str
return [] return []
def _run() -> list[dict]: def _run() -> list[dict]:
rel = _conn.execute(sql, params or []) cur = _conn.cursor()
cols = [d[0] for d in rel.description] try:
return [dict(zip(cols, row)) for row in rel.fetchall()] rel = cur.execute(sql, params or [])
cols = [d[0] for d in rel.description]
return [dict(zip(cols, row)) for row in rel.fetchall()]
finally:
cur.close()
try: try:
return await asyncio.to_thread(_run) return await asyncio.to_thread(_run)

View File

@@ -367,7 +367,7 @@ async def generate_articles(
"""INSERT INTO published_scenarios """INSERT INTO published_scenarios
(slug, title, location, country, venue_type, ownership, (slug, title, location, country, venue_type, ownership,
court_config, state_json, calc_json, created_at) court_config, state_json, calc_json, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(slug) DO UPDATE SET ON CONFLICT(slug) DO UPDATE SET
state_json = excluded.state_json, state_json = excluded.state_json,
calc_json = excluded.calc_json, calc_json = excluded.calc_json,
@@ -474,13 +474,14 @@ async def generate_articles(
md_dir.mkdir(parents=True, exist_ok=True) md_dir.mkdir(parents=True, exist_ok=True)
(md_dir / f"{article_slug}.md").write_text(body_md) (md_dir / f"{article_slug}.md").write_text(body_md)
# Upsert article in SQLite — keyed by (url_path, language) # Upsert article — keyed by (url_path, language).
# Single statement: no SELECT round-trip, no per-row commit.
await db.execute( await db.execute(
"""INSERT INTO articles """INSERT INTO articles
(url_path, slug, title, meta_description, country, region, (url_path, slug, title, meta_description, country, region,
status, published_at, template_slug, language, date_modified, status, published_at, template_slug, language, date_modified,
seo_head, created_at) seo_head, created_at)
VALUES (?, ?, ?, ?, ?, ?, 'published', ?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?, 'published', ?, ?, ?, ?, ?, ?)
ON CONFLICT(url_path, language) DO UPDATE SET ON CONFLICT(url_path, language) DO UPDATE SET
title = excluded.title, title = excluded.title,
meta_description = excluded.meta_description, meta_description = excluded.meta_description,