清理无用代码、合并工具链、修复注释与日志问题
- 删除破损文件: main.py/main.ui/main_ui.py - 删除 runtime_hook.py(归宿主维护),清除 tools/ 目录 - 合并 export_runtime/pack_zip/verify_companions 到 build_pyd.py - 修复注释: docstring 参数与实际签名不一致、过时引用、拼写错误 - 修复日志: 消除静默吞异常、删冗余 log+raise、补缺失日志 - 精简 .gitignore
This commit is contained in:
+2
-2
@@ -9,13 +9,13 @@ NMAE = "MIL Tool"
|
||||
# 工具版本
|
||||
__MAJOR_VER: int = 0 # 主版本号
|
||||
__MINOR_VER: int = 0 # 次版本号
|
||||
__MICRO_VER: int = 4 # 修订版本号
|
||||
__MICRO_VER: int = 6 # 修订版本号
|
||||
|
||||
VERSION:str = f"{__MAJOR_VER}.{__MINOR_VER}.{__MICRO_VER}"
|
||||
|
||||
# 工具描述
|
||||
DESCRIPITION = """
|
||||
主要用于生成Simlink Test Case。
|
||||
主要用于生成Simulink Test Case。
|
||||
"""
|
||||
|
||||
SVG = """
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
提供 MIL 仿真数据读取功能
|
||||
|
||||
使用示例:
|
||||
from src.core import read_excel_data
|
||||
from mil.core import read_excel_data
|
||||
|
||||
result = read_excel_data("simulation.xlsx")
|
||||
"""
|
||||
|
||||
+7
-25
@@ -16,7 +16,8 @@ class Config():
|
||||
配置传输载体。序列化使用 JSON 文件持久化。
|
||||
|
||||
Attributes:
|
||||
DataPath: 仿真数据目录(Excel 原始文件所在路径)
|
||||
path: 配置文件路径(JSON 文件)
|
||||
DataPath: 仿真数据目录
|
||||
FilePath: 当前打开的 Excel 文件路径
|
||||
AddTimeEn: 用例步骤时间是否按累加方式记录
|
||||
GeratePath: 是否为生成的用例另存新文件
|
||||
@@ -47,16 +48,13 @@ class Config():
|
||||
}
|
||||
|
||||
def load_config(self) -> "Config":
|
||||
"""从 JSON 文件读取配置并填充到当前实例的各个字段。
|
||||
"""从 self.path 指定的 JSON 文件读取配置并填充到当前实例的各个字段。
|
||||
|
||||
解析规则:
|
||||
- JSON 中存在的字段会被回写到 Config 的对应字段;
|
||||
- JSON 中缺失的字段保持当前 Config 实例的默认值;
|
||||
- JSON 中多余字段被忽略(向前兼容:增加字段不会破坏老配置)。
|
||||
|
||||
Args:
|
||||
config_path: 配置文件路径。
|
||||
|
||||
Returns:
|
||||
self:填充后的 Config 实例,便于链式调用。
|
||||
|
||||
@@ -85,10 +83,7 @@ class Config():
|
||||
return self
|
||||
|
||||
def save_config(self):
|
||||
"""将当前配置以 JSON 格式写入磁盘。
|
||||
|
||||
Args:
|
||||
config_path: 配置文件路径。
|
||||
"""将当前配置以 JSON 格式写入 self.path 指定的文件。
|
||||
|
||||
Raises:
|
||||
Exception: 写入失败时记录日志并原样抛出异常。
|
||||
@@ -97,7 +92,8 @@ class Config():
|
||||
with open(self.path,'w',encoding='utf-8') as f:
|
||||
json.dump(self.to_dict(), f, indent=4, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
logger.error(f"配置文件{self.path}写入失败{e.args}")
|
||||
logger.error(f"配置文件{self.path}写入失败: {e}")
|
||||
raise
|
||||
|
||||
@dataclass
|
||||
class DataLog:
|
||||
@@ -105,7 +101,7 @@ class DataLog:
|
||||
|
||||
Attributes:
|
||||
time: 时间戳(秒)
|
||||
value: 信号值(可以是任意类型)
|
||||
value: 信号值(字符串形式,写入 Excel 时按内容推断 int/str 类型)
|
||||
"""
|
||||
time: float = 0.0
|
||||
value: str = ""
|
||||
@@ -124,7 +120,6 @@ class SignalData:
|
||||
attributes: 列上方各属性行(行号 -> 文本)的字典映射
|
||||
datalog: 时间戳-数值采样点列表
|
||||
"""
|
||||
# signal_type: str | None = None
|
||||
column: int = 0
|
||||
attributes: dict[str, str] = field(default_factory=dict)
|
||||
datalog: list[DataLog] = field(default_factory=list)
|
||||
@@ -177,16 +172,3 @@ class ExcelDataResult:
|
||||
"""
|
||||
return list(self.signals.keys())
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
"""转换为字典格式(兼容旧 API)
|
||||
|
||||
Returns:
|
||||
包含所有信号的字典,保留原有的数据结构
|
||||
"""
|
||||
result = {
|
||||
"sheet_name": self.sheet_name,
|
||||
"source_row": self.source_row
|
||||
}
|
||||
for name, signal in self.signals.items():
|
||||
result[name] = signal.to_dict()
|
||||
return result
|
||||
@@ -61,7 +61,7 @@ def _load_from_source(runtime_dir: Path, pkg: str) -> ModuleType | None:
|
||||
|
||||
|
||||
def _load_from_pyd(build_dir: Path, pkg: str) -> ModuleType | None:
|
||||
"""尝试从 build/<pkg>/<pkg>.cp311-*.pyd 加载预编译包。"""
|
||||
"""尝试从 build/<pkg>/<pkg>.<python-tag>.pyd 加载预编译包。"""
|
||||
candidates = list(build_dir.glob(f"{pkg}.*.pyd"))
|
||||
if not candidates:
|
||||
return None
|
||||
@@ -87,7 +87,6 @@ def load_companions(packages: list[str]) -> list[str]:
|
||||
loaded: list[str] = []
|
||||
for pkg in packages:
|
||||
if pkg in sys.modules:
|
||||
logger.debug(f"伴生包 {pkg} 已在 sys.modules,跳过")
|
||||
loaded.append(pkg)
|
||||
continue
|
||||
|
||||
@@ -102,5 +101,4 @@ def load_companions(packages: list[str]) -> list[str]:
|
||||
logger.warning(
|
||||
f"伴生包未找到: {pkg}(runtime={runtime_dir} / build={build_dir} 均无)"
|
||||
)
|
||||
|
||||
return loaded
|
||||
@@ -3,7 +3,7 @@
|
||||
这是唯一的事实源:
|
||||
- build_pyd.py 读 COMPANION_PACKAGES_PYD 决定要编哪些伴生包;
|
||||
- build_pyd.py 编译 mil 时用 --include-package 把 COMPANION_PACKAGES_INLINE 编进 mil.pyd;
|
||||
- tools/export_runtime.py 读 COMPANION_C_EXTENSIONS 决定要拷哪些 C 扩展。
|
||||
- build_pyd.py 导出步骤读 COMPANION_C_EXTENSIONS 决定要拷哪些 C 扩展。
|
||||
|
||||
加新伴生包时只动这里,其它脚本自动跟随。
|
||||
"""
|
||||
|
||||
@@ -133,10 +133,9 @@ def _analysis_case(data_dict: dict, sheets_dict: dict) -> CaseResultDict:
|
||||
for case in sheet_dict.keys():
|
||||
try:
|
||||
if sheet_dict[case]["enable"]:
|
||||
# 已完成的用例跳过生成
|
||||
continue
|
||||
except KeyError:
|
||||
# 缺少 enable 字段:保守跳过
|
||||
logger.warning(f"用例 '{case}' 缺少 enable 字段,跳过生成")
|
||||
continue
|
||||
|
||||
# 拷贝数据并重置 datalog,然后按步骤逐条填充
|
||||
|
||||
@@ -86,19 +86,16 @@ def read_excel_case(
|
||||
except FileNotFoundError:
|
||||
raise ExcelReadError(f"Excel文件 {excel_path} 不存在")
|
||||
except Exception as e:
|
||||
logger.error(f"读取 Excel 文件失败: {e}")
|
||||
raise ExcelReadError(f"无法读取Excel文件 {excel_path}: {str(e)}")
|
||||
|
||||
# 版本表 Atech-Hefei 必须存在;解析后将其从工作簿移除,避免进入后续遍历
|
||||
try:
|
||||
version = _get_template_version(wb["Atech-Hefei"])
|
||||
if version is None:
|
||||
logger.error("缺少模板版本号")
|
||||
raise ExcelFormatError("Excel格式错误,缺少模板版本号")
|
||||
logger.info(f"用例模板版本号: {version}")
|
||||
del wb["Atech-Hefei"]
|
||||
except KeyError:
|
||||
logger.error(f"缺少 'Atech-Hefei' 表")
|
||||
raise ExcelFormatError(f"Excel文件 {excel_path} 格式错误,缺少 Atech-Hefei 表")
|
||||
|
||||
result_dict: CaseDict = {}
|
||||
|
||||
@@ -32,23 +32,14 @@ class ExcelReaderConfig:
|
||||
source_header: 数据源标记行文本,默认 "Source: Input"
|
||||
time_column: 时间列索引,默认 1(A 列)
|
||||
header_row: 信号名称所在行号,默认 1
|
||||
type_row: 信号类型所在行号,默认 3
|
||||
interp_row: 插值策略所在行号,默认 6
|
||||
data_start_row_offset: 相对于 source_row 的数据起始行偏移量,默认 1
|
||||
output_header: 输出数据标记行文本,默认 "Source: Output"
|
||||
block_path_row: BlockPath 属性所在行号,默认 4
|
||||
"""
|
||||
sheet_name: str = "Scenario1"
|
||||
source_header: str = "Source: Input"
|
||||
time_column: int = 1
|
||||
header_row: int = 1
|
||||
type_row: int = 3
|
||||
interp_row: int = 6
|
||||
data_start_row_offset: int = 1
|
||||
|
||||
output_header: str = "Source: Output"
|
||||
block_path_row: int = 4
|
||||
|
||||
|
||||
def read_excel_data(
|
||||
excel_path: str,
|
||||
@@ -87,17 +78,14 @@ def read_excel_data(
|
||||
wb = load_workbook(excel_path)
|
||||
logger.info(f"文件加载成功,Sheet 数量: {len(wb.sheetnames)}")
|
||||
except FileNotFoundError:
|
||||
logger.error(f"文件不存在: {excel_path}")
|
||||
raise ExcelReadError(f"Excel文件 {excel_path} 不存在")
|
||||
except Exception as e:
|
||||
logger.error(f"读取文件失败: {e}")
|
||||
raise ExcelReadError(f"读取Excel文件 {excel_path} 失败: {e}")
|
||||
|
||||
# 2) 取出约定名称的工作表,KeyError 表示工作表缺失,视为格式错误
|
||||
try:
|
||||
sheet = wb[config.sheet_name]
|
||||
except KeyError:
|
||||
logger.error(f"缺少 '{config.sheet_name}' 表")
|
||||
raise ExcelFormatError(f"Excel文件 {excel_path} 缺少 '{config.sheet_name}' 表")
|
||||
|
||||
# 3) 自第 1 行起纵向扫描 "Source: Input" 标记行
|
||||
@@ -108,7 +96,6 @@ def read_excel_data(
|
||||
source_row += 1
|
||||
# 扫描到表格末尾仍未命中,认定为格式错误
|
||||
if source_row >= sheet.max_row:
|
||||
logger.error(f"缺少 {config.source_header} 标记")
|
||||
raise ExcelFormatError(f"Excel格式错误,缺少 {config.source_header}")
|
||||
|
||||
logger.debug(f"找到 {config.source_header} 标记,行号: {source_row}")
|
||||
@@ -177,7 +164,7 @@ def __get_signal_attributes(
|
||||
Args:
|
||||
sheet: Worksheet 对象
|
||||
column: 列号
|
||||
max_row: 信号名行(不含)以内的最大行号
|
||||
max_row: Source: Input 标记行(不包含),即属性区域的上界
|
||||
|
||||
Returns:
|
||||
信号属性字典,键为行号(int),值为该单元格文本(str)
|
||||
|
||||
@@ -44,7 +44,6 @@ def update_case_excel(filename: str, old_data: dict, new_data: dict) -> None:
|
||||
new_source_row = new_data.pop('source_row')
|
||||
|
||||
if not isinstance(old_wb, Workbook) or not isinstance(old_sheet, Worksheet):
|
||||
logger.error("数据类型错误,Workbook 或 Worksheet 类型不匹配")
|
||||
raise CaseDataError("数据异常,Workbook 或 Worksheet 类型错误")
|
||||
|
||||
# 计算"新增"与"删除"两组信号
|
||||
|
||||
@@ -106,6 +106,7 @@ class MILProject(QFrame, Ui_FrameMILProject):
|
||||
else:
|
||||
path,type = QFileDialog.getOpenFileName(self, "选择文件", "./","Excel工作簿(*.xlsx)")
|
||||
if not os.path.exists(path):
|
||||
logger.debug(f"数据文件选择已取消: {dataPath}")
|
||||
return
|
||||
self.lineEditDataPath.setText(path)
|
||||
self.on_datapath_editing_finished_event()
|
||||
@@ -117,6 +118,7 @@ class MILProject(QFrame, Ui_FrameMILProject):
|
||||
else:
|
||||
path,type = QFileDialog.getOpenFileName(self, "选择文件", "./","Excel工作簿(*.xlsx)")
|
||||
if not os.path.exists(path):
|
||||
logger.debug(f"测试用例文件选择已取消: {filePath}")
|
||||
return
|
||||
self.lineEditFilePath.setText(path)
|
||||
self.on_filepath_editing_finished_event()
|
||||
+9
-7
@@ -11,8 +11,8 @@ from .mil_project import MILProject
|
||||
|
||||
from mil.core import Config
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CONF = "mil.json"
|
||||
|
||||
class FrameMILTool(QFrame,Ui_FrameMILTool):
|
||||
@@ -109,12 +109,11 @@ class FrameMILTool(QFrame,Ui_FrameMILTool):
|
||||
if text == "" or self.lock_event:
|
||||
return
|
||||
|
||||
self.config.CurrProject= text
|
||||
self.config.CurrProject = text
|
||||
self.config.save_config()
|
||||
|
||||
self.DataPath.setText(self.config.ItemConfigs[self.config.CurrProject]["DataPath"])
|
||||
self.FilePath.setText(self.config.ItemConfigs[self.config.CurrProject]["FilePath"])
|
||||
pass
|
||||
|
||||
def on_new_pro_event(self):
|
||||
item = QListWidgetItem()
|
||||
@@ -127,7 +126,6 @@ class FrameMILTool(QFrame,Ui_FrameMILTool):
|
||||
self.listWidget.addItem(item)
|
||||
self.listWidget.setCurrentItem(item)
|
||||
self.listWidget.setItemWidget(item, mil_project)
|
||||
pass
|
||||
|
||||
def add_pro_event(self, name):
|
||||
item = QListWidgetItem()
|
||||
@@ -143,8 +141,9 @@ class FrameMILTool(QFrame,Ui_FrameMILTool):
|
||||
|
||||
def on_del_pro_event(self):
|
||||
mil_project = self.listWidget.itemWidget(self.listWidget.currentItem())
|
||||
if not isinstance(mil_project,MILProject):
|
||||
raise "on_del_pro_event error!!!"
|
||||
if not isinstance(mil_project, MILProject):
|
||||
logger.error("on_del_pro_event: 当前项不是 MILProject 实例")
|
||||
return
|
||||
|
||||
if self.config.CurrProject == mil_project.name:
|
||||
self.config.CurrProject = ""
|
||||
@@ -154,7 +153,6 @@ class FrameMILTool(QFrame,Ui_FrameMILTool):
|
||||
self.config.save_config()
|
||||
|
||||
self.update_config()
|
||||
pass
|
||||
|
||||
def search_mil_pro_item(self, name):
|
||||
for mil_project in self.listWidget.findChildren(MILProject):
|
||||
@@ -171,6 +169,8 @@ class FrameMILTool(QFrame,Ui_FrameMILTool):
|
||||
else:
|
||||
path,type = QFileDialog.getOpenFileName(self, "选择文件", os.getcwd(),"Excel工作簿(*.xlsx)")
|
||||
self.DataPath.setText(path)
|
||||
if not path:
|
||||
return
|
||||
|
||||
self.config.ItemConfigs[self.config.CurrProject]["DataPath"] = path
|
||||
mil_project = self.search_mil_pro_item(self.config.CurrProject)
|
||||
@@ -185,6 +185,8 @@ class FrameMILTool(QFrame,Ui_FrameMILTool):
|
||||
else:
|
||||
path,type = QFileDialog.getOpenFileName(self, "选择文件", os.getcwd(),"Excel工作簿(*.xlsx)")
|
||||
self.FilePath.setText(path)
|
||||
if not path:
|
||||
return
|
||||
|
||||
self.config.ItemConfigs[self.config.CurrProject]["FilePath"] = path
|
||||
mil_project = self.search_mil_pro_item(self.config.CurrProject)
|
||||
|
||||
Reference in New Issue
Block a user