Files
commander-ai-lab/routes/import_routes.py
T
87404f3702 refactor: move logging out of routes/shared.py into services/logging.py (#99)
Create services/logging.py as the canonical home for setup_logging(),
all log format constants, named loggers, and _ml_logging_enabled.

Update all route modules and lab_api.py to import logging symbols from
services.logging and all other symbols from their canonical sources
(models.state, models.requests, models.responses, services.database,
services.deck_service, services.scryfall, services.import_helpers,
services.import_service, services.precon_service, services.forge_runner).

Delete routes/shared.py — the re-export hub is no longer needed.

Closes #61

Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 21:04:25 -04:00

124 lines
4.3 KiB
Python

"""
routes/import_routes.py
=======================
Deck import & commander meta endpoints:
POST /api/lab/import/url
POST /api/lab/import/text
GET /api/lab/meta/commanders
GET /api/lab/meta/search
POST /api/lab/meta/fetch
"""
from __future__ import annotations
from typing import Optional
from fastapi import APIRouter, HTTPException, BackgroundTasks
from fastapi.responses import JSONResponse
from models.state import COMMANDER_META
from models.requests import ImportUrlRequest, ImportTextRequest, MetaFetchRequest
from services.import_helpers import (
_import_from_url, _parse_text_decklist, _save_profile_to_dck,
_fetch_edhrec_average,
)
from services.logging import log
router = APIRouter(tags=["import"])
@router.post("/api/lab/import/url")
async def import_from_url(req: ImportUrlRequest):
"""Import a deck from Archidekt or EDHREC URL. Returns parsed DeckProfile + saves .dck file."""
url = req.url.strip()
try:
profile = _import_from_url(url)
dck_path = _save_profile_to_dck(profile)
return {
"success": True,
"deckName": profile["name"],
"commander": profile["commander"],
"source": profile["source"],
"sourceUrl": profile["sourceUrl"],
"totalCards": profile["totalCards"],
"dckFile": dck_path.stem,
"colorIdentity": profile.get("colorIdentity", []),
"archetype": profile.get("archetype"),
}
except Exception as e:
raise HTTPException(400, str(e))
@router.post("/api/lab/import/text")
async def import_from_text(req: ImportTextRequest):
"""Import a deck from plain text card list."""
try:
profile = _parse_text_decklist(req.text, req.commander)
dck_path = _save_profile_to_dck(profile)
return {
"success": True,
"deckName": profile["name"],
"commander": profile["commander"],
"source": "Text Import",
"totalCards": profile["totalCards"],
"dckFile": dck_path.stem,
}
except Exception as e:
raise HTTPException(400, str(e))
@router.get("/api/lab/meta/commanders")
async def list_meta_commanders():
"""List available commanders in the meta mapping."""
commanders = []
for name, entries in COMMANDER_META.items():
entry = entries[0] if entries else {}
commanders.append({
"name": name,
"archetype": entry.get("archetype", ""),
"colorIdentity": entry.get("colorIdentity", []),
"source": entry.get("source", "edhrec"),
})
return {"commanders": commanders}
@router.get("/api/lab/meta/search")
async def search_meta_commanders(q: str = ""):
"""Search commanders by partial name match."""
query = q.lower()
matches = []
for name, entries in COMMANDER_META.items():
if query in name.lower():
entry = entries[0] if entries else {}
matches.append({
"name": name,
"archetype": entry.get("archetype", ""),
"colorIdentity": entry.get("colorIdentity", []),
})
return {"results": matches}
@router.post("/api/lab/meta/fetch")
async def fetch_meta_deck(req: MetaFetchRequest):
"""Fetch EDHREC average deck for a commander and save as .dck file."""
try:
profile = _fetch_edhrec_average(req.commander)
dck_path = _save_profile_to_dck(profile)
return {
"success": True,
"deckName": profile["name"],
"commander": profile["commander"],
"source": "EDHREC Average",
"sourceUrl": profile.get("sourceUrl", ""),
"totalCards": profile["totalCards"],
"dckFile": dck_path.stem,
"colorIdentity": profile.get("colorIdentity", []),
"sampleSize": profile.get("sampleSize"),
}
except Exception as e:
raise HTTPException(400, f"Failed to fetch meta deck for '{req.commander}': {str(e)}")
# ══════════════════════════════════════════════════════════════
# Existing Endpoints (v1/v2)
# ══════════════════════════════════════════════════════════════