Copy library datasheets onto every graph IC before review.

Review skipped U* when the PDF was stored under a catalog MPN or the part was only in the netlist. Lookup now uses spelling variants and aliases.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-28 02:18:50 +02:00
co-authored by Cursor
parent 19b4c11f62
commit 3be7d2fc21
2 changed files with 39 additions and 10 deletions
+26 -6
View File
@@ -681,11 +681,19 @@ async def _ensure_local_datasheet(
""" """
if pdf_path.is_file(): if pdf_path.is_file():
return True return True
lib_ds_key = proj_svc.library_has_datasheet(ctx.storage, mpn) from backend.services.datasheet_finder import find_datasheet, mpn_query_variants
if lib_ds_key:
ctx.storage.download_to_local(lib_ds_key, pdf_path) for name in mpn_query_variants(mpn) or [mpn]:
return True alt = pdf_path.parent / f"{safe_mpn(name)}.pdf"
from backend.services.datasheet_finder import find_datasheet if alt.is_file():
if alt.resolve() != pdf_path.resolve():
pdf_path.parent.mkdir(parents=True, exist_ok=True)
pdf_path.write_bytes(alt.read_bytes())
return True
lib_ds_key = proj_svc.library_has_datasheet(ctx.storage, name)
if lib_ds_key:
ctx.storage.download_to_local(lib_ds_key, pdf_path)
return True
broker.publish( broker.publish(
ctx.project_id, "step_update", ctx.project_id, "step_update",
@@ -1474,7 +1482,19 @@ async def _stage_validation(ctx: PipelineContext) -> None:
# Ensure all IC datasheet PDFs are available locally for review. # Ensure all IC datasheet PDFs are available locally for review.
# Cached ICs skipped pintable extraction, so their PDFs may not # Cached ICs skipped pintable extraction, so their PDFs may not
# have been downloaded yet. Auto-fetch fills remaining gaps. # have been downloaded yet. Auto-fetch fills remaining gaps.
for mpn in ctx.ic_mpns: # Ensure PDFs for BOM ICs and any extra U* the netlist classified as IC.
seen_mpn: set[str] = set()
mpns_to_place = list(ctx.ic_mpns)
for comp in ctx.graph.components.values():
if comp.component_type != ComponentType.IC:
continue
extra = (comp.mpn or "").strip()
if extra:
mpns_to_place.append(extra)
for mpn in mpns_to_place:
if mpn in seen_mpn:
continue
seen_mpn.add(mpn)
safe = safe_mpn(mpn) safe = safe_mpn(mpn)
pdf_path = ds_dir / f"{safe}.pdf" pdf_path = ds_dir / f"{safe}.pdf"
if not pdf_path.is_file(): if not pdf_path.is_file():
+13 -4
View File
@@ -571,15 +571,24 @@ def _find_pdf(
"""Find the datasheet PDF for an MPN. Checks local dir first, """Find the datasheet PDF for an MPN. Checks local dir first,
then tries to download from the library. then tries to download from the library.
""" """
safe = safe_mpn(mpn) from backend.services.datasheet_finder import mpn_query_variants
local = pdf_dir / f"{safe}.pdf" from backend.pinscopex.utils import safe_mpn as _safe
if local.is_file():
return local names = mpn_query_variants(mpn) or [mpn]
for name in names:
local = pdf_dir / f"{_safe(name)}.pdf"
if local.is_file():
wanted = pdf_dir / f"{_safe(mpn)}.pdf"
if local != wanted and not wanted.is_file():
wanted.write_bytes(local.read_bytes())
return wanted
return local
if storage: if storage:
from backend.services import projects as proj_svc from backend.services import projects as proj_svc
lib_key = proj_svc.library_has_datasheet(storage, mpn) lib_key = proj_svc.library_has_datasheet(storage, mpn)
if lib_key: if lib_key:
local = pdf_dir / f"{_safe(mpn)}.pdf"
storage.download_to_local(lib_key, local) storage.download_to_local(lib_key, local)
if local.is_file(): if local.is_file():
return local return local