""" FastAPI entrypoint for the Scouting · Racing Santander Space. """ import os import warnings from pathlib import Path # Cosmetic: pandas PerformanceWarning when scoring 10k+ row dfs (we add columns # one-by-one — copies the frame internally; cost is a few ms per request). warnings.filterwarnings('ignore', category=Warning, module='pandas') warnings.filterwarnings('ignore', message='.*highly fragmented.*') from fastapi import FastAPI, Request from fastapi.responses import FileResponse, JSONResponse from fastapi.staticfiles import StaticFiles from auth import AuthMiddleware, register_auth_routes from data import bootstrap_data, get_meta from routes.meta import router as meta_router from routes.rows import router as rows_router from routes.player import router as player_router APP_DIR = Path(__file__).parent STATIC_DIR = APP_DIR / 'static' app = FastAPI(title='Scouting · Racing Santander', docs_url='/api/docs', redoc_url=None) # Bootstrap data (HF download if needed) before serving requests. bootstrap_data() # Auth — wraps everything except /api/login and the static index page (it shows the login form itself). app.add_middleware(AuthMiddleware) register_auth_routes(app) app.include_router(meta_router, prefix='/api') app.include_router(rows_router, prefix='/api') app.include_router(player_router, prefix='/api') @app.get('/healthz') def healthz(): meta = get_meta() return {'ok': True, 'players': meta['n_players'], 'leagues': len(meta['leagues'])} # Static assets (CSS, JS, images) app.mount('/static', StaticFiles(directory=STATIC_DIR), name='static') @app.get('/') def index(): return FileResponse(STATIC_DIR / 'index.html') @app.exception_handler(401) async def unauthorized_handler(request: Request, exc): # for HTML routes return the index (frontend renders the login modal on 401 fetch) if request.url.path == '/' or request.url.path.startswith('/static'): return FileResponse(STATIC_DIR / 'index.html') return JSONResponse(status_code=401, content={'detail': 'unauthorized'})