"""路径管理模块。 提供程序根目录和关键资源路径的计算逻辑,处理以下场景: - 正常 Python 运行(通过 __file__ 定位) - PyInstaller/Nuitka 单文件打包(通过 __compiled__ 信息定位) - PyInstaller 冻结目录模式(通过 sys.frozen / sys.executable 定位) """ from __future__ import annotations import sys from pathlib import Path # 应用程序包目录名 APP_DIR_NAME = "a1_swap_mod_packer" # 换板 G-code 文件的默认子目录名 SWAP_GCODE_DIR_NAME = "swap_gcode" # G-code 补丁配置文件名 PATCH_CONFIG_FILE_NAME = "gcode_patches.ini" def program_root() -> Path: """返回程序根目录的绝对路径。 根据运行环境自动选择定位策略: - Nuitka 编译的单文件:通过 __compiled__.containing_dir 获取。 - Nuitka 但无 containing_dir:通过 __compiled__.original_argv0 推算。 - PyInstaller 冻结模式:通过 sys.executable 所在目录获取。 - 正常 Python 运行:基于本模块文件路径向上两级推算。 Returns: Path: 程序根目录的绝对路径。 """ # Nuitka 编译标记,单文件模式下需特殊处理 compiled = globals().get("__compiled__") if compiled is not None and getattr(compiled, "onefile", False): # Nuitka 提供的包含目录 containing_dir = getattr(compiled, "containing_dir", None) if containing_dir: return Path(containing_dir).resolve() # 回退:通过原始可执行文件路径推算 original_argv0 = getattr(compiled, "original_argv0", None) if original_argv0: return Path(original_argv0).resolve().parent # PyInstaller 冻结模式 if getattr(sys, "frozen", False): return Path(sys.executable).resolve().parent # 正常 Python 解释器运行:向上两级回到项目根目录 return Path(__file__).resolve().parents[1] def default_swap_gcode_dir() -> Path: """返回换板 G-code 文件的默认存放目录。 Returns: Path: 程序根目录下的 swap_gcode 子目录。 """ return program_root() / SWAP_GCODE_DIR_NAME def default_patch_config_path() -> Path: """返回 G-code 补丁配置文件的默认路径。 Returns: Path: 程序根目录下的 gcode_patches.ini 文件路径。 """ return program_root() / PATCH_CONFIG_FILE_NAME def user_settings_path() -> Path: """返回用户设置文件的路径。 Returns: Path: 程序根目录下的 settings.json 文件路径。 """ return program_root() / "settings.json"