mirror of
https://github.com/mwisnowski/mtg_python_deckbuilder.git
synced 2025-12-16 23:50:12 +01:00
fix(lint): improved type checking and code quality (77% error reduction)
This commit is contained in:
parent
3c45a31aa3
commit
83fe527979
37 changed files with 423 additions and 303 deletions
|
|
@ -30,7 +30,7 @@ from ..services.build_utils import (
|
|||
from ..app import templates
|
||||
from deck_builder import builder_constants as bc
|
||||
from ..services import orchestrator as orch
|
||||
from ..services.orchestrator import is_setup_ready as _is_setup_ready, is_setup_stale as _is_setup_stale # type: ignore
|
||||
from ..services.orchestrator import is_setup_ready as _is_setup_ready, is_setup_stale as _is_setup_stale
|
||||
from ..services.build_utils import owned_names as owned_names_helper
|
||||
from ..services.tasks import get_session, new_sid
|
||||
from html import escape as _esc
|
||||
|
|
@ -119,7 +119,7 @@ def _available_cards_normalized() -> tuple[set[str], dict[str, str]]:
|
|||
from deck_builder.include_exclude_utils import normalize_punctuation
|
||||
except Exception:
|
||||
# Fallback: identity normalization
|
||||
def normalize_punctuation(x: str) -> str: # type: ignore
|
||||
def normalize_punctuation(x: str) -> str:
|
||||
return str(x).strip().casefold()
|
||||
norm_map: dict[str, str] = {}
|
||||
for name in names:
|
||||
|
|
@ -470,7 +470,7 @@ def _background_options_from_commander_catalog() -> list[dict[str, Any]]:
|
|||
|
||||
seen: set[str] = set()
|
||||
options: list[dict[str, Any]] = []
|
||||
for record in getattr(catalog, "entries", ()): # type: ignore[attr-defined]
|
||||
for record in getattr(catalog, "entries", ()):
|
||||
if not getattr(record, "is_background", False):
|
||||
continue
|
||||
name = getattr(record, "display_name", None)
|
||||
|
|
@ -2865,7 +2865,7 @@ async def build_step5_rewind(request: Request, to: str = Form(...)) -> HTMLRespo
|
|||
snap = h.get("snapshot")
|
||||
break
|
||||
if snap is not None:
|
||||
orch._restore_builder(ctx["builder"], snap) # type: ignore[attr-defined]
|
||||
orch._restore_builder(ctx["builder"], snap)
|
||||
ctx["idx"] = int(target_i) - 1
|
||||
ctx["last_visible_idx"] = int(target_i) - 1
|
||||
except Exception:
|
||||
|
|
@ -3869,7 +3869,7 @@ async def build_step5_reset_stage(request: Request) -> HTMLResponse:
|
|||
if not ctx or not ctx.get("snapshot"):
|
||||
return await build_step5_get(request)
|
||||
try:
|
||||
orch._restore_builder(ctx["builder"], ctx["snapshot"]) # type: ignore[attr-defined]
|
||||
orch._restore_builder(ctx["builder"], ctx["snapshot"])
|
||||
except Exception:
|
||||
return await build_step5_get(request)
|
||||
# Re-render step 5 with cleared added list
|
||||
|
|
@ -4293,7 +4293,7 @@ async def build_alternatives(
|
|||
try:
|
||||
if rng is not None:
|
||||
return rng.sample(seq, limit) if len(seq) >= limit else list(seq)
|
||||
import random as _rnd # type: ignore
|
||||
import random as _rnd
|
||||
return _rnd.sample(seq, limit) if len(seq) >= limit else list(seq)
|
||||
except Exception:
|
||||
return list(seq[:limit])
|
||||
|
|
@ -4344,7 +4344,7 @@ async def build_alternatives(
|
|||
# Helper: map display names
|
||||
def _display_map_for(lower_pool: set[str]) -> dict[str, str]:
|
||||
try:
|
||||
return builder_display_map(b, lower_pool) # type: ignore[arg-type]
|
||||
return builder_display_map(b, lower_pool)
|
||||
except Exception:
|
||||
return {nm: nm for nm in lower_pool}
|
||||
|
||||
|
|
@ -4522,7 +4522,7 @@ async def build_alternatives(
|
|||
pass
|
||||
# Sort by priority like the builder
|
||||
try:
|
||||
pool = bu.sort_by_priority(pool, ["edhrecRank","manaValue"]) # type: ignore[arg-type]
|
||||
pool = bu.sort_by_priority(pool, ["edhrecRank","manaValue"])
|
||||
except Exception:
|
||||
pass
|
||||
# Exclusions and ownership (for non-random roles this stays before slicing)
|
||||
|
|
@ -5020,13 +5020,13 @@ async def build_compliance_panel(request: Request) -> HTMLResponse:
|
|||
comp = None
|
||||
try:
|
||||
if hasattr(b, 'compute_and_print_compliance'):
|
||||
comp = b.compute_and_print_compliance(base_stem=None) # type: ignore[attr-defined]
|
||||
comp = b.compute_and_print_compliance(base_stem=None)
|
||||
except Exception:
|
||||
comp = None
|
||||
try:
|
||||
if comp:
|
||||
from ..services import orchestrator as orch
|
||||
comp = orch._attach_enforcement_plan(b, comp) # type: ignore[attr-defined]
|
||||
comp = orch._attach_enforcement_plan(b, comp)
|
||||
except Exception:
|
||||
pass
|
||||
if not comp:
|
||||
|
|
@ -5151,11 +5151,11 @@ async def build_enforce_apply(request: Request) -> HTMLResponse:
|
|||
# If missing, export once to establish base
|
||||
if not base_stem:
|
||||
try:
|
||||
ctx["csv_path"] = b.export_decklist_csv() # type: ignore[attr-defined]
|
||||
ctx["csv_path"] = b.export_decklist_csv()
|
||||
import os as _os
|
||||
base_stem = _os.path.splitext(_os.path.basename(ctx["csv_path"]))[0]
|
||||
# Also produce a text export for completeness
|
||||
ctx["txt_path"] = b.export_decklist_text(filename=base_stem + '.txt') # type: ignore[attr-defined]
|
||||
ctx["txt_path"] = b.export_decklist_text(filename=base_stem + '.txt')
|
||||
except Exception:
|
||||
base_stem = None
|
||||
# Add lock placeholders into the library before enforcement so user choices are present
|
||||
|
|
@ -5200,7 +5200,7 @@ async def build_enforce_apply(request: Request) -> HTMLResponse:
|
|||
pass
|
||||
# Run enforcement + re-exports (tops up to 100 internally)
|
||||
try:
|
||||
rep = b.enforce_and_reexport(base_stem=base_stem, mode='auto') # type: ignore[attr-defined]
|
||||
rep = b.enforce_and_reexport(base_stem=base_stem, mode='auto')
|
||||
except Exception as e:
|
||||
err_ctx = step5_error_ctx(request, sess, f"Enforcement failed: {e}")
|
||||
resp = templates.TemplateResponse("build/_step5.html", err_ctx)
|
||||
|
|
@ -5274,13 +5274,13 @@ async def build_enforcement_fullpage(request: Request) -> HTMLResponse:
|
|||
comp = None
|
||||
try:
|
||||
if hasattr(b, 'compute_and_print_compliance'):
|
||||
comp = b.compute_and_print_compliance(base_stem=None) # type: ignore[attr-defined]
|
||||
comp = b.compute_and_print_compliance(base_stem=None)
|
||||
except Exception:
|
||||
comp = None
|
||||
try:
|
||||
if comp:
|
||||
from ..services import orchestrator as orch
|
||||
comp = orch._attach_enforcement_plan(b, comp) # type: ignore[attr-defined]
|
||||
comp = orch._attach_enforcement_plan(b, comp)
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -425,7 +425,7 @@ async def decks_compare(request: Request, A: Optional[str] = None, B: Optional[s
|
|||
mt_val = str(int(mt))
|
||||
except Exception:
|
||||
mt_val = "0"
|
||||
options.append({"name": it.get("name"), "label": label, "mtime": mt_val}) # type: ignore[arg-type]
|
||||
options.append({"name": it.get("name"), "label": label, "mtime": mt_val})
|
||||
|
||||
diffs = None
|
||||
metaA: Dict[str, str] = {}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from pathlib import Path
|
|||
import json as _json
|
||||
from fastapi.responses import HTMLResponse, JSONResponse
|
||||
from ..app import templates
|
||||
from ..services.orchestrator import _ensure_setup_ready # type: ignore
|
||||
from ..services.orchestrator import _ensure_setup_ready
|
||||
|
||||
router = APIRouter(prefix="/setup")
|
||||
|
||||
|
|
@ -21,7 +21,7 @@ def _kickoff_setup_async(force: bool = False):
|
|||
def runner():
|
||||
try:
|
||||
print(f"[SETUP THREAD] Starting setup/tagging (force={force})...")
|
||||
_ensure_setup_ready(print, force=force) # type: ignore[arg-type]
|
||||
_ensure_setup_ready(print, force=force)
|
||||
print("[SETUP THREAD] Setup/tagging completed successfully")
|
||||
except Exception as e: # pragma: no cover - background best effort
|
||||
try:
|
||||
|
|
@ -36,7 +36,7 @@ def _kickoff_setup_async(force: bool = False):
|
|||
|
||||
|
||||
@router.get("/running", response_class=HTMLResponse)
|
||||
async def setup_running(request: Request, start: Optional[int] = 0, next: Optional[str] = None, force: Optional[bool] = None) -> HTMLResponse: # type: ignore[override]
|
||||
async def setup_running(request: Request, start: Optional[int] = 0, next: Optional[str] = None, force: Optional[bool] = None) -> HTMLResponse:
|
||||
# Optionally start the setup/tagging in the background if requested
|
||||
try:
|
||||
if start and int(start) != 0:
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from typing import Optional, Dict, Any
|
|||
|
||||
from fastapi import APIRouter, Request, HTTPException, Query
|
||||
from fastapi import BackgroundTasks
|
||||
from ..services.orchestrator import _ensure_setup_ready, _run_theme_metadata_enrichment # type: ignore
|
||||
from ..services.orchestrator import _ensure_setup_ready, _run_theme_metadata_enrichment
|
||||
from fastapi.responses import JSONResponse, HTMLResponse
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from ..services.theme_catalog_loader import (
|
||||
|
|
@ -17,10 +17,10 @@ from ..services.theme_catalog_loader import (
|
|||
filter_slugs_fast,
|
||||
summaries_for_slugs,
|
||||
)
|
||||
from ..services.theme_preview import get_theme_preview # type: ignore
|
||||
from ..services.theme_catalog_loader import catalog_metrics, prewarm_common_filters # type: ignore
|
||||
from ..services.theme_preview import preview_metrics # type: ignore
|
||||
from ..services import theme_preview as _theme_preview_mod # type: ignore # for error counters
|
||||
from ..services.theme_preview import get_theme_preview
|
||||
from ..services.theme_catalog_loader import catalog_metrics, prewarm_common_filters
|
||||
from ..services.theme_preview import preview_metrics
|
||||
from ..services import theme_preview as _theme_preview_mod # for error counters
|
||||
import os
|
||||
from fastapi import Body
|
||||
|
||||
|
|
@ -36,7 +36,7 @@ router = APIRouter(prefix="/themes", tags=["themes"]) # /themes/status
|
|||
|
||||
# Reuse the main app's template environment so nav globals stay consistent.
|
||||
try: # circular-safe import: app defines templates before importing this router
|
||||
from ..app import templates as _templates # type: ignore
|
||||
from ..app import templates as _templates
|
||||
except Exception: # Fallback (tests/minimal contexts)
|
||||
_templates = Jinja2Templates(directory=str(Path(__file__).resolve().parent.parent / 'templates'))
|
||||
|
||||
|
|
@ -131,7 +131,7 @@ async def theme_suggest(
|
|||
# Optional rate limit using app helper if available
|
||||
rl_result = None
|
||||
try:
|
||||
from ..app import rate_limit_check # type: ignore
|
||||
from ..app import rate_limit_check
|
||||
rl_result = rate_limit_check(request, "suggest")
|
||||
except HTTPException as http_ex: # propagate 429 with headers
|
||||
raise http_ex
|
||||
|
|
@ -231,7 +231,7 @@ async def theme_status():
|
|||
yaml_file_count = 0
|
||||
if yaml_catalog_exists:
|
||||
try:
|
||||
yaml_file_count = len([p for p in CATALOG_DIR.iterdir() if p.suffix == ".yml"]) # type: ignore[arg-type]
|
||||
yaml_file_count = len([p for p in CATALOG_DIR.iterdir() if p.suffix == ".yml"])
|
||||
except Exception:
|
||||
yaml_file_count = -1
|
||||
tagged_time = _load_tag_flag_time()
|
||||
|
|
@ -547,7 +547,7 @@ async def theme_yaml(theme_id: str):
|
|||
raise HTTPException(status_code=404, detail="yaml_not_found")
|
||||
# Reconstruct minimal YAML (we have dict already)
|
||||
import yaml as _yaml # local import to keep top-level lean
|
||||
text = _yaml.safe_dump(y, sort_keys=False) # type: ignore
|
||||
text = _yaml.safe_dump(y, sort_keys=False)
|
||||
headers = {"Content-Type": "text/plain; charset=utf-8"}
|
||||
return HTMLResponse(text, headers=headers)
|
||||
|
||||
|
|
@ -631,7 +631,7 @@ async def api_theme_search(
|
|||
prefix: list[dict[str, Any]] = []
|
||||
substr: list[dict[str, Any]] = []
|
||||
seen: set[str] = set()
|
||||
themes_iter = list(idx.catalog.themes) # type: ignore[attr-defined]
|
||||
themes_iter = list(idx.catalog.themes)
|
||||
# Phase 1 + 2: exact / prefix
|
||||
for t in themes_iter:
|
||||
name = t.theme
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue