From 79ee5e3c64c0140a61324914d24049478a9cf7f5 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Tue, 28 May 2019 14:47:24 +0200 Subject: create-bom: Don't skip unmatched parts from the BOM. part-validate-parts: Read parts from the schematic, BOM and supplier's parts for even better rules. Enhancing footprint rule to check that the BOM part has the same footprint. --- src/ee/tools/part_validate_parts.py | 99 ++++++++++++++++++++++++++++--------- 1 file changed, 77 insertions(+), 22 deletions(-) (limited to 'src/ee/tools/part_validate_parts.py') diff --git a/src/ee/tools/part_validate_parts.py b/src/ee/tools/part_validate_parts.py index bf45ace..a9c5ba7 100644 --- a/src/ee/tools/part_validate_parts.py +++ b/src/ee/tools/part_validate_parts.py @@ -1,8 +1,10 @@ import argparse from itertools import groupby from pathlib import Path +from typing import List import ee.tools +from ee.db import ObjDb from ee.part import Part, load_db, common_fact_types @@ -46,27 +48,55 @@ class Messages(object): self.messages.extend(messages.messages) -def check_has_footprint(part: Part): - fp = part.facts.get_value(common_fact_types.footprint) - if fp is not None: - return +class Context(object): + def __init__(self, supplier_parts: ObjDb[Part]): + self.supplier_parts = supplier_parts + self.uri_idx = supplier_parts.index("uri") - return Messages(part).warning("No footprint") + def get_supplier_part(self, part_uri): + return self.uri_idx.get_single(part_uri) -def validate(f, part: Part): +def check_has_footprint(ctx: Context, bom: Part, sch: Part): + ms = Messages(sch) + + fp = sch.facts.get_value(common_fact_types.footprint) + if fp is None: + return ms.warning("No footprint in schematic part") + + part_ref = bom.get_only_part_reference() + + if part_ref is None: + return ms.warning("Part has footprint in schematic but no BOM part selected.") + + supplier_part = ctx.get_supplier_part(part_ref.part_uriProp) + + supplier_fp = supplier_part.facts.get_value(common_fact_types.footprint) + + if supplier_fp is None: + return ms.warning(f"Part has footprint in schematic and a BOM part but the BOM part doesn't have a footprint. " + f"Part's footprint: {fp}.") + if fp != supplier_fp: + return ms.warning("Part has footprint in schematic and a BOM part but their footprints do not match. " + f"Footprints: part: {fp}, BOM: {supplier_fp}.") + + ms.info("Part has footprint and BOM part. Their footprints matches.") + + +def validate(f, ctx: Context, bom_part: Part, sch_part: Part): validators = [ check_has_footprint ] - messages = Messages(part) + messages = Messages(sch_part) for validator in validators: - m = validator(part) + m = validator(ctx, bom_part, sch_part) if m: messages.append(m) - print("{}".format(part.printable_reference), file=f) - print("{}".format("=" * len(part.printable_reference)), file=f) + title = "Checking {}".format(sch_part.printable_reference) + print(title, file=f) + print("{}".format("=" * len(title)), file=f) print("", file=f) for msg in messages.errors: @@ -83,16 +113,31 @@ def validate(f, part: Part): return messages -def work(in_path: Path, out_path: Path): - in_parts = load_db(in_path) +def work(bom_path: Path, sch_path: Path, report_path: Path, part_dbs: List[Path]): + bom_parts: ObjDb[Part] = ObjDb[Part]() + bom_parts.add_unique_index("uri", lambda p: p.uri) + [bom_parts.add(Part(xml)) for xml in load_db(bom_path).iterparts()] - with out_path.open("w") as f: - messages = Messages(None) + sch_parts: ObjDb[Part] = ObjDb[Part]() + sch_parts.add_unique_index("uri", lambda p: p.uri) + ref_idx = sch_parts.add_unique_index("ref", lambda p: p.get_exactly_one_schematic_reference().referenceProp) + [sch_parts.add(Part(xml)) for xml in load_db(sch_path).iterparts()] - for xml in in_parts.iterparts(): - part = Part(xml) + supplier_parts = ObjDb[Part]() + supplier_parts.add_unique_index("uri", lambda p: p.uri) - ms = validate(f, part) + for path in part_dbs: + for xml in load_db(path).iterparts(): + supplier_parts.add(Part(xml)) + + ctx = Context(supplier_parts) + + with report_path.open("w") as f: + messages = Messages(None) + + for bom_part in bom_parts: + sch_part = ref_idx.get_single(bom_part.get_exactly_one_schematic_reference().referenceProp) + ms = validate(f, ctx, bom_part, sch_part) messages.append(ms) print("", file=f) @@ -111,16 +156,26 @@ def work(in_path: Path, out_path: Path): parser = argparse.ArgumentParser() ee.tools.add_default_argparse_group(parser) -parser.add_argument("--in", - dest="in_path", +parser.add_argument("--bom", + required=True, + metavar="PART DB") + +parser.add_argument("--sch", required=True, metavar="PART DB") -parser.add_argument("--out", +parser.add_argument("--report", required=True, - metavar="REQUIREMENTS") + metavar="FILE") + +parser.add_argument("--part-db", + dest="part_dbs", + nargs="*", + required=True, + metavar="PART DB") args = parser.parse_args() ee.tools.process_default_argparse_group(args) -work(Path(args.in_path), Path(args.out)) +part_dbs_paths = [Path(path) for path in args.part_dbs] +work(Path(args.bom), Path(args.sch), Path(args.report), part_dbs_paths) -- cgit v1.2.3