refactor: 重构所有面板 update_from_config 为文件系统扫描模式
=== 核心变更 ===
- _step_path_resolver 新增 scan_work_dir_for_input() 统一文件扫描工具
- 基于 _SCAN_TABLE 映射表,按 output_type 自动扫描 work_dir 子目录
- 支持扩展名匹配(.dat/.tif/.bsq/.csv 等)和文件名关键词匹配
- 按 mtime 排序,返回最新匹配文件
=== 各面板重构 ===
- step2/3/4/6: 废弃 main_window.stepX_panel 跨面板读取
统一改为 scan_work_dir_for_input(work_dir, 'water_mask/glint_mask/deglint_image')
- step6: 移除对 step1/2/3/5 panel 的4处跨面板依赖
- step8: 替换 _resolve_training_csv_from_workdir 为 scan_work_dir_for_input
优先级:training_spectra_indices -> training_spectra
- step9: 替换 _resolve_latest_wqi_test_csv 为 scan_work_dir_for_input
废弃 factory.get_panel('step4_sampling') 和 get_panel('step8_ml_train')
- step10: 替换3层回退链为 scan_work_dir_for_input('sampling_points')
- step11: 替换 factory.get_panel('step9')/('step1') 为文件扫描
=== 删除的冗余方法 ===
- step8._resolve_training_csv_from_workdir (~55行)
- step9._resolve_latest_wqi_test_csv (~56行)
=== 数据流原则 ===
1. pipeline context 为第一顺位(执行时内存状态)
2. 文件系统扫描为回退(仅信任硬盘上真实存在的文件)
3. 彻底禁止面板间 UI 控件互相读取
This commit is contained in:
@ -183,9 +183,91 @@ def resolve_subdir(work_dir, subdir_key: str) -> str:
|
||||
return wd
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# 文件系统扫描表 —— 定义每个上游产出类型对应的搜索策略
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
_SCAN_TABLE = {
|
||||
# output_type → (subdir_key, extensions, file_name_matcher)
|
||||
'water_mask': ('water_mask', ['.dat', '.tif', '.tiff'], None),
|
||||
'glint_mask': ('glint_detection', ['.dat'], 'severe_glint'),
|
||||
'deglint_image': ('deglint', ['.bsq', '.dat', '.tif', '.tiff'], None),
|
||||
'sampling_points': ('sampling', ['.csv'], 'sampling_spectra'),
|
||||
'processed_data': ('data_cleaning', ['.csv'], 'processed_data'),
|
||||
'training_spectra': ('spectral_feature',['.csv'], 'training_spectra'),
|
||||
'training_spectra_indices': ('indices', ['.csv'], 'training_spectra_indices'),
|
||||
'ml_models_dir': ('supervised_models', None, None), # 目录
|
||||
'ml_predictions_dir': ('ml_prediction', None, None), # 目录
|
||||
'water_index_csv_dir': ('watercolor', None, None), # 目录
|
||||
'visualization_dir': ('visualization', None, None), # 目录
|
||||
'reference_img': ('water_mask', ['.bsq', '.dat', '.tif', '.tiff'], None),
|
||||
}
|
||||
|
||||
|
||||
def scan_work_dir_for_input(work_dir: str, output_type: str):
|
||||
"""基于文件系统扫描查找上游步骤的产出文件。
|
||||
|
||||
这是 update_from_config 重构的核心工具函数。
|
||||
仅信任硬盘上真实存在的文件,彻底消除面板间 UI 控件互相读取。
|
||||
|
||||
Args:
|
||||
work_dir: 工作目录路径
|
||||
output_type: 产出类型,如 'water_mask', 'deglint_image', 'sampling_points'
|
||||
|
||||
Returns:
|
||||
找到的文件/目录绝对路径字符串,未找到返回 None
|
||||
"""
|
||||
if not work_dir:
|
||||
return None
|
||||
|
||||
wd = Path(work_dir)
|
||||
entry = _SCAN_TABLE.get(output_type)
|
||||
if entry is None:
|
||||
return None
|
||||
|
||||
subdir_key, extensions, matcher = entry
|
||||
target_dir = wd / _FALLBACK_DIR_TABLE.get(subdir_key, subdir_key)
|
||||
if not target_dir.is_dir():
|
||||
return None
|
||||
|
||||
# 目录类型(extensions 为 None)→ 只要目录存在就返回
|
||||
if extensions is None:
|
||||
return str(target_dir).replace('\\', '/')
|
||||
|
||||
# 扫描目录中的文件
|
||||
candidates = []
|
||||
for ext in extensions:
|
||||
for f in target_dir.glob(f'*{ext}'):
|
||||
if not f.is_file():
|
||||
continue
|
||||
candidates.append(f)
|
||||
# 也搜 ext 的大写变体
|
||||
for f in target_dir.glob(f'*{ext.upper()}'):
|
||||
if not f.is_file():
|
||||
continue
|
||||
candidates.append(f)
|
||||
|
||||
if not candidates:
|
||||
return None
|
||||
|
||||
# 按 matcher 优先级 + mtime 排序
|
||||
if matcher:
|
||||
matched = [f for f in candidates if matcher.lower() in f.stem.lower()]
|
||||
if matched:
|
||||
matched.sort(key=lambda p: p.stat().st_mtime, reverse=True)
|
||||
return str(matched[0]).replace('\\', '/')
|
||||
# matcher 未命中时,仍返回最新文件(宽松匹配)
|
||||
candidates.sort(key=lambda p: p.stat().st_mtime, reverse=True)
|
||||
return str(candidates[0]).replace('\\', '/')
|
||||
|
||||
# 无 matcher → 返回最新的
|
||||
candidates.sort(key=lambda p: p.stat().st_mtime, reverse=True)
|
||||
return str(candidates[0]).replace('\\', '/')
|
||||
|
||||
|
||||
__all__ = [
|
||||
'STEP_DATA_SOURCE',
|
||||
'resolve_step_widget',
|
||||
'get_step_output_path',
|
||||
'resolve_subdir',
|
||||
'scan_work_dir_for_input',
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user