Rename the core package to periscopex, update UI/docs/Docker/deploy defaults to periscope.michelebigi.it, and keep legacy version/storage key aliases so existing projects keep working. Co-authored-by: Cursor <cursoragent@cursor.com>
42 lines
1.5 KiB
Python
42 lines
1.5 KiB
Python
"""Shared-library promotion gates for extracted IC JSON."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import json
|
|
from typing import Any
|
|
|
|
|
|
def pintable_checksum(pintable: list[Any]) -> str:
|
|
"""Stable hash of pin number+name pairs (order-independent)."""
|
|
rows: list[tuple[str, str]] = []
|
|
for pin in pintable or []:
|
|
if isinstance(pin, dict):
|
|
num = str(pin.get("number") or "").strip()
|
|
name = str(pin.get("name") or "").strip()
|
|
else:
|
|
num = str(getattr(pin, "number", "") or "").strip()
|
|
name = str(getattr(pin, "name", "") or "").strip()
|
|
if num:
|
|
rows.append((num, name))
|
|
payload = json.dumps(sorted(rows), separators=(",", ":"))
|
|
return hashlib.sha256(payload.encode("utf-8")).hexdigest()[:16]
|
|
|
|
|
|
def should_promote_extraction(data: dict) -> tuple[bool, str]:
|
|
"""Return (ok, reason). Reject empty / tiny pintables from shared library."""
|
|
pins = data.get("pintable") or []
|
|
if not isinstance(pins, list) or len(pins) == 0:
|
|
return False, "empty pintable"
|
|
if len(pins) < 2:
|
|
return False, "pintable has fewer than 2 pins"
|
|
# Require at least one named pin so a number-only stub cannot poison the library.
|
|
named = 0
|
|
for pin in pins:
|
|
name = pin.get("name") if isinstance(pin, dict) else getattr(pin, "name", None)
|
|
if name and str(name).strip() and str(name).strip() != "~":
|
|
named += 1
|
|
if named == 0:
|
|
return False, "pintable has no named pins"
|
|
return True, pintable_checksum(pins)
|