#!/usr/bin/env python3 """Bootstrap da fundação de dados: baixa o ano corrente inteiro da Apoena. Meses fechados (jan..mes_atual-1) -> pivot__. Mês corrente -> current_ (swap atômico). Uso: ./scripts/bootstrap_extract.py # ano corrente ./scripts/bootstrap_extract.py --year 2026 --months 1-6 """ from __future__ import annotations import argparse import logging import os import sys from datetime import datetime from pathlib import Path from zoneinfo import ZoneInfo ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT)) BRT = ZoneInfo("America/Sao_Paulo") logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s", datefmt="%H:%M:%S") log = logging.getLogger("bootstrap_extract") def load_env_local(path: Path) -> None: if not path.exists(): return for line in path.read_text().splitlines(): line = line.strip() if not line or line.startswith("#") or "=" not in line: continue k, v = line.split("=", 1) os.environ.setdefault(k.strip(), v.strip().strip('"').strip("'")) def main() -> int: load_env_local(ROOT / ".env.local") # importa só depois de carregar env (extractor lê REPORT_BASE no import-time) import duckdb from dashboard_apn.extractor import F2MExtractor, PIVOT_BASES now = datetime.now(BRT) p = argparse.ArgumentParser() p.add_argument("--db", default=os.environ.get("F2M_DB_PATH", str(ROOT / "f2m_local.duckdb"))) p.add_argument("--year", type=int, default=now.year) p.add_argument("--months", help="Ex: 1-6 (default: jan..mes_atual)") args = p.parse_args() db_path = Path(args.db) email = os.environ.get("F2M_EMAIL", "") password = os.environ.get("F2M_PASSWORD", "") if not email or not password: log.error("F2M_EMAIL/F2M_PASSWORD ausentes") return 1 mes_atual = now.month if args.year == now.year else 12 if args.months: a, b = (args.months.split("-", 1) + [None])[:2] months = list(range(int(a), int(b) + 1)) if b else [int(a)] else: months = list(range(1, mes_atual + 1)) log.info("Bases: %s", list(PIVOT_BASES.values())) log.info("DB: %s | ano=%d | meses=%s | mes_corrente=%d", db_path, args.year, months, mes_atual) # cria DB vazio se não existir duckdb.connect(str(db_path)).close() ex = F2MExtractor(str(db_path), email, password) for mes in months: if args.year == now.year and mes == mes_atual: log.info("Mês corrente %02d -> current_*", mes) ex.extract_current_month() else: log.info("Mês fechado %02d -> pivot_*_%02d", mes, mes) ex.extract_month(args.year, mes, year_prefix=(args.year != now.year)) # relatório de contagens con = duckdb.connect(str(db_path), read_only=True) try: tables = sorted(r[0] for r in con.execute("SHOW TABLES").fetchall()) log.info("=== Tabelas (%d) ===", len(tables)) for t in tables: n = con.execute(f'SELECT COUNT(*) FROM "{t}"').fetchone()[0] log.info(" %-40s %8d", t, n) finally: con.close() return 0 if __name__ == "__main__": raise SystemExit(main())