飞书多维表同步工具2026-07-10v4.1.4
保存路径被覆盖+save_path空值+GUI自动化测试
bug修复v4.1.4
需求描述
v4.1.3修复后API下载仍报错"[WinError 3] 系统找不到指定的路径: ''",且任务编辑面板中看不到保存路径选择入口。深入排查发现两个关键bug:
- 保存路径控件和文件命名设置LabelFrame都grid在row=6,后者覆盖了前者的显示位置
- save_path为空字符串时
task.get("save_path", DEFAULT_SAVE_PATH)返回空字符串(key存在value为空),导致os.makedirs("")报WinError 3
根因分析
- grid row冲突:erp_report_tab.py第1064-1078行,保存路径Label/Entry/Button和naming_frame都grid在row=6。Tkinter grid中同一位置后创建的控件会覆盖先创建的,导致保存路径不可见
- save_path空值处理:lingxing_api_downloader.py第303行
task.get("save_path", DEFAULT_SAVE_PATH),当task中save_path=""(空字符串)时,dict.get返回空字符串而非默认值(因为key存在),os.makedirs("")报错
改动文件清单
| 文件 | 类型 | 改动内容 |
|---|---|---|
tabs/erp_report_tab.py | 修改 | naming_frame从row=6移到row=7,不再覆盖保存路径控件的显示位置 |
erp/lingxing_api_downloader.py | 修改 | save_path读取改为task.get("save_path") or DEFAULT_SAVE_PATH,空字符串/None/缺失都回退到默认值 |
tests/test_erp_dialog_gui.py | 新建 | GUI自动化测试(13个测试):凭据切换模拟、保存路径grid布局验证、导出方式切换完整流程模拟、save_path空值处理、report_type保存正确性 |
gui_sync.py | 修改 | 版本号 4.1.3→4.1.4 |
技术要点
- Tkinter grid同一位置覆盖机制:grid(row=6)中后创建的控件会覆盖先创建的控件。解决方法:确保不同控件使用不同的row编号
- dict.get的默认值陷阱:
dict.get(key, default)只在key不存在时返回default,key存在但value为空字符串时返回空字符串。需要用dict.get(key) or default处理空值 - GUI自动化测试方法:用
tk.Tk()+root.withdraw()创建隐藏窗口,tk.Toplevel()创建模拟对话框,用grid_info()检查控件布局位置,不依赖winfo_ismapped()(withdraw后总是返回0)
验证结果
- 语法检查:3个修改文件全部通过
py_compile - 自动化测试:38个测试全部通过(
python -m unittest tests.test_erp_credential_flow tests.test_erp_dialog_gui -v)- 凭据加载逻辑:5项通过
- 执行器凭据读取:4项通过
- GUI凭据切换:5项通过
- 端到端凭据流:2项通过
- 旧任务兼容性:3项通过
- report_type正确性:6项通过
- GUI对话框凭据切换模拟:3项通过
- GUI保存路径布局验证:2项通过(grid不冲突、Entry被正确放置)
- 导出方式切换完整流程:1项通过(API→Web→API完整切换)
- save_path空值处理:4项通过(空字符串/None/缺失/有值)
- report_type保存正确性:3项通过(id不含中文、name含中文、保存逻辑用id)
踩坑与解决
- winfo_ismapped在withdraw后返回0:测试中用dialog.withdraw()隐藏窗口后,所有控件的winfo_ismapped()都返回0,导致测试失败。解决方法:改用grid_info()检查控件是否被grid放置(检查row字段是否存在),不依赖窗口可见性
- grid覆盖问题:保存路径Label/Entry/Button和naming_frame都grid在row=6,naming_frame是columnspan=3的LabelFrame会完全覆盖整行。解决方法:naming_frame移到row=7
下一阶段规划
- 考虑在on_save中增加save_path空值校验提示("请选择保存路径")
- 考虑API方式下output_mode=feishu_only时save_path可选(不需要本地保存)