""" MT5 路径占位符解析(不做任何自动探测)。 支持占位符: {PROJECT_ROOT} 项目根目录绝对路径 {APP_DATA_DIR} %APPDATA% (C:\\Users\\\\AppData\\Roaming) ${APPDATA} 同上 (POSIX 风格) ${USERPROFILE} C:\\Users\\ 留空的路径会原样返回,由调用方/用户决定。 """ import os from typing import Optional PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) def _expand_placeholders(value: str, project_root: str) -> str: if not value: return value expanded = ( value .replace("{PROJECT_ROOT}", project_root) .replace("{APP_DATA_DIR}", os.environ.get("APPDATA", "")) .replace("${APPDATA}", os.environ.get("APPDATA", "")) .replace("${USERPROFILE}", os.environ.get("USERPROFILE", "")) ) if "{" in expanded and "}" in expanded: return expanded return os.path.normpath(expanded) def resolve_mt5_settings(mt5_settings: dict, project_root: Optional[str] = None) -> dict: """只做 {PROJECT_ROOT} 等占位符替换;空值原样保留,不做任何自动探测。""" if project_root is None: project_root = PROJECT_ROOT resolved = dict(mt5_settings) for key, default_sub in (("ini_dir", os.path.join("config", "generated")), ("reports_dir", "reports")): v = resolved.get(key, "") if not v: resolved[key] = os.path.join(project_root, default_sub) else: expanded = _expand_placeholders(v, project_root) if expanded and (os.path.isabs(expanded) or "{" not in expanded): resolved[key] = expanded else: resolved[key] = os.path.join(project_root, expanded) return resolved if __name__ == "__main__": import pprint sample = { "terminal_path": "", "data_dir": "", "ini_dir": "{PROJECT_ROOT}/config/generated", "reports_dir": "{PROJECT_ROOT}/reports", } pprint.pp(resolve_mt5_settings(sample))