"""Data models for PinMAP → PinList conversion.""" from dataclasses import dataclass, field @dataclass class Pin: """A single pin on the package.""" number: int name: str edge: str # "top" | "right" | "bottom" | "left" position_on_edge: int @dataclass class PinMAP: """Parsed pin map from an Excel file.""" package_info: str pins: list[Pin] width: int height: int grid_origin: tuple[int, int] # (row, col) of top-left corner raw_cells: dict[tuple[int, int], str] = field(default_factory=dict) @dataclass class PinList: """Flat pin list for output.""" package_info: str rows: list[tuple[str, int]] # [(PinName, Pin序号), ...] @dataclass class ValidationError: """A single validation issue.""" level: str # "error" | "warning" message: str details: str @dataclass class ValidationResult: """Aggregate validation result.""" is_valid: bool errors: list[ValidationError] = field(default_factory=list) warnings: list[ValidationError] = field(default_factory=list) @dataclass class PinListEntry: """A single pin entry from the PinList.""" number: int # Pin 序号(B 列) name: str # PinName(A 列,可能为空) @dataclass class EdgePins: """Pins assigned to one edge of the PinMAP.""" edge: str # "left" | "bottom" | "right" | "top" pins: list[tuple[int, str]] # [(number, name), ...] cells: list[tuple[int, int]] # 对应的单元格坐标 (row, col) 0-based @dataclass class PinMAPLayout: """计算出的 PinMAP 布局。""" package_info: str rows: int cols: int edges: dict[str, EdgePins] # left/bottom/right/top cells: dict[str, str] # 单元格数据 {"A2": "1", "B2": "Pin1", ...} # ── Custom exceptions ────────────────────────────────────────────── class PinMapError(Exception): """Base exception for this project.""" class FileFormatError(PinMapError): """Raised when a file is not a valid Excel format.""" class StructureError(PinMapError): """Raised when the PinMAP structure is invalid or unrecognisable.""" class LayoutError(PinMapError): """布局计算错误(尺寸无效、Pin 数量不匹配等)。"""