""" web/app.py — FastAPI application factory. Usage: from web.app import create_app app = create_app() uvicorn.run(app, host=host, port=port) The app is created fresh per uvicorn startup (no module-level state). Templates and static files are mounted from web/templates/ and web/static/. """ from contextlib import asynccontextmanager from pathlib import Path import jinja2 from fastapi import FastAPI from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates from web import db as webdb from web.routes import auth, dashboard, config_routes, users _WEB_DIR = Path(__file__).parent @asynccontextmanager async def _lifespan(app: FastAPI): webdb.init_db() yield def create_app() -> FastAPI: app = FastAPI(title="ULPgrammer", lifespan=_lifespan) # Use a custom Environment with caching disabled. # Jinja2's LRUCache has a Python 3.14 hashability issue with its cache key; # cache_size=0 disables the LRUCache code path entirely. _env = jinja2.Environment( loader=jinja2.FileSystemLoader(str(_WEB_DIR / "templates")), autoescape=jinja2.select_autoescape(), cache_size=0, ) app.state.templates = Jinja2Templates(env=_env) # Static files app.mount("/static", StaticFiles(directory=str(_WEB_DIR / "static")), name="static") # Routers app.include_router(auth.router) app.include_router(dashboard.router) app.include_router(config_routes.router) app.include_router(users.router) return app