114 lines
3.9 KiB
Python
114 lines
3.9 KiB
Python
"""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,
|
||
)
|