mtg_python_deckbuilder/code/scripts/apply_next_theme_editorial.py

79 lines
3.1 KiB
Python

"""Apply example_cards / example_commanders to the next theme missing them.
Usage:
python code/scripts/apply_next_theme_editorial.py
Repeating invocation will fill themes one at a time (skips deprecated alias placeholders).
Options:
--force overwrite existing lists for that theme
--top / --top-commanders size knobs forwarded to suggestion generator
"""
from __future__ import annotations
import argparse
import subprocess
import sys
from pathlib import Path
import yaml # type: ignore
ROOT = Path(__file__).resolve().parents[2]
CATALOG_DIR = ROOT / 'config' / 'themes' / 'catalog'
def find_next_missing():
for path in sorted(CATALOG_DIR.glob('*.yml')):
try:
data = yaml.safe_load(path.read_text(encoding='utf-8'))
except Exception:
continue
if not isinstance(data, dict):
continue
notes = data.get('notes', '')
if isinstance(notes, str) and 'Deprecated alias file' in notes:
continue
# Completion rule: a theme is considered "missing" only if a key itself is absent.
# We intentionally allow empty lists (e.g., obscure themes with no clear commanders)
# so we don't get stuck repeatedly selecting the same file.
if ('example_cards' not in data) or ('example_commanders' not in data):
return data.get('display_name'), path.name
return None, None
def main(): # pragma: no cover
ap = argparse.ArgumentParser(description='Apply editorial examples to next missing theme')
ap.add_argument('--force', action='store_true')
ap.add_argument('--top', type=int, default=8)
ap.add_argument('--top-commanders', type=int, default=5)
args = ap.parse_args()
theme, fname = find_next_missing()
if not theme:
print('All themes already have example_cards & example_commanders (or no YAML).')
return
print(f"Next missing theme: {theme} ({fname})")
cmd = [
sys.executable,
str(ROOT / 'code' / 'scripts' / 'generate_theme_editorial_suggestions.py'),
'--themes', theme,
'--apply', '--limit-yaml', '1',
'--top', str(args.top), '--top-commanders', str(args.top_commanders)
]
if args.force:
cmd.append('--force')
print('Running:', ' '.join(cmd))
subprocess.run(cmd, check=False)
# Post-pass: if we managed to add example_cards but no commanders were inferred, stamp an empty list
# so subsequent runs proceed to the next theme instead of re-processing this one forever.
if fname:
target = CATALOG_DIR / fname
try:
data = yaml.safe_load(target.read_text(encoding='utf-8'))
if isinstance(data, dict) and 'example_cards' in data and 'example_commanders' not in data:
data['example_commanders'] = []
target.write_text(yaml.safe_dump(data, sort_keys=False, allow_unicode=True), encoding='utf-8')
print(f"[post] added empty example_commanders list to {fname} (no suggestions available)")
except Exception as e: # pragma: no cover
print(f"[post-warn] failed to add placeholder commanders for {fname}: {e}")
if __name__ == '__main__':
main()