chronaxis.results.text_can_metadata
源码基线:8904c2f744951857659abd40aaa3535d57faf53c
1"""保存新文本CAN同次读取取得的DBC身份、解析声明和实际观测事实。23这是can-text-v1的独立清单,不冒充旧进程READY或未计算的原文件哈希。4声明的路径/格式与实际读取计数分别保留;空来源不伪造首末时间。5"""67from dataclasses import dataclass8from ..core.validation import require_identifier,require_text9from ..timebase.conversion import require_int64_ns10from .can_metadata import CANUnitCheck,CANFrameFormatNotice111213@dataclass(frozen=True)14class TextCANSourceMetadata:15 """仅接受冻结有限字段;实际事实由完成的ObservedSourceScan交付。"""1617 source: str18 session_id: str19 source_type: str20 read_identity: str21 inputs: tuple[tuple[str,str,int], ...]22 dbc_path: str23 dbc_sha256: str24 cantools_version: str25 record_count: int26 decode_calls: int27 first_ns: int | None28 last_ns: int | None29 unit_checks: tuple[CANUnitCheck,...]30 frame_format_notices: tuple[CANFrameFormatNotice,...]=()31 profile: str='can-text-v1'32 decode_scope: str='requested'33 time_scope: str='source'3435 def __post_init__(self):36 """核实结构及计数一致性,不读文件。参数: 冻结字段。返回: None。异常: 类型/值错误。37 """38 for name in ('source','session_id'):39 require_identifier(getattr(self,name),name)40 for name in ('read_identity','dbc_path','cantools_version'):41 require_text(getattr(self,name),name)42 if (self.source_type not in ('can_asc','asc_or_blf','raw_can_csv') or self.profile!='can-text-v1'43 or self.decode_scope!='requested' or self.time_scope!='source'):44 raise ValueError('文本CAN清单策略错误')45 if type(self.dbc_sha256) is not str or len(self.dbc_sha256)!=64 or any(c not in '0123456789abcdef' for c in self.dbc_sha256):46 raise ValueError('文本CAN清单需要实际DBC SHA256')47 if type(self.inputs) is not tuple or not 1<=len(self.inputs)<=4096:48 raise ValueError('文本CAN清单需要有限有序输入')49 for item in self.inputs:50 if type(item) is not tuple or len(item)!=3:51 raise ValueError('输入清单需要(path,parser,offset_ns)')52 require_text(item[0],'path'); require_text(item[1],'parser'); require_int64_ns(item[2],'offset_ns')53 if type(self.record_count) is not int or self.record_count<0 or type(self.decode_calls) is not int or not 0<=self.decode_calls<=self.record_count:54 raise ValueError('文本CAN实际帧数与解码次数错误')55 if not self.record_count:56 if self.first_ns is not None or self.last_ns is not None:57 raise ValueError('空文本CAN不能声明观测时间')58 else:59 require_int64_ns(self.first_ns,'first_ns'); require_int64_ns(self.last_ns,'last_ns')60 if self.first_ns>self.last_ns:61 raise ValueError('文本CAN观测时间倒退')62 if (type(self.unit_checks) is not tuple or any(type(x) is not CANUnitCheck for x in self.unit_checks)63 or type(self.frame_format_notices) is not tuple or any(type(x) is not CANFrameFormatNotice for x in self.frame_format_notices)):64 raise TypeError('文本CAN单位/帧型清单需要冻结模型tuple')65