From d9cf71000fb7c2197d05bae1c7bce47af5297aa5 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Thu, 21 Feb 2019 11:21:12 +0100 Subject: Trying a new way to generate way to generate files. --- src/ee/kicad/make_bom.py | 151 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 src/ee/kicad/make_bom.py (limited to 'src/ee/kicad') diff --git a/src/ee/kicad/make_bom.py b/src/ee/kicad/make_bom.py new file mode 100644 index 0000000..3fa102f --- /dev/null +++ b/src/ee/kicad/make_bom.py @@ -0,0 +1,151 @@ +import sys +from typing import Optional, List, Callable, Mapping +from xml.dom import minidom +from xml.etree import ElementTree + +from ee import EeException +from ee.kicad.model import Component +from ee.kicad.read_schematic import read_schematics +from ee.kicad.to_bom import to_bom, to_bom_xml +from ee.tools import mk_parents +from ee.xml import bomFile +from ee.bom import part_type_uris + +__all__ = [ + "StrategyCallable", + "MakeBomStrategy", + "apply_strategies", + "mpn_strategy", + "part_type_strategy", + "dpn_strategy_factory", + "make_bom", +] + +StrategyCallable = Callable[[Component, bomFile.Part], Optional[bomFile.Part]] + + +def apply_strategies(c: Component, part: bomFile.Part, strategies: List[StrategyCallable]): + for strategy in strategies: + part = strategy(c, part) + + if part is None: + return + + if not isinstance(part, bomFile.Part): + raise EeException("Values returned from strategy must be a bomFile.Part, got {}".format(type(part))) + + return part + + +def part_type_strategy(component: Component, part: bomFile.Part) -> bomFile.Part: + fp = component.footprint + if fp is None: + return part + + lib, part_name = fp.split(":") + + if lib == "Capacitor_SMD": + part.part_typeProp = part_type_uris.CAPACITOR + elif lib == "Resistor_SMD": + part.part_typeProp = part_type_uris.RESISTOR + elif lib == "Diode_SMD": + part.part_typeProp = part_type_uris.DIODE + elif lib == "Inductor_SMD": + part.part_typeProp = part_type_uris.INDUCTOR + elif lib == "Crystal": + part.part_typeProp = part_type_uris.CRYSTAL + + return part + + +def mpn_strategy(component: Component, part: bomFile.Part) -> bomFile.Part: + mpn = component.get_field("mpn") + if mpn is not None: + pn = bomFile.PartNumber(value=mpn.value) + part.part_numbersProp.add_part_number(pn) + + return part + + +def dpn_strategy_factory(dpn_mappings: Mapping[str, str]) -> StrategyCallable: + def dpn_strategy(component: Component, part: bomFile.Part) -> bomFile.Part: + for field_name, distributor in dpn_mappings: + s = component.get_field(field_name) + if s is not None: + pn = bomFile.PartNumber(value=s, distributor=distributor) + part.part_numbersProp.add_part_number(pn) + + return part + + return dpn_strategy + + +class MakeBomStrategy(): + def __init__(self, dpn_mappings: Mapping[str, str] = None): + self.dpn_mappings = dpn_mappings or {} + self.default_strategies = [ + mpn_strategy, + part_type_strategy, + dpn_strategy_factory(self.dpn_mappings), + ] + + def process_part(self, component: Component, part: bomFile.Part): + return self.default_process_part(component, part) + + def default_process_part(self, component: Component, part: bomFile.Part): + return apply_strategies(component, part, self.default_strategies) + + +def work(sch, out_file, strategy: MakeBomStrategy, new_mode, pretty): + if not new_mode: + bom = to_bom_xml(sch) + xml = ElementTree.tostring(bom, encoding="unicode") + + if pretty: + xml = minidom.parseString(xml).toprettyxml(indent=" ") + + print(xml, file=out_file) + else: + file = bomFile.BomFile() + + parts = bomFile.PartList() + file.partsProp = parts + + components = to_bom(sch) + for c in components: + part = bomFile.Part(id=c.ref) + part.schema_reference = c.ref + part.part_numbersProp = bomFile.PartNumberList() + + part = strategy.process_part(c, part) + + if len(part.part_numbersProp.get_part_number()) == 0: + part.part_numbersProp = None + + if part is not None: + parts.add_part(part) + + file.export(out_file, 0, name_="bom-file", namespacedef_="xmlns='http://purl.org/ee/bom-file'", + pretty_print=pretty) + + +def make_bom(sch_file: str, out_file: Optional[str], strategy_name: str, new_mode: bool, pretty: bool): + sch = read_schematics(sch_file) + + import pydoc + make_bom_strategy_factory = pydoc.locate(strategy_name) + + if not callable(make_bom_strategy_factory): + raise EeException("Not a callable: {}, is a {}".format(strategy_name, type(make_bom_strategy_factory))) + + make_bom_strategy = make_bom_strategy_factory() # type: MakeBomStrategy + + if not isinstance(make_bom_strategy, MakeBomStrategy): + raise EeException("Not a MakeBomStrategy: {}, is a {}".format(strategy_name, type(make_bom_strategy))) + + if out_file: + mk_parents(out_file) + with open(out_file, "w") as f: + work(sch, f, make_bom_strategy, new_mode, pretty) + else: + work(sch, sys.stdout, make_bom_strategy, new_mode, pretty) -- cgit v1.2.3