/
keorlov
/
aichess
Обзор
Документация
Войти
/
keorlov
/
aichess
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/engine_discovery.py
71 строка
2 KB
Konstantin Orlov
wip
06 июн 2026, 13:19
06 июн 2026, 13:19
cb645b7
Код
Авторство
О чём код?
"""Auto-discovery of chess engines from the engines/ directory. Each subdirectory under ``engines_dir`` that contains an ``engine.py`` with a ``choose_move(fen: str) -> str`` callable is treated as a valid engine. Discovery performs only an AST-level check (no execution) so engines with side effects at import time are not run during tournament startup. The match runner will surface real import / call errors when the engine is actually invoked. Returns a dictionary mapping engine name -> absolute file path of engine.py. """ import ast import os from typing import Dict def discover_engines(engines_dir: str) -> Dict[str, str]: """Scan ``engines_dir`` and return {engine_name: engine_file_path}. Engines with broken engine.py files are still included (the match runner handles import failures), but a warning is printed. """ engines: Dict[str, str] = {} if not os.path.isdir(engines_dir): return engines engines_dir = os.path.abspath(engines_dir) for entry in sorted(os.listdir(engines_dir)): engine_path = os.path.join(engines_dir, entry) if not os.path.isdir(engine_path): continue engine_file = os.path.join(engine_path, "engine.py") if not os.path.isfile(engine_file): continue engines[entry] = engine_file _validate_engine_ast(entry, engine_file) return engines def _validate_engine_ast(name: str, engine_file: str): """AST-level check that the engine defines a ``choose_move`` function. No code is executed. If the file is unparseable or doesn't define ``choose_move``, a warning is printed but the engine is still listed — the match runner will surface the real failure when it tries to import the module. """ try: with open(engine_file, "r", encoding="utf-8") as f: source = f.read() tree = ast.parse(source, filename=engine_file) except SyntaxError as e: print(f"Warning: {name} engine.py has a syntax error: {e}") return except OSError as e: print(f"Warning: {name} engine.py could not be read: {e}") return for node in ast.walk(tree): if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)) and node.name == "choose_move": return print(f"Warning: {name} engine.py has no choose_move function")