"""PinList validator — checks pin data integrity. Validates a PinList for: 1. Pin numbers starting from 1 with no gaps 2. No duplicate pin numbers 3. Total pin count matches grid perimeter (rows + cols) × 2 4. Missing PinName defaults to NC (warning) 5. Pin count not a multiple of 4 (info) """ from models import PinListEntry, ValidationResult, ValidationError def validate_pinlist( entries: list[PinListEntry], rows: int, cols: int, ) -> ValidationResult: """ 验证 PinList 数据。 检查项: 1. Pin 序号从 1 开始连续无缺失 2. Pin 序号无重复 3. Pin 总数 = (rows + cols) × 2(周长匹配) 4. Pin 缺少 PinName 时默认为 NC(warning) 5. Pin 数量不是 4 的倍数时提示(info) Parameters ---------- entries : list[PinListEntry] 已按序号排序的引脚列表 rows : int 用户输入的 PinMAP 行数 cols : int 用户输入的 PinMAP 列数 Returns ------- ValidationResult """ errors: list[ValidationError] = [] warnings: list[ValidationError] = [] infos: list[ValidationError] = [] numbers = [e.number for e in entries] # ── 1. 连续性检查 ──────────────────────────────────────────── expected_numbers = list(range(1, len(numbers) + 1)) if numbers != expected_numbers: missing = set(expected_numbers) - set(numbers) if missing: errors.append(ValidationError( level="error", message="Pin序号不连续", details=f"缺失的序号: {sorted(missing)}", )) # ── 2. 唯一性检查 ──────────────────────────────────────────── if len(numbers) != len(set(numbers)): from collections import Counter counts = Counter(numbers) duplicates = sorted(n for n, c in counts.items() if c > 1) errors.append(ValidationError( level="error", message="Pin序号存在重复", details=f"重复的序号: {duplicates}", )) # ── 3. 周长匹配 ────────────────────────────────────────────── # 周长公式:(rows + cols) * 2 expected_total = (rows + cols) * 2 actual_total = len(entries) if actual_total != expected_total: errors.append(ValidationError( level="error", message="Pin数量与网格周长不匹配", details=( f"网格 {rows}×{cols} 需要 {expected_total} 个引脚," f"但 PinList 有 {actual_total} 个" ), )) # ── 4. 缺失 PinName(warning)──────────────────────────────── missing_names = [e for e in entries if not e.name or not e.name.strip()] if missing_names: warnings.append(ValidationError( level="warning", message=f"检测到 {len(missing_names)} 个引脚缺少 PinName", details=( f"缺失引脚序号: {[e.number for e in missing_names]}," f"将默认为 NC" ), )) # ── 5. 非 4 倍数提示(info)────────────────────────────────── if actual_total % 4 != 0: infos.append(ValidationError( level="info", message="Pin数量不是4的倍数", details=( f"Pin数量 ({actual_total}) 不是 4 的倍数," f"四条边将不均匀分布" ), )) is_valid = len(errors) == 0 return ValidationResult( is_valid=is_valid, errors=errors, warnings=warnings, )