Files
mil_sdk/mil/core/base.py
T

192 lines
6.0 KiB
Python
Raw 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 SDK 核心数据模型"""
import os
import json
import logging
from dataclasses import dataclass, field, fields
from typing import Any
logger = logging.getLogger(__name__)
@dataclass
class Config():
"""MIL SDK 全局配置
承载测试工程相关的全局开关与路径信息,是 UI 层与 core 层之间的
配置传输载体。序列化使用 JSON 文件持久化。
Attributes:
DataPath: 仿真数据目录(Excel 原始文件所在路径)
FilePath: 当前打开的 Excel 文件路径
AddTimeEn: 用例步骤时间是否按累加方式记录
GeratePath: 是否为生成的用例另存新文件
CurrProject: 当前工程名称
ItemConfigs: 各模块/用例项的细粒度配置
"""
path:str
DataPath:str = ""
FilePath:str = ""
AddTimeEn:bool = True
GeratePath:bool = True
CurrProject:str = ""
# dict 是可变类型,必须用 default_factory 显式实例化,避免多个 Config 共享同一对象
ItemConfigs: dict = field(default_factory=dict)
def check_path(self):
return os.path.exists(self.path)
def to_dict(self):
"""将 Config 实例序列化为 dict,便于写入 JSON 文件。"""
return {
"DataPath":self.DataPath,
"FilePath":self.FilePath,
"AddTimeEn":self.AddTimeEn,
"GeratePath":self.GeratePath,
"CurrProject":self.CurrProject,
"ItemConfigs":self.ItemConfigs,
}
def load_config(self) -> "Config":
"""从 JSON 文件读取配置并填充到当前实例的各个字段。
解析规则:
- JSON 中存在的字段会被回写到 Config 的对应字段;
- JSON 中缺失的字段保持当前 Config 实例的默认值;
- JSON 中多余字段被忽略(向前兼容:增加字段不会破坏老配置)。
Args:
config_path: 配置文件路径。
Returns:
self:填充后的 Config 实例,便于链式调用。
Raises:
FileNotFoundError: 配置文件不存在。
json.JSONDecodeError: 文件内容不是合法 JSON。
"""
try:
# 以 UTF-8 读取 JSON,避免 Windows 默认编码带来的乱码问题
with open(self.path, 'r', encoding='utf-8') as f:
raw = json.load(f)
except FileNotFoundError:
# 显式记录并重抛,遵循"错误必须显式处理,禁止静默失败"
logger.error(f"配置文件{self.path}未找到")
raise
if not isinstance(raw, dict):
# 文件不合法(非 dict 根节点)→ 用一个空 dict 填充,保持实例可用
raw = {}
# 用反射取出本类已声明的字段名白名单,避免 JSON 脏字段污染
allowed = {f.name for f in fields(self.__class__)}
for key, value in raw.items():
if key in allowed:
setattr(self, key, value)
return self
def save_config(self):
"""将当前配置以 JSON 格式写入磁盘。
Args:
config_path: 配置文件路径。
Raises:
Exception: 写入失败时记录日志并原样抛出异常。
"""
try:
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}")
@dataclass
class DataLog:
"""仿真数据日志记录
Attributes:
time: 时间戳(秒)
value: 信号值(可以是任意类型)
"""
time: float = 0.0
value: str = ""
@dataclass
class SignalData:
"""信号数据封装
描述 Excel 中某一列信号的完整信息:
- 所在列号(column
- 列上方的属性行(attributes,例如 Signal Name / BlockPath 等)
- 时间-值采样序列(datalog
Attributes:
column: 信号在 Excel 工作表中的列索引(1-based
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)
def to_dict(self) -> dict[str, Any]:
"""将 SignalData 转为 dict,便于跨层传输与持久化。
Returns:
包含 column、attributes、datalog 字段的字典。
"""
return {
"column": self.column,
"attributes": self.attributes,
"datalog": self.datalog
}
@dataclass
class ExcelDataResult:
"""Excel 数据读取结果封装
提供对 Excel 数据的类型安全访问,隐藏内部实现细节
Attributes:
sheet_name: 工作表名称
source_row: Source: Input 所在行号
signals: 信号名称到信号数据的映射
"""
sheet_name: str = "Scenario1"
source_row: int = 0
signals: dict[str, SignalData] = field(default_factory=dict)
def get_signal(self, name: str) -> SignalData | None:
"""获取指定信号的数据
Args:
name: 信号名称
Returns:
信号数据对象,如果不存在返回 None
"""
return self.signals.get(name)
def get_signal_names(self) -> list[str]:
"""获取所有信号名称
Returns:
信号名称列表
"""
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