import os import sys # 尝试导入 toml 解析库 try: import tomllib as toml # Python 3.11+ except ImportError: try: import tomli as toml # pip install tomli except ImportError: print("错误: 缺少 TOML 解析库。请运行: pip install tomli") sys.exit(1) def get_base_dir(): """ 获取程序运行的基准目录 (即 EXE 所在的目录 或 开发环境的项目根目录) 用于确定 output_folder 等需要写入的路径。 """ if getattr(sys, 'frozen', False): # 打包环境: EXE 所在目录 return os.path.dirname(sys.executable) else: # 开发环境: 项目根目录 (假设此脚本在 utils/ 文件夹中,需要向上两级) return os.path.dirname(os.path.dirname(os.path.abspath(__file__))) def get_resource_path(relative_path): """ 智能路径获取: 1. 优先检查 EXE 旁边是否有该文件 (外部资源)。 2. 如果没有,则使用 EXE 内部打包的资源 (内部资源)。 """ # 1. 获取外部基准路径 base_path = get_base_dir() # 拼接外部路径 external_path = os.path.join(base_path, relative_path) # 如果外部文件存在,直接返回 (优先使用用户修改过的文件) if os.path.exists(external_path): return external_path # 2. 如果外部不存在,且处于打包环境,则回退到内部临时目录 (sys._MEIPASS) if getattr(sys, 'frozen', False): # sys._MEIPASS 是 PyInstaller 解压临时文件的目录 internal_path = os.path.join(sys._MEIPASS, relative_path) if os.path.exists(internal_path): return internal_path # 3. 默认返回外部路径 # (如果都没找到,让报错信息指向外部路径,提示用户文件缺失) return external_path # ========================================== # 1. 配置加载 (Config Loader) # ========================================== def load_config(config_filename="config.toml"): """读取 TOML 配置文件""" # 1. 智能获取配置文件路径 # (优先找 EXE 旁边的 config.toml,找不到则用打包在里面的) config_path = get_resource_path(config_filename) if not os.path.exists(config_path): print(f"错误: 找不到配置文件 {config_filename}") print(f"尝试寻找的路径是: {config_path}") # 如果是打包环境,提示用户可能需要把 config.toml 复制出来 if getattr(sys, 'frozen', False): print("提示: 请确保 config.toml 位于程序同级目录下,或已正确打包。") sys.exit(1) try: with open(config_path, "rb") as f: data = toml.load(f) # 获取基准目录(用于 output_folder) base_dir = get_base_dir() # 将 TOML 的层级结构映射回扁平结构 # ⚠️ 注意: # - 读取类文件 (模板, Excel, 图片, 字体) 使用 get_resource_path (支持内外回退) # - 写入类文件夹 (output_folder) 使用 os.path.join(base_dir, ...) (必须在外部) config = { "root_path": base_dir, # --- 资源文件 (使用智能路径) --- # 假设 config.toml 里写的是 "report_template.pptx",文件在 templates 文件夹下 "source_file": get_resource_path( os.path.join("templates", data["paths"]["source_file"]) ), # 假设 config.toml 里写的是 "names.xlsx",文件在 data 文件夹下 # 如果 config.toml 里写的是 "data/names.xlsx",则不需要 os.path.join("data", ...) "excel_file": get_resource_path( os.path.join("data", data["paths"]["excel_file"]) ), "image_folder": get_resource_path( os.path.join("data", data["paths"]["image_folder"]) ), "fonts_dir": get_resource_path( os.path.join(data["paths"]["fonts_dir"]) ), # --- 输出文件夹 (必须强制在外部,不能指向临时目录) --- "output_folder": os.path.join(base_dir, data["paths"]["output_folder"]), # --- 其他配置 --- "class_name": data["class_info"]["class_name"], "teachers": data["class_info"]["teachers"], "default_comment": data["defaults"].get("default_comment", "暂无评语"), "age_group": data["defaults"].get("age_group", "大班上学期"), "ai": data["ai"], } return config except KeyError as e: print(f"配置文件格式错误,缺少键值: {e}") sys.exit(1) except Exception as e: print(f"读取配置文件出错: {e}") import traceback traceback.print_exc() sys.exit(1)