aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ee/kicad/functions.py128
-rw-r--r--src/ee/part/__init__.py3
-rw-r--r--src/ee/part/common_fact_types.py4
-rw-r--r--src/ee/part/fact_keys.py1
-rw-r--r--src/ee/tools/init.py3
-rw-r--r--src/ee/tools/part_apply_function.py29
-rw-r--r--src/ee/tools/part_validate_parts.py104
-rw-r--r--src/ee/tools/templates/build.ninja.j212
8 files changed, 240 insertions, 44 deletions
diff --git a/src/ee/kicad/functions.py b/src/ee/kicad/functions.py
index 39614b6..2d8106a 100644
--- a/src/ee/kicad/functions.py
+++ b/src/ee/kicad/functions.py
@@ -1,7 +1,10 @@
import re
+import yaml
+
import ee.kicad.model
import ee.kicad.sch_fact_types as kicad_ft
+from ee import EeException
from ee.kicad import sch_fact_types
from ee.part import Part
from ee.part import common_fact_types
@@ -36,70 +39,121 @@ def part_type_from_ref_type(ref_type):
return uris.TRANSISTOR
-def part_type_strategy(part: Part) -> Part:
- pt = None
+def part_type_strategy(**kwargs):
+ def on_part(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)
- fp_lib = part.facts.get_value(kicad_ft.footprint_library)
- if fp_lib is not None:
- pt = part_type_from_footprint(fp_lib)
+ 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
+
+ return on_part
+
+
+def fix_value_strategy(**kwargs):
+ def on_part(part: Part) -> Part:
+ ref = part.get_only_schematic_reference()
+
+ if not ref:
+ return part
- 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 not ref_num:
+ return part
- if pt is not None:
- part.facts.add(common_fact_types.ee_component_type, pt)
+ v = part.facts.get_value(sch_fact_types.value)
+ if not v:
+ return part
- 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"))
-def fix_value_strategy(part: Part) -> Part:
- ref = part.get_only_schematic_reference()
+ 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"))
- if not ref:
return part
- ref_type, ref_num = ee.kicad.model.split_ref(ref.referenceProp)
+ return on_part
- if not ref_num:
- return part
- v = part.facts.get_value(sch_fact_types.value)
- if not v:
+def mpn_strategy(**kwargs):
+ def on_part(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
- symbol_name = part.facts.get_value(sch_fact_types.symbol_name)
+ return on_part
+
- if ref_type in ("D", "R", "L", "C") and v == symbol_name:
- part.remove_fact(uris.make_fact_key("value"))
+def map_footprint(footprint_mappings=None, **kwargs):
+ if footprint_mappings is None:
+ return None
- 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"))
+ mappings = {}
+ with open(footprint_mappings, "r") as f:
+ doc = yaml.load(f, Loader=yaml.SafeLoader)
+ if not isinstance(doc, dict):
+ raise EeException("The footprint mappings document must be a dict.")
- return part
+ if "kicad-to-common" not in doc:
+ raise EeException("The footprint mappings document must contain the key 'kicad-to-common'.")
+ for k, v in doc["kicad-to-common"].items():
+ if not isinstance(v, str):
+ raise EeException("Bad value for key {}, must be a string".format(k))
-def mpn_strategy(part: Part) -> Part:
- for field in part.facts.all(sch_fact_types.field):
+ mappings[k] = v
- k, v = re.split(":", field.value, 1)
- if k == "mpn":
- part.add_mpn(v)
+ def on_part(part: Part) -> Part:
+ kicad_footprint = part.facts.get_value(kicad_ft.footprint)
- return part
+ if not kicad_footprint:
+ return part
+ footprint = mappings.get(kicad_footprint, None)
+
+ if footprint:
+ part.facts.add(common_fact_types.footprint, footprint)
+
+ return part
-def default(part: Part) -> Part:
- functions = [
+ return on_part
+
+
+def default(**kwargs):
+ function_factories = [
fix_value_strategy,
mpn_strategy,
part_type_strategy,
+ map_footprint,
]
- for f in functions:
- part = f(part)
+ 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 part
+ return on_part
diff --git a/src/ee/part/__init__.py b/src/ee/part/__init__.py
index a2face8..3ce255e 100644
--- a/src/ee/part/__init__.py
+++ b/src/ee/part/__init__.py
@@ -375,6 +375,9 @@ class Facts(object):
k = self._get_key(key)
return next((f.valueProp for f in self.part.get_facts() if f.keyProp == k), None)
+ def get_values(self, *keys: Union[str, FactType]) -> List[Optional[str]]:
+ return [self.get_value(key) for key in keys]
+
class Entry(object):
def __init__(self, new: bool, part: types.Part):
diff --git a/src/ee/part/common_fact_types.py b/src/ee/part/common_fact_types.py
index 12c099e..10ba1eb 100644
--- a/src/ee/part/common_fact_types.py
+++ b/src/ee/part/common_fact_types.py
@@ -1,5 +1,7 @@
import ee
-from ee.part import EeValueFactType, fact_keys
+from ee.part import EeValueFactType, fact_keys, FactType
+
+footprint = FactType(fact_keys.footprint, "Footprint")
resistance = EeValueFactType(fact_keys.resistance, "Resistance", ee.resistance_type)
capacitance = EeValueFactType(fact_keys.capacitance, "Capacitance", ee.capacitance_type)
diff --git a/src/ee/part/fact_keys.py b/src/ee/part/fact_keys.py
index 65dc699..9617b9c 100644
--- a/src/ee/part/fact_keys.py
+++ b/src/ee/part/fact_keys.py
@@ -14,3 +14,4 @@ place_part = "http://purl.org/ee/fact-type/place-part"
imperial_footprint_size = "http://purl.org/ee/fact-type/imperial-footprint-size"
part_class = "http://purl.org/ee/fact-type/part-class"
+footprint = "http://purl.org/ee/fact-type/footprint"
diff --git a/src/ee/tools/init.py b/src/ee/tools/init.py
index 156d1b7..6d7908e 100644
--- a/src/ee/tools/init.py
+++ b/src/ee/tools/init.py
@@ -25,6 +25,9 @@ def init_kicad_project(basedir: Path, cfg, args):
if pcb_file.is_file():
cfg["kicad-project"]["pcb"] = str(pcb_file)
+
+ cfg["kicad-project"]["functions"] = "ee.kicad.functions.default"
+ cfg["kicad-project"]["function-arguments"] = ""
else:
print("Found more than one kicad project file.")
diff --git a/src/ee/tools/part_apply_function.py b/src/ee/tools/part_apply_function.py
index bece364..af51b5a 100644
--- a/src/ee/tools/part_apply_function.py
+++ b/src/ee/tools/part_apply_function.py
@@ -4,7 +4,7 @@ from pathlib import Path
from typing import List
from ee import tools, EeException
-from ee.part import Part, PartDb, load_db, save_db
+from ee.part import Part, load_db, save_db
from ee.project import Project
@@ -23,15 +23,29 @@ def load_functions(function_names):
return functions
-def work(in_path: Path, out_path: Path, report_path: Path, function_names: List[str]):
- functions = load_functions(function_names)
+def work(in_path: Path, out_path: Path, report_path: Path, function_names: List[str], arguments: List[str]):
+ factories = load_functions(function_names)
in_parts = load_db(in_path)
- parts = PartDb()
+ kwargs = {}
+ for a in arguments:
+ import re
+ k, v = re.split(":", a, maxsplit=1)
+ kwargs[k] = v
+
+ functions = [[factory[0], factory[1](**kwargs)] for factory in factories]
tools.mk_parents(report_path)
with report_path.open("w") as rpt:
+
+ if len(kwargs):
+ print("Arguments:", file=rpt)
+ print("", file=rpt)
+ for key in sorted(kwargs):
+ print(" * {}={}".format(key, kwargs[key]), file=rpt)
+ print("", file=rpt)
+
for xml in in_parts.iterparts():
part = Part(xml)
@@ -57,6 +71,11 @@ parser.add_argument("--function",
nargs="*",
metavar="FUNCTION")
+parser.add_argument("--argument",
+ required=True,
+ nargs="*",
+ metavar="ARG")
+
parser.add_argument("--execution",
default="default")
@@ -64,4 +83,4 @@ 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)
+work(Path(args.in_path), Path(args.out), report, args.function, args.argument)
diff --git a/src/ee/tools/part_validate_parts.py b/src/ee/tools/part_validate_parts.py
new file mode 100644
index 0000000..897b0bf
--- /dev/null
+++ b/src/ee/tools/part_validate_parts.py
@@ -0,0 +1,104 @@
+import argparse
+from pathlib import Path
+
+from ee.part import Part, load_db, common_fact_types
+
+
+class Messages(object):
+ INFO = 1
+ WARNING = 2
+ ERROR = 3
+
+ def __init__(self):
+ self.messages = []
+
+ def error(self, msg):
+ self.messages.append((Messages.ERROR, msg))
+ return self
+
+ def warning(self, msg):
+ self.messages.append((Messages.WARNING, msg))
+ return self
+
+ def info(self, msg):
+ self.messages.append((Messages.INFO, msg))
+ return self
+
+ @property
+ def errors(self):
+ return [m[1] for m in self.messages if m[0] == Messages.ERROR]
+
+ @property
+ def warnings(self):
+ return [m[1] for m in self.messages if m[0] == Messages.WARNING]
+
+ @property
+ def infos(self):
+ return [m[1] for m in self.messages if m[0] == Messages.INFO]
+
+ def __len__(self):
+ return self.messages.__len__()
+
+ def append(self, messages: "Messages"):
+ 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
+
+ return Messages().warning("No footprint set")
+
+
+def validate(f, part: Part):
+ validators = [
+ check_has_footprint
+ ]
+
+ messages = Messages()
+ for validator in validators:
+ m = validator(part)
+ if m:
+ messages.append(m)
+
+ print("{}".format(part.printable_reference), file=f)
+ print("{}".format("=" * len(part.printable_reference)), file=f)
+ print("", file=f)
+
+ for msg in messages.errors:
+ print("* ERROR: {}".format(msg), file=f)
+ for msg in messages.warnings:
+ print("* WARNING: {}".format(msg), file=f)
+ for msg in messages.infos:
+ print("* INFO: {}".format(msg), file=f)
+
+ if len(messages) == 0:
+ print("No issues found", file=f)
+ print("", file=f)
+
+
+def work(in_path: Path, out_path: Path):
+ in_parts = load_db(in_path)
+
+ with out_path.open("w") as f:
+ for xml in in_parts.iterparts():
+ part = Part(xml)
+
+ validate(f, part)
+
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument("--in",
+ dest="in_path",
+ required=True,
+ metavar="PART DB")
+
+parser.add_argument("--out",
+ required=True,
+ metavar="REQUIREMENTS")
+
+args = parser.parse_args()
+
+work(Path(args.in_path), Path(args.out))
diff --git a/src/ee/tools/templates/build.ninja.j2 b/src/ee/tools/templates/build.ninja.j2
index 1f9ba35..0aaa76f 100644
--- a/src/ee/tools/templates/build.ninja.j2
+++ b/src/ee/tools/templates/build.ninja.j2
@@ -26,12 +26,15 @@ 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
+ command = $ee part-apply-function --in $in --out $out $functions $arguments
rule part-find-requirements
description = part-find-requirements
command = $ee part-find-requirements --in $in --out $out
+rule part-validate-parts
+ command = $ee part-validate-parts --in $in --out $out
+
rule digikey-search-parts
description = digikey-search-parts
command = $ee digikey-search-parts --in $in --out $out
@@ -83,8 +86,15 @@ build ee/sch.xml: part-apply-function ee/kicad-sch.xml
{%- else %}
functions = --function ee.kicad.functions.default
{%- endif %}
+{%- if project.cfg["kicad-project"]["function-arguments"] %}
+ arguments = --argument {{ project.cfg["kicad-project"]["function-arguments"] }}
+{%- else %}
+ arguments = --argument ""
+{%- endif %}
{%- endif %}
+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 %}