""" shared.py — fleetfuel · minimal DB + helper utilities. Self-contained (mirrors 16_fleettickets/shared.py) so fleetfuel stands alone. The DB connection comes from DATABASE_URL (points at the shared `tracksolid_db`, where the `fuel` schema lives alongside `tracksolid` / `reporting` / `tickets`). """ from __future__ import annotations import logging import os from contextlib import contextmanager from typing import Any, Optional import psycopg2 def get_logger(name: str) -> logging.Logger: logger = logging.getLogger(f"fleetfuel.{name}") if not logger.handlers: h = logging.StreamHandler() h.setFormatter(logging.Formatter("%(asctime)s [%(levelname)s] %(name)s — %(message)s", datefmt="%Y-%m-%d %H:%M:%S")) logger.addHandler(h) logger.setLevel(os.getenv("LOG_LEVEL", "INFO")) return logger @contextmanager def get_conn(): """DB connection context manager. Auto-commits on success, rolls back on error.""" dsn = os.environ.get("DATABASE_URL") if not dsn: raise RuntimeError("DATABASE_URL is not set") conn = psycopg2.connect(dsn) try: conn.autocommit = False yield conn conn.commit() except Exception: conn.rollback() raise finally: conn.close() def clean(v: Any) -> Optional[str]: """Trimmed string, or None if empty/None.""" if v is None: return None s = str(v).strip() return s if s != "" else None