Files
mil_sdk/mil/core/mil_update_excel.py
feifei.xu f188055228 清理无用代码、合并工具链、修复注释与日志问题
- 删除破损文件: main.py/main.ui/main_ui.py
- 删除 runtime_hook.py(归宿主维护),清除 tools/ 目录
- 合并 export_runtime/pack_zip/verify_companions 到 build_pyd.py
- 修复注释: docstring 参数与实际签名不一致、过时引用、拼写错误
- 修复日志: 消除静默吞异常、删冗余 log+raise、补缺失日志
- 精简 .gitignore
2026-07-21 18:14:34 +08:00

141 lines
5.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""MIL 测试用例 Excel 更新模块
主要功能:
- 比较新旧数据差异
- 添加新信号列或删除旧信号列
"""
import logging
from typing import Any
from .base import SignalData
from .exceptions import CaseDataError
from openpyxl import Workbook
from openpyxl.worksheet.worksheet import Worksheet
logger = logging.getLogger(__name__)
def update_case_excel(filename: str, old_data: dict, new_data: dict) -> None:
"""将旧 Excel 同步到新 Excel 的信号列集合(增 / 删)。
流程:
1. 拆出 wb / sheet / source_row 等元数据;
2. 算 diff:要新增的信号、要删除的信号;
3. 先删后插(保持列号稳定);
4. 回写文件。
Args:
filename: 目标 Excel 文件路径。
old_data: 旧数据字典(含 wb / sheet / source_row 及各信号)。
new_data: 新数据字典(结构同上,用于 diff 比较)。
Raises:
CaseDataError: 旧数据字典中 Workbook/Worksheet 类型不匹配。
"""
logger.info(f"开始更新 Excel 文件 {filename}")
# 注意:pop 会从字典中移除键,调用前请确认数据不再被复用
old_wb = old_data.pop('wb')
old_sheet = old_data.pop('sheet')
old_source_row = old_data.pop('source_row')
new_data.pop('wb')
new_data.pop('sheet')
new_source_row = new_data.pop('source_row')
if not isinstance(old_wb, Workbook) or not isinstance(old_sheet, Worksheet):
raise CaseDataError("数据异常,Workbook 或 Worksheet 类型错误")
# 计算"新增"与"删除"两组信号
add_input = _get_add_input(old_data, new_data)
del_input = _get_del_input(old_data, new_data)
datalog_len = _get_datalog_len(old_data)
# 先删除旧列(逆序删除是为了让被删列的索引不会影响后续操作)
for name, info in reversed(del_input.items()):
old_sheet.delete_cols(info['column'])
logger.info(f"删除第{info['column']}\t信号名: {name}")
# 再插入新增列:先 insert_cols 占位,再填充属性行与数据点
for name, info in add_input.items():
old_sheet.insert_cols(info['column'])
# 1) 属性行(header 行以下至 source_row - 1
for index in range(1, old_source_row):
if index == old_source_row - 1:
# source_header 行:从 attributes 字典里取出 source_header 文本
# 注:attributes 的行号空间与 old_data 保持一致,应使用 old_source_row
old_sheet.cell(index, info['column']).value = info['attributes'][old_source_row - 1]
old_sheet.cell(index, info['column']).data_type = "str"
else:
old_sheet.cell(index, info['column']).value = info['attributes'][index]
old_sheet.cell(index, info['column']).data_type = "str"
# 2) 数据行:根据值类型设置 data_type
for index in range(old_source_row + 1, datalog_len + old_source_row + 1):
try:
value = int(info['datalog'][0].value)
old_sheet.cell(index, info['column']).value = value
old_sheet.cell(index, info['column']).data_type = "int"
except (ValueError, TypeError):
value = str(info['datalog'][0].value)
old_sheet.cell(index, info['column']).value = value
old_sheet.cell(index, info['column']).data_type = "str"
logger.info(f"新增第{info['column']}\t信号名: {name}")
old_wb.save(filename)
logger.info(f"更新 Excel 文件 {filename} 完成")
def _get_add_input(old_data: dict, new_data: dict) -> dict[str, SignalData]:
"""计算"新增"信号集合:存在于 new_data 但不存在于 old_data 的信号。
Args:
old_data: 旧数据字典。
new_data: 新数据字典。
Returns:
新增信号字典。
"""
add_input: dict[str, SignalData] = {}
for name in new_data.keys():
if name not in old_data.keys():
add_input[name] = new_data[name]
return add_input
def _get_del_input(old_data: dict, new_data: dict) -> dict[str, SignalData]:
"""计算"删除"信号集合:存在于 old_data 但不存在于 new_data 的信号。
Args:
old_data: 旧数据字典。
new_data: 新数据字典。
Returns:
删除信号字典。
"""
del_input: dict[str, SignalData] = {}
for name in old_data.keys():
if name not in new_data.keys():
del_input[name] = old_data[name]
return del_input
def _get_datalog_len(old_data: dict) -> int:
"""获取旧数据中第一个信号的 datalog 长度,作为新增列填充行数的基准。
假设 old_data 中各信号 datalog 长度一致(来自同一时间轴)。
Args:
old_data: 旧数据字典。
Returns:
数据日志长度(行数);空字典返回 0。
"""
if not old_data:
return 0
# 取首项的 datalog 长度即可,无需遍历整张字典
first_name = next(iter(old_data))
return len(old_data[first_name]['datalog'])