fix: 3 post-refactor bugs (COMMANDER_META, PRECON_INDEX, startup)

Task 1: Move BUILTIN_COMMANDERS + load_commander_meta() to shared.py
        Fix import_routes.py to use _shared.COMMANDER_META (module ref)
Task 2: Rewrite precon.py to use _shared.PRECON_INDEX (module ref)
Task 3: Add @app.on_event('startup') safety net for uvicorn --reload
This commit is contained in:
KoalaTrapLord committed 2026-03-14 19:08:21 +00:00
1 parent 36077c94ab
commit 8a6fbfaa8a
4 files changed
+55 -49

No files matched your search

+15 -38
View File
@@ -99,6 +99,8 @@ from routes.shared import (
# EDHREC cache
_edhrec_cache, _EDHREC_CACHE_TTL,
_edhrec_cache_get, _edhrec_cache_set,
# Commander meta
load_commander_meta, BUILTIN_COMMANDERS,
)
# Route modules
@@ -151,6 +153,18 @@ app.include_router(import_router)
app.include_router(lab_router)
@app.on_event("startup")
async def _on_startup():
"""Safety net: ensure DB and precon index are initialized even when
main() is bypassed (e.g. uvicorn lab_api:app --reload)."""
import routes.shared as _shared
_shared.init_collection_db()
if not _shared.PRECON_INDEX:
_shared.download_precon_database()
if not _shared.COMMANDER_META:
_shared.load_commander_meta()
# ══════════════════════════════════════════════════════════════
# In-Memory State (used by remaining endpoints)
# ══════════════════════════════════════════════════════════════
@@ -619,29 +633,6 @@ async def get_card_edhrec(cardId: int):
return result
# ══════════════════════════════════════════════════════════════
# Commander Meta Mapping (loaded at startup)
# ══════════════════════════════════════════════════════════════
BUILTIN_COMMANDERS = {
"Edgar Markov": [{"source": "edhrec", "archetype": "aggro", "colorIdentity": ["W","B","R"]}],
"Atraxa, Praetors' Voice": [{"source": "edhrec", "archetype": "midrange", "colorIdentity": ["W","U","B","G"]}],
"Korvold, Fae-Cursed King": [{"source": "edhrec", "archetype": "combo", "colorIdentity": ["B","R","G"]}],
"Muldrotha, the Gravetide": [{"source": "edhrec", "archetype": "midrange", "colorIdentity": ["U","B","G"]}],
"The Ur-Dragon": [{"source": "edhrec", "archetype": "midrange", "colorIdentity": ["W","U","B","R","G"]}],
"Yuriko, the Tiger's Shadow": [{"source": "edhrec", "archetype": "aggro", "colorIdentity": ["U","B"]}],
"Krenko, Mob Boss": [{"source": "edhrec", "archetype": "aggro", "colorIdentity": ["R"]}],
"Meren of Clan Nel Toth": [{"source": "edhrec", "archetype": "midrange", "colorIdentity": ["B","G"]}],
"Prossh, Skyraider of Kher": [{"source": "edhrec", "archetype": "combo", "colorIdentity": ["B","R","G"]}],
"Kaalia of the Vast": [{"source": "edhrec", "archetype": "aggro", "colorIdentity": ["W","B","R"]}],
"Talrand, Sky Summoner": [{"source": "edhrec", "archetype": "control", "colorIdentity": ["U"]}],
"Omnath, Locus of Creation": [{"source": "edhrec", "archetype": "combo", "colorIdentity": ["W","U","R","G"]}],
"Teysa Karlov": [{"source": "edhrec", "archetype": "combo", "colorIdentity": ["W","B"]}],
"Lathril, Blade of the Elves": [{"source": "edhrec", "archetype": "aggro", "colorIdentity": ["B","G"]}],
"Breya, Etherium Shaper": [{"source": "edhrec", "archetype": "combo", "colorIdentity": ["W","U","B","R"]}],
}
# ══════════════════════════════════════════════════════════════
# Python Simulator API
# ══════════════════════════════════════════════════════════════
@@ -4405,21 +4396,7 @@ def resolve_forge_decks_dir() -> str:
return ""
def load_commander_meta():
"""Load commander meta mapping from file or use builtins."""
global COMMANDER_META
meta_path = Path(__file__).parent / "commander-meta.json"
if meta_path.exists():
try:
with open(meta_path, "r", encoding="utf-8") as f:
COMMANDER_META = json.load(f)
log.info(f" Meta: Loaded {len(COMMANDER_META)} commanders from {meta_path}")
return
except Exception as e:
log.warning(f" WARNING: Failed to load commander-meta.json: {e}")
COMMANDER_META = BUILTIN_COMMANDERS
log.info(f" Meta: {len(COMMANDER_META)} built-in commanders")
# load_commander_meta() is now in routes/shared.py
def main():
+3 -3
View File
@@ -15,8 +15,8 @@ from typing import Optional
from fastapi import APIRouter, HTTPException, BackgroundTasks
from fastapi.responses import JSONResponse
import routes.shared as _shared
from routes.shared import (
COMMANDER_META,
ImportUrlRequest,
ImportTextRequest,
MetaFetchRequest,
@@ -74,7 +74,7 @@ async def import_from_text(req: ImportTextRequest):
async def list_meta_commanders():
"""List available commanders in the meta mapping."""
commanders = []
for name, entries in COMMANDER_META.items():
for name, entries in _shared.COMMANDER_META.items():
entry = entries[0] if entries else {}
commanders.append({
"name": name,
@@ -90,7 +90,7 @@ async def search_meta_commanders(q: str = ""):
"""Search commanders by partial name match."""
query = q.lower()
matches = []
for name, entries in COMMANDER_META.items():
for name, entries in _shared.COMMANDER_META.items():
if query in name.lower():
entry = entries[0] if entries else {}
matches.append({
+3 -8
View File
@@ -15,13 +15,8 @@ from pathlib import Path
from fastapi import APIRouter, HTTPException
from routes.shared import (
CFG,
PRECON_INDEX,
PRECON_DIR,
download_precon_database,
log,
)
import routes.shared as _shared # module reference, not value import
from routes.shared import CFG, PRECON_DIR, download_precon_database, log
router = APIRouter(tags=["precon"])
@@ -29,7 +24,7 @@ router = APIRouter(tags=["precon"])
@router.get("/api/lab/precons")
async def list_precons():
"""List all available precon decks."""
return {"precons": PRECON_INDEX}
return {"precons": _shared.PRECON_INDEX} # reads current value every call
@router.post("/api/lab/precons/install")
+34
View File
@@ -148,6 +148,40 @@ class BatchState:
active_batches: dict[str, BatchState] = {}
COMMANDER_META: dict = {}
BUILTIN_COMMANDERS: dict = {
"Edgar Markov": [{"source": "edhrec", "archetype": "aggro", "colorIdentity": ["W","B","R"]}],
"Atraxa, Praetors' Voice": [{"source": "edhrec", "archetype": "midrange", "colorIdentity": ["W","U","B","G"]}],
"Korvold, Fae-Cursed King": [{"source": "edhrec", "archetype": "combo", "colorIdentity": ["B","R","G"]}],
"Muldrotha, the Gravetide": [{"source": "edhrec", "archetype": "midrange", "colorIdentity": ["U","B","G"]}],
"The Ur-Dragon": [{"source": "edhrec", "archetype": "midrange", "colorIdentity": ["W","U","B","R","G"]}],
"Yuriko, the Tiger's Shadow": [{"source": "edhrec", "archetype": "aggro", "colorIdentity": ["U","B"]}],
"Krenko, Mob Boss": [{"source": "edhrec", "archetype": "aggro", "colorIdentity": ["R"]}],
"Meren of Clan Nel Toth": [{"source": "edhrec", "archetype": "midrange", "colorIdentity": ["B","G"]}],
"Prossh, Skyraider of Kher": [{"source": "edhrec", "archetype": "combo", "colorIdentity": ["B","R","G"]}],
"Kaalia of the Vast": [{"source": "edhrec", "archetype": "aggro", "colorIdentity": ["W","B","R"]}],
"Talrand, Sky Summoner": [{"source": "edhrec", "archetype": "control", "colorIdentity": ["U"]}],
"Omnath, Locus of Creation": [{"source": "edhrec", "archetype": "combo", "colorIdentity": ["W","U","R","G"]}],
"Teysa Karlov": [{"source": "edhrec", "archetype": "combo", "colorIdentity": ["W","B"]}],
"Lathril, Blade of the Elves": [{"source": "edhrec", "archetype": "aggro", "colorIdentity": ["B","G"]}],
"Breya, Etherium Shaper": [{"source": "edhrec", "archetype": "combo", "colorIdentity": ["W","U","B","R"]}],
}
def load_commander_meta() -> None:
"""Load commander meta mapping from file or fall back to builtins."""
global COMMANDER_META
meta_path = Path(__file__).parent.parent / "commander-meta.json"
if meta_path.exists():
try:
with open(meta_path, "r", encoding="utf-8") as f:
COMMANDER_META = json.load(f)
log.info(f" Meta: Loaded {len(COMMANDER_META)} commanders from {meta_path}")
return
except Exception as e:
log.warning(f" WARNING: Failed to load commander-meta.json: {e}")
COMMANDER_META = BUILTIN_COMMANDERS
log.info(f" Meta: {len(COMMANDER_META)} built-in commanders")
# ══════════════════════════════════════════════════════════════
# Pydantic Models