OC_P8 / database /setup.py
KLEB38's picture
Upload folder using huggingface_hub
ab6d9f6 verified
Raw
History Blame Contribute Delete
3.38 kB
"""CLI utility to create or truncate the prediction log tables.
Usage:
uv run python -m database.setup --create # both prod + test
uv run python -m database.setup --create-test # test table only
uv run python -m database.setup --truncate-test # cleanup CI artefacts
DATABASE_URL is read from the environment (or ``database/.env`` for local
runs). The script is idempotent — re-running ``--create`` is a no-op when
the tables already exist.
"""
from __future__ import annotations
import argparse
import logging
import os
import sys
from pathlib import Path
from sqlalchemy import MetaData, create_engine, text
from database.models import (
PROD_TABLE_NAME,
TEST_TABLE_NAME,
build_predictions_log_table,
)
logger = logging.getLogger("database.setup")
logging.basicConfig(level=logging.INFO, format="%(levelname)s %(name)s %(message)s")
def _load_dotenv_fallback() -> None:
"""Load database/.env if python-dotenv is installed and the file exists."""
env_path = Path(__file__).parent / ".env"
if not env_path.exists():
return
try:
from dotenv import load_dotenv # type: ignore
except ImportError:
logger.warning("python-dotenv not installed; relying on shell env only")
return
load_dotenv(env_path)
def _resolve_database_url(cli_url: str | None) -> str:
if cli_url:
return cli_url
url = os.getenv("DATABASE_URL") or os.getenv("TEST_DATABASE_URL")
if not url:
raise SystemExit(
"DATABASE_URL not set. Export it or pass --database-url. "
"Local devs can populate database/.env."
)
return url
def create_tables(url: str, *, include_prod: bool, include_test: bool) -> None:
engine = create_engine(url)
metadata = MetaData()
if include_prod:
build_predictions_log_table(PROD_TABLE_NAME, metadata)
if include_test:
build_predictions_log_table(TEST_TABLE_NAME, metadata)
metadata.create_all(engine, checkfirst=True)
created = ", ".join(metadata.tables.keys())
logger.info("Tables ensured: %s", created)
def truncate_test(url: str) -> None:
"""Wipe the test table. Hard-coded to TEST_TABLE_NAME — production is never touched."""
engine = create_engine(url)
with engine.begin() as conn:
conn.execute(text(f"TRUNCATE TABLE {TEST_TABLE_NAME} RESTART IDENTITY"))
logger.info("Truncated %s", TEST_TABLE_NAME)
def main(argv: list[str] | None = None) -> int:
_load_dotenv_fallback()
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--database-url", help="Override env DATABASE_URL")
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--create", action="store_true", help="Create both tables")
group.add_argument("--create-test", action="store_true", help="Create test table only")
group.add_argument(
"--truncate-test", action="store_true", help="Empty the test table"
)
args = parser.parse_args(argv)
url = _resolve_database_url(args.database_url)
if args.create:
create_tables(url, include_prod=True, include_test=True)
elif args.create_test:
create_tables(url, include_prod=False, include_test=True)
elif args.truncate_test:
truncate_test(url)
return 0
if __name__ == "__main__":
sys.exit(main())