From 9bbb4f8f3a1d8e2bfe1f06c945081153435de940 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Mon, 20 May 2019 23:36:49 +0200 Subject: o Replacing digikey-normalize-facts with part-apply-function. Moving code from tool to ee.digikey.functions. --- src/ee/digikey/functions.py | 157 ++++++++++++++++++++++++++++++++ src/ee/digikey/normalize_facts.py | 153 ------------------------------- src/ee/kicad/functions.py | 4 + src/ee/tools/digikey_normalize_facts.py | 19 ---- src/ee/tools/init.py | 7 ++ src/ee/tools/part_apply_function.py | 5 +- src/ee/tools/templates/build.ninja.j2 | 27 +++--- 7 files changed, 184 insertions(+), 188 deletions(-) create mode 100644 src/ee/digikey/functions.py delete mode 100644 src/ee/digikey/normalize_facts.py delete mode 100644 src/ee/tools/digikey_normalize_facts.py diff --git a/src/ee/digikey/functions.py b/src/ee/digikey/functions.py new file mode 100644 index 0000000..047fad1 --- /dev/null +++ b/src/ee/digikey/functions.py @@ -0,0 +1,157 @@ +import re +from typing import List, Tuple, Union, Mapping, Callable, Any + +from ee import EeVal, EeException +from ee.part import Part +from ee.xml import types, uris + +__all__ = ["normalize_facts"] + + +# TODO: this should be moved to a generic normalizer +def handle_tolerance(tolerance: types.Fact, capacitance: types.Fact) -> List[types.Fact]: + cap_value = float(EeVal.parse(capacitance.valueProp)) + + s = tolerance.valueProp + print("tolerance: {}".format(s)) + is_plus_minus = s.startswith("±") + s = s[1:] if is_plus_minus else s + + is_percent = s.endswith("%") + + is_farad = s.endswith("F") + + print("tolerance={}, is_plus_minus={}, is_farad={}, is_percent={}".format( + tolerance.valueProp, is_plus_minus, is_farad, is_percent)) + print("capacitance={}".format(EeVal.parse(capacitance.valueProp))) + + low_pct = low_value = None + high_pct = high_value = None + facts = [] # type: List[Tuple[str, str, Union[str, EeVal]]] + + if is_farad: + s = s[0:-1] if is_farad else s + + try: + farad = EeVal.parse(s) + except EeException: + farad = None + + elif is_percent: + s = s[0:-1] + pct_value = int(s) + + if is_plus_minus: + low_pct = high_pct = str(pct_value) + pct = float(pct_value) / 100 + low_value = EeVal(value=cap_value * (1 - pct), exp=1, unit="F") + high_value = EeVal(value=cap_value * (1 + pct), exp=1, unit="F") + else: + raise EeException("bad combination") + + if low_pct: + facts.append(("tolerance-percent-lower", "Tolerance, lower (%)", low_pct)) + if high_pct: + facts.append(("tolerance-percent-upper", "Tolerance, upper (%)", high_pct)) + if low_value: + facts.append(("tolerance-lower", "Tolerance, lower", low_value)) + if high_value: + facts.append(("tolerance-upper", "Tolerance, upper", high_value)) + + if low_pct and low_pct == high_pct: + facts.append(("tolerance-percent", "Tolerance (±%)", low_pct)) + + return [types.Fact(key=uris.make_fact_key(key), label=label, value=str(value)) for key, label, value in facts] + + +def re_parser(pattern, kis: List[Tuple[str, int]]): + r = re.compile(pattern) + + def parse(value): + m = r.match(value) + + if not m: + return + + return [(k, m.group(i)) for k, i in kis] + + return parse + + +def no_parser(key): + def parse(value): + return key, value + + return parse + + +def ee_val_parser(key): + def parse(value): + return key, EeVal.parse(value) + + return parse + + +_operating_temperature_re = re.compile("-([0-9]+)°C ~ ([0-9])+°C") +_height_seated_re = re.compile("([0-9]+\\.[0-9]+)\" \\(([0-9]+\\.[0-9]+)mm\\)") +_land_size_re = re.compile("([0-9]+\\.[0-9]+)\" L x ([0-9]+\\.[0-9]+)\" W " + "\\(([0-9]+\\.[0-9]+)mm x ([0-9]+\\.[0-9]+)mm\\)") # 0.260" L x 0.260" W (6.60mm x 6.60mm) +_parsers: Mapping[int, Callable[[str], Any]] = { + 3: no_parser("tolerance"), + 1471: ee_val_parser("voltage-input-min"), # Voltage - Input (Min) + 573: ee_val_parser("voltage-input-max"), # Voltage - Input (Max) + 1429: ee_val_parser("voltage-output-max"), # Voltage - Output (Max) + 252: re_parser(_operating_temperature_re, [("temperature-min", 1), ("temperature-max", 2)]), + 1686: re_parser(_operating_temperature_re, [("temperature-junction-min", 1), ("temperature-junction-max", 2)]), + + 1500: re_parser(_height_seated_re, [("part-height", 2)]), + 884: re_parser(_land_size_re, [("land-size-x", 3), ("land-size-y", 4)]), + + 2049: ee_val_parser("capacitance"), + 2079: ee_val_parser("voltage-rating"), +} + + +# noinspection PyUnusedLocal +def normalize_facts(**kwargs): + parsers: Mapping[str, Callable[[str], Any]] = {uris.make_digikey_fact_key(k): v for k, v in _parsers.items()} + + def on_part(part: Part) -> Part: + for dk_key, parser in parsers.items(): + value = part.facts.get_value(dk_key) + + if value is None or value == "-": + continue + + res = parser(value) + + if res is not None: + if isinstance(res, list): + for key, value in res: + key = uris.make_fact_key(key) + part.facts.add(key, value) + else: + key, value = res + key = uris.make_fact_key(key) + part.facts.add(key, value) + + return part + + return on_part + + +def default(**kwargs): + function_factories = [ + normalize_facts, + ] + + functions = [factory(**kwargs) for factory in function_factories] + functions = [f for f in functions if f is not None] + + def on_part(part: Part) -> Part: + for f in functions: + part = f(part) + + return part + + return on_part diff --git a/src/ee/digikey/normalize_facts.py b/src/ee/digikey/normalize_facts.py deleted file mode 100644 index 1ffc16a..0000000 --- a/src/ee/digikey/normalize_facts.py +++ /dev/null @@ -1,153 +0,0 @@ -import re -from pathlib import Path -from typing import List, Tuple, Union, Mapping, Callable, Any - -from ee import EeVal, EeException -from ee.part import PartDb, load_db, save_db -from ee.xml import types, uris - -__all__ = ["normalize_facts"] - - -# TODO: this should be moved to a generic normalizer -def handle_tolerance(tolerance: types.Fact, capacitance: types.Fact) -> List[types.Fact]: - cap_value = float(EeVal.parse(capacitance.valueProp)) - - s = tolerance.valueProp - print("tolerance: {}".format(s)) - is_plus_minus = s.startswith("±") - s = s[1:] if is_plus_minus else s - - is_percent = s.endswith("%") - - is_farad = s.endswith("F") - - print("tolerance={}, is_plus_minus={}, is_farad={}, is_percent={}".format( - tolerance.valueProp, is_plus_minus, is_farad, is_percent)) - print("capacitance={}".format(EeVal.parse(capacitance.valueProp))) - - low_pct = low_value = None - high_pct = high_value = None - facts = [] # type: List[Tuple[str, str, Union[str, EeVal]]] - - if is_farad: - s = s[0:-1] if is_farad else s - - try: - farad = EeVal.parse(s) - except EeException: - farad = None - - elif is_percent: - s = s[0:-1] - pct_value = int(s) - - if is_plus_minus: - low_pct = high_pct = str(pct_value) - pct = float(pct_value) / 100 - low_value = EeVal(value=cap_value * (1 - pct), exp=1, unit="F") - high_value = EeVal(value=cap_value * (1 + pct), exp=1, unit="F") - else: - raise EeException("bad combination") - - if low_pct: - facts.append(("tolerance-percent-lower", "Tolerance, lower (%)", low_pct)) - if high_pct: - facts.append(("tolerance-percent-upper", "Tolerance, upper (%)", high_pct)) - if low_value: - facts.append(("tolerance-lower", "Tolerance, lower", low_value)) - if high_value: - facts.append(("tolerance-upper", "Tolerance, upper", high_value)) - - if low_pct and low_pct == high_pct: - facts.append(("tolerance-percent", "Tolerance (±%)", low_pct)) - - return [types.Fact(key=uris.make_fact_key(key), label=label, value=str(value)) for key, label, value in facts] - - -def re_parser(pattern, kis: List[Tuple[str, int]]): - r = re.compile(pattern) - - def parse(value): - m = r.match(value) - - if not m: - return - - return [(k, m.group(i)) for k, i in kis] - - return parse - - -def no_parser(key): - def parse(value): - return key, value - - return parse - - -def ee_val_parser(key): - def parse(value): - return key, EeVal.parse(value) - - return parse - - -_operating_temperature_re = re.compile("-([0-9]+)°C ~ ([0-9])+°C") -_height_seated_re = re.compile("([0-9]+\\.[0-9]+)\" \\(([0-9]+\\.[0-9]+)mm\\)") -_land_size_re = re.compile("([0-9]+\\.[0-9]+)\" L x ([0-9]+\\.[0-9]+)\" W " - "\\(([0-9]+\\.[0-9]+)mm x ([0-9]+\\.[0-9]+)mm\\)") # 0.260" L x 0.260" W (6.60mm x 6.60mm) -parsers: Mapping[int, Callable[[str], Any]] = { - 3: no_parser("tolerance"), - 1471: ee_val_parser("voltage-input-min"), # Voltage - Input (Min) - 573: ee_val_parser("voltage-input-max"), # Voltage - Input (Max) - 1429: ee_val_parser("voltage-output-max"), # Voltage - Output (Max) - 252: re_parser(_operating_temperature_re, [("temperature-min", 1), ("temperature-max", 2)]), - 1686: re_parser(_operating_temperature_re, [("temperature-junction-min", 1), ("temperature-junction-max", 2)]), - - 1500: re_parser(_height_seated_re, [("part-height", 2)]), - 884: re_parser(_land_size_re, [("land-size-x", 3), ("land-size-y", 4)]), - - 2049: ee_val_parser("capacitance"), - 2079: ee_val_parser("voltage-rating"), -} - - -def normalize_facts(in_path: Path, out_path: Path): - in_db = load_db(in_path) - out_parts = PartDb() - - for part in in_db.iterparts(): # type: types.Part - fact_list: types.FactList = part.factsProp - if fact_list is None: - continue - - in_facts: List[types.Fact] = fact_list.factProp - out_facts = [] - - for f in in_facts: - key = uris.parse_digikey_fact_key(f.keyProp) - - value = f.valueProp - - if value == "-": - continue - - parser = parsers.get(key) - - if parser is not None: - res = parser(value) - - if res is not None: - if isinstance(res, list): - results = res - else: - results = [res] - facts = [types.Fact(key=uris.make_fact_key(key), value=value) for key, value in results] - out_facts.extend(facts) - - part.factsProp.factProp = out_facts - out_parts.add_entry(part, True) - - print("Saving {} work parts".format(out_parts.size())) - save_db(out_path, out_parts, sort=True) diff --git a/src/ee/kicad/functions.py b/src/ee/kicad/functions.py index 2d8106a..c0d1780 100644 --- a/src/ee/kicad/functions.py +++ b/src/ee/kicad/functions.py @@ -39,6 +39,7 @@ def part_type_from_ref_type(ref_type): return uris.TRANSISTOR +# noinspection PyUnusedLocal def part_type_strategy(**kwargs): def on_part(part: Part) -> Part: pt = None @@ -62,6 +63,7 @@ def part_type_strategy(**kwargs): return on_part +# noinspection PyUnusedLocal def fix_value_strategy(**kwargs): def on_part(part: Part) -> Part: ref = part.get_only_schematic_reference() @@ -91,6 +93,7 @@ def fix_value_strategy(**kwargs): return on_part +# noinspection PyUnusedLocal def mpn_strategy(**kwargs): def on_part(part: Part) -> Part: for field in part.facts.all(sch_fact_types.field): @@ -104,6 +107,7 @@ def mpn_strategy(**kwargs): return on_part +# noinspection PyUnusedLocal def map_footprint(footprint_mappings=None, **kwargs): if footprint_mappings is None: return None diff --git a/src/ee/tools/digikey_normalize_facts.py b/src/ee/tools/digikey_normalize_facts.py deleted file mode 100644 index decf435..0000000 --- a/src/ee/tools/digikey_normalize_facts.py +++ /dev/null @@ -1,19 +0,0 @@ -import argparse -from pathlib import Path - -from ee.digikey.normalize_facts import normalize_facts - -parser = argparse.ArgumentParser() - -parser.add_argument("--in", - dest="in_", - required=True, - metavar="PART DB") - -parser.add_argument("--out", - required=True, - metavar="PART DB") - -args = parser.parse_args() - -normalize_facts(Path(args.in_), Path(args.out)) diff --git a/src/ee/tools/init.py b/src/ee/tools/init.py index 6d7908e..f77b60b 100644 --- a/src/ee/tools/init.py +++ b/src/ee/tools/init.py @@ -35,6 +35,12 @@ def init_kicad_project(basedir: Path, cfg, args): cfg["kicad-project"]["strategy"] = args.kicad_bom_strategy +def init_digikey(project: Project): + project.cfg.add_section("supplier:digikey") + + project.cfg["supplier:digikey"]["function"] = "ee.kicad.digikey.functions.default" + + def init_seeed_opl(project: Project): import ee.supplier.seeed ee.supplier.seeed.init_project(project) @@ -45,6 +51,7 @@ def init(project_dir: Path, basedir: Path, args): project = Project(project_dir, cfg) init_kicad_project(basedir, cfg, args) + init_digikey(project) init_seeed_opl(project) if args.create_bom_strategy: diff --git a/src/ee/tools/part_apply_function.py b/src/ee/tools/part_apply_function.py index af51b5a..b2c9585 100644 --- a/src/ee/tools/part_apply_function.py +++ b/src/ee/tools/part_apply_function.py @@ -72,15 +72,14 @@ parser.add_argument("--function", metavar="FUNCTION") parser.add_argument("--argument", - required=True, nargs="*", metavar="ARG") parser.add_argument("--execution", - default="default") + required=True) args = parser.parse_args() project = Project.load() report = project.report_dir / "apply-function" / (args.execution + ".rst") -work(Path(args.in_path), Path(args.out), report, args.function, args.argument) +work(Path(args.in_path), Path(args.out), report, args.function, args.argument or []) diff --git a/src/ee/tools/templates/build.ninja.j2 b/src/ee/tools/templates/build.ninja.j2 index 0aaa76f..cb98921 100644 --- a/src/ee/tools/templates/build.ninja.j2 +++ b/src/ee/tools/templates/build.ninja.j2 @@ -26,7 +26,7 @@ rule pn-part-search-list command = $ee pn-part-search-list --in $in --out $out --supplier $supplier rule part-apply-function - command = $ee part-apply-function --in $in --out $out $functions $arguments + command = $ee part-apply-function --execution $execution --in $in --out $out $functions $arguments rule part-find-requirements description = part-find-requirements @@ -39,18 +39,10 @@ rule digikey-search-parts description = digikey-search-parts command = $ee digikey-search-parts --in $in --out $out -rule digikey-normalize-facts - description = digikey-normalize-facts - command = $ee digikey-normalize-facts --in $in --out $out - rule element14-search-parts description = element14-search-parts command = $ee element14-search-parts --in $in --out $out -rule element14-normalize-facts - description = element14-normalize-facts - command = $ee element14-normalize-facts --in $in --out $out - rule create-bom description = create-bom command = $ee create-bom --schematic $schematic --part-db $part_dbs --out $out $strategy @@ -81,6 +73,7 @@ build {{ gerber_zip }}: kicad-gerber $pcb {% if sch is defined -%} build ee/kicad-sch.xml: kicad-make-bom $sch build ee/sch.xml: part-apply-function ee/kicad-sch.xml + execution = kicad {%- if project.cfg["kicad-project"]["functions"] %} functions = --function {{ project.cfg["kicad-project"]["functions"] }} {%- else %} @@ -89,7 +82,7 @@ build ee/sch.xml: part-apply-function ee/kicad-sch.xml {%- if project.cfg["kicad-project"]["function-arguments"] %} arguments = --argument {{ project.cfg["kicad-project"]["function-arguments"] }} {%- else %} - arguments = --argument "" + arguments = {%- endif %} {%- endif %} @@ -98,15 +91,23 @@ build $report_dir/part-validate-parts.rst: part-validate-parts ee/sch.xml build ee/requirements.xml: part-find-requirements ee/sch.xml {% for s in distributors %} +{%- set cfg = project.cfg["supplier:" + s] if "supplier:" + s in project.cfg else None %} # Supplier {{ s }} build ee/{{ s }}/pn-part-search-list.xml: pn-part-search-list ee/sch.xml supplier = {{ s }} build ee/{{ s }}/downloaded.xml | ee/{{ s }}/downloaded.rst: {{ s }}-search-parts ee/{{ s }}/pn-part-search-list.xml -build ee/{{ s }}/parts.xml: {{ s }}-normalize-facts ee/{{ s }}/downloaded.xml - -default ee/{{ s }}/parts.xml +build ee/{{ s }}/parts.xml: part-apply-function ee/{{ s }}/downloaded.xml + execution = {{ s }} +{%- if cfg and "functions" in cfg %} + functions = --function {{ cfg["functions"] }} +{%- else %} + functions = --function ee.{{ s }}.functions.default +{%- endif %} +{%- if cfg and "function-arguments" in cfg %} + arguments = --argument {{ cfg["function-arguments"] }} +{%- endif %} {%- endfor %} {%- for f in parts_yaml_files %} -- cgit v1.2.3