From 9eba62ef1d6b4896de693976116f69a9692332d9 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Mon, 20 May 2019 15:27:38 +0200 Subject: ee: o Adding FactType as a smaller wrapper around the fact uri. o Adding ee.part.Facts, used as Part.facts o Renaming 'type' uri to 'ee-component-type'. kicad-make-bom: Removing strategy functionality, replaced with part-apply-function. Moving default strategy contents into ee.kicad.functions. --- src/ee/kicad/functions.py | 105 ++++++++++++++++++++++++++ src/ee/kicad/make_bom.py | 164 ++++------------------------------------- src/ee/kicad/model.py | 24 +++--- src/ee/kicad/sch_fact_types.py | 18 +++++ 4 files changed, 151 insertions(+), 160 deletions(-) create mode 100644 src/ee/kicad/functions.py create mode 100644 src/ee/kicad/sch_fact_types.py (limited to 'src/ee/kicad') diff --git a/src/ee/kicad/functions.py b/src/ee/kicad/functions.py new file mode 100644 index 0000000..39614b6 --- /dev/null +++ b/src/ee/kicad/functions.py @@ -0,0 +1,105 @@ +import re + +import ee.kicad.model +import ee.kicad.sch_fact_types as kicad_ft +from ee.kicad import sch_fact_types +from ee.part import Part +from ee.part import common_fact_types +from ee.xml import uris + + +def part_type_from_footprint(lib): + if lib == "Capacitor_SMD": + return uris.CAPACITOR + elif lib == "Resistor_SMD": + return uris.RESISTOR + elif lib == "Diode_SMD": + return uris.DIODE + elif lib == "Inductor_SMD": + return uris.INDUCTOR + elif lib == "Crystal": + return uris.CRYSTAL + + +def part_type_from_ref_type(ref_type): + if ref_type == "C": + return uris.CAPACITOR + elif ref_type == "R": + return uris.RESISTOR + elif ref_type == "D": + return uris.DIODE + elif ref_type == "L": + return uris.INDUCTOR + elif ref_type == "X": + return uris.CRYSTAL + elif ref_type == "Q": + return uris.TRANSISTOR + + +def part_type_strategy(part: Part) -> Part: + pt = None + + fp_lib = part.facts.get_value(kicad_ft.footprint_library) + if fp_lib is not None: + pt = part_type_from_footprint(fp_lib) + + ref = part.get_only_schematic_reference() + if ref: + ref_type, ref_num = ee.kicad.model.split_ref(ref.referenceProp) + + if ref_type: + pt = part_type_from_ref_type(ref_type) + + if pt is not None: + part.facts.add(common_fact_types.ee_component_type, pt) + + return part + + +def fix_value_strategy(part: Part) -> Part: + ref = part.get_only_schematic_reference() + + if not ref: + return part + + ref_type, ref_num = ee.kicad.model.split_ref(ref.referenceProp) + + if not ref_num: + return part + + v = part.facts.get_value(sch_fact_types.value) + if not v: + return part + + symbol_name = part.facts.get_value(sch_fact_types.symbol_name) + + if ref_type in ("D", "R", "L", "C") and v == symbol_name: + part.remove_fact(uris.make_fact_key("value")) + + if ref_type == "Q" and v == symbol_name and re.match("^Q_[NP]MOS_[DSG]{3}$", symbol_name): + part.remove_fact(uris.make_fact_key("value")) + + return part + + +def mpn_strategy(part: Part) -> Part: + for field in part.facts.all(sch_fact_types.field): + + k, v = re.split(":", field.value, 1) + if k == "mpn": + part.add_mpn(v) + + return part + + +def default(part: Part) -> Part: + functions = [ + fix_value_strategy, + mpn_strategy, + part_type_strategy, + ] + + for f in functions: + part = f(part) + + return part diff --git a/src/ee/kicad/make_bom.py b/src/ee/kicad/make_bom.py index dcdf96b..13b2157 100644 --- a/src/ee/kicad/make_bom.py +++ b/src/ee/kicad/make_bom.py @@ -1,145 +1,19 @@ -import pydoc -import re from pathlib import Path -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 import sch_fact_types from ee.kicad.read_schematic import read_schematics from ee.kicad.to_bom import to_bom, to_bom_xml from ee.part import PartDb, save_db, Part -from ee.xml import types, uris +from ee.xml import types __all__ = [ - "StrategyCallable", - "MakeBomStrategy", - "apply_strategies", - "mpn_strategy", - "part_type_strategy", - "dpn_strategy_factory", "make_bom", ] -StrategyCallable = Callable[[Component, Part], Optional[Part]] - -def apply_strategies(c: Component, part: Part, strategies: List[StrategyCallable]): - for strategy in strategies: - part = strategy(c, part) - - if part is None: - return - - if not isinstance(part, Part): - raise EeException("Values returned from strategy must be a Part, got {}".format(type(part))) - - return part - - -def part_type_from_footprint(fp): - lib, part_name = fp.split(":") - - if lib == "Capacitor_SMD": - return uris.CAPACITOR - elif lib == "Resistor_SMD": - return uris.RESISTOR - elif lib == "Diode_SMD": - return uris.DIODE - elif lib == "Inductor_SMD": - return uris.INDUCTOR - elif lib == "Crystal": - return uris.CRYSTAL - - -def part_type_from_ref_type(ref_type): - if ref_type == "C": - return uris.CAPACITOR - elif ref_type == "R": - return uris.RESISTOR - elif ref_type == "D": - return uris.DIODE - elif ref_type == "L": - return uris.INDUCTOR - elif ref_type == "X": - return uris.CRYSTAL - elif ref_type == "Q": - return uris.TRANSISTOR - - -def part_type_strategy(component: Component, part: Part) -> Part: - pt = None - - fp = component.footprint - if fp is not None: - pt = part_type_from_footprint(fp) - - if pt is None and component.has_ref_num: - pt = part_type_from_ref_type(component.ref_type) - - if pt is not None: - part.get_facts().append(types.Fact(uris.make_fact_key("type"), value=pt)) - - return part - - -def fix_value_strategy(component: Component, part: Part) -> Part: - if not component.has_ref_num: - return part - - rt = component.ref_type - v = component.value - - if rt in ("D", "R", "L", "C") and v == component.symbol.name: - part.remove_fact(uris.make_fact_key("value")) - - if rt == "Q" and v == component.symbol.name and re.match("^Q_[NP]MOS_[DSG]{3}$", component.symbol.name): - part.remove_fact(uris.make_fact_key("value")) - - return part - - -def mpn_strategy(component: Component, part: Part) -> Part: - mpn = component.get_field("mpn") - if mpn is not None: - part.add_mpn(mpn.value) - - return part - - -def dpn_strategy_factory(dpn_mappings: Mapping[str, str]) -> StrategyCallable: - def dpn_strategy(component: Component, part: Part) -> Part: - for field_name, distributor in dpn_mappings: - s = component.get_field(field_name) - if s is None: - continue - - part.add_spn(s.value) - - return part - - return dpn_strategy - - -class MakeBomStrategy(): - def __init__(self): - self.dpn_mappings = {} - self.default_strategies = [ - fix_value_strategy, - mpn_strategy, - part_type_strategy, - dpn_strategy_factory(self.dpn_mappings), - ] - - def process_part(self, component: Component, part: Part): - return self.default_process_part(component, part) - - def default_process_part(self, component: Component, part: Part): - return apply_strategies(component, part, self.default_strategies) - - -def work(sch, out: Path, strategy: MakeBomStrategy, new_mode, pretty): +def work(sch, out: Path, new_mode, pretty): def strip(s): s = (s or "").strip() @@ -165,39 +39,31 @@ def work(sch, out: Path, strategy: MakeBomStrategy, new_mode, pretty): value = strip(c.value) if value: - part.facts.add(uris.make_fact_key("value"), value) + part.facts.add(sch_fact_types.value, value) + + if c.symbol.library: + part.facts.add(sch_fact_types.symbol_library, c.symbol.library) + part.facts.add(sch_fact_types.symbol_name, c.symbol.name) footprint = strip(c.footprint) if footprint: - part.facts.add(uris.make_fact_key("footprint"), footprint) + part.facts.add(sch_fact_types.footprint, footprint) i = footprint.find(":") if i >= 0: lib, footprint = footprint.split(":") - part.facts.add(uris.make_fact_key("kicad-schematic-library"), lib) - part.facts.add(uris.make_fact_key("kicad-schematic-footprint"), footprint) + part.facts.add(sch_fact_types.footprint_library, lib) + part.facts.add(sch_fact_types.footprint_name, footprint) - part = strategy.process_part(c, part) - - if part is None: - continue + for f in c.named_fields: + part.facts.add(sch_fact_types.field, "{}:{}".format(f.name, f.value)) parts.add_entry(part, True) save_db(out, parts) -def make_bom(sch_file: Path, out_dir: Path, strategy_name: str, new_mode: bool, pretty: bool): +def make_bom(sch_file: Path, out_dir: Path, new_mode: bool, pretty: bool): sch = read_schematics(str(sch_file)) - 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))) - - work(sch, out_dir, make_bom_strategy, new_mode, pretty) + work(sch, out_dir, new_mode, pretty) diff --git a/src/ee/kicad/model.py b/src/ee/kicad/model.py index 295a40a..1f6cf96 100644 --- a/src/ee/kicad/model.py +++ b/src/ee/kicad/model.py @@ -1,6 +1,6 @@ import re from functools import total_ordering -from typing import List, Set +from typing import List, Set, Tuple, Optional from ee import EeException @@ -62,7 +62,16 @@ class Symbol(object): self.name = symbol else: self.library = symbol[0:i] - self.name = symbol[i+1:] + self.name = symbol[i + 1:] + + +def split_ref(ref: str) -> Tuple[Optional[str], Optional[int]]: + r = re.compile("([^0-9]+)(.+)") + try: + parts = r.split(ref) + return parts[1], int(parts[2]) + except ValueError: + return None, None @total_ordering @@ -76,14 +85,7 @@ class Component(object): self._ref = ref self._fields = fields # type List[ComponentField] - r = re.compile("([^0-9]+)(.+)") - try: - parts = r.split(self._ref) - self._ref_type = parts[1] - self._ref_num = int(parts[2]) - except ValueError: - self._ref_type = None - self._ref_num = None + self._ref_type, self._ref_num = split_ref(self._ref) def __eq__(self, o: object) -> bool: other = o # type: Component @@ -157,7 +159,7 @@ class Component(object): return list(self._fields) @property - def named_fields(self): + def named_fields(self) -> List[ComponentField]: return [f for f in self._fields if f.name] def get_field(self, name) -> ComponentField: diff --git a/src/ee/kicad/sch_fact_types.py b/src/ee/kicad/sch_fact_types.py new file mode 100644 index 0000000..c9ea918 --- /dev/null +++ b/src/ee/kicad/sch_fact_types.py @@ -0,0 +1,18 @@ +from ee.part import FactType + + +def make_fact_key(key: str): + return "http://purl.org/ee/kicad-sch-fact-type#{}".format(key) + + +value = FactType(make_fact_key("value"), "Value") +component = FactType(make_fact_key("component"), "Value") + +symbol_library = FactType(make_fact_key("symbol-library"), "Value") +symbol_name = FactType(make_fact_key("symbol-name"), "Value") + +footprint = FactType(make_fact_key("footprint"), "Value") +footprint_library = FactType(make_fact_key("footprint-library"), "Value") +footprint_name = FactType(make_fact_key("footprint-name"), "Value") + +field = FactType(make_fact_key("field"), "Value") -- cgit v1.2.3