aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ee/kicad/bom/__init__.py77
-rw-r--r--src/ee/kicad/bom_tool/__init__.py110
-rw-r--r--src/ee/kicad/bom_tool/predef.py6
3 files changed, 188 insertions, 5 deletions
diff --git a/src/ee/kicad/bom/__init__.py b/src/ee/kicad/bom/__init__.py
index 1808357..d0798a4 100644
--- a/src/ee/kicad/bom/__init__.py
+++ b/src/ee/kicad/bom/__init__.py
@@ -1,10 +1,34 @@
+import re
+import sys
+
__all__ = [
'Part',
'Library',
'Bom',
'Comp',
+ 'split_ref',
]
+def split_ref(ref):
+ """Split "C12" into a tuple that's useful for sorting by component reference.
+
+ For example: "C12" => ("C", 12, None). "Cfoo" => ("C", sys.maxsize, "").
+ """
+ m = split_ref.r.match(ref)
+ if not m:
+ return (ref, sys.maxsize, "")
+ groups = m.groups()
+ ref = groups[0]
+ val = groups[1]
+ rest = groups[2]
+ try:
+ return (ref, int(val), rest)
+ except ValueError:
+ pass
+
+ return (ref, val, rest)
+split_ref.r = re.compile("([A-Za-z]+)([0-9]+)(.*)")
+
class Part:
def __init__(self, name):
self.name = name
@@ -22,19 +46,26 @@ class Library:
self.parts[part] = p
return p
-class Bom:
+class Bom(object):
def __init__(self):
self.libraries = {}
- self.components = {}
+ self._components = {}
def add_component(self, component):
- self.components[component.ref] = component
+ self._components[component.ref] = component
def get_component(self, name):
- return self.components[name]
+ return self._components[name]
def get_components(self):
- return self.components
+ return self._components
+
+ def all_field_names(self):
+ fields = set(['ref', 'value'])
+ for c in self._components.values():
+ for f in c.fields:
+ fields.add(f)
+ return fields
def find_library(self, name):
try:
@@ -44,6 +75,27 @@ class Bom:
self.libraries[name] = lib
return lib
+ def to_pandas(self, ref_field_name = None, value_field_name = None):
+ import pandas
+
+ ref_field_name = ref_field_name or "ref"
+ value_field_name = value_field_name or "value"
+
+ fields = self.all_field_names()
+ data = {k: [] for k in fields}
+ refs = []
+ values = []
+ for ref, c in self.get_components().items():
+ refs.append(c.ref)
+ values.append(c.value)
+ for field in fields:
+ data[field].append(c[field] if field in c else None)
+
+# del data[ref_field_name]
+ data[ref_field_name] = refs
+ data[value_field_name] = values
+ return pandas.DataFrame(data=data, index=refs)
+
class Comp:
def __init__(self, ref, value, library, part, footprint):
self.ref = ref
@@ -56,3 +108,18 @@ class Comp:
def add_field(self, key, value):
self.fields[key] = value
+ def __contains__(self, key):
+ if key == 'ref':
+ return self.ref is not None
+ elif key == 'value':
+ return self.value is not None
+ else:
+ return key in self.fields
+
+ def __getitem__(self, key):
+ if key == 'ref':
+ return self.ref
+ elif key == 'value':
+ return self.value
+ else:
+ return self.fields[key]
diff --git a/src/ee/kicad/bom_tool/__init__.py b/src/ee/kicad/bom_tool/__init__.py
new file mode 100644
index 0000000..9f450c9
--- /dev/null
+++ b/src/ee/kicad/bom_tool/__init__.py
@@ -0,0 +1,110 @@
+from ee.kicad.bom import *
+import functools
+import itertools
+import pandas as pd
+
+def _none_if_empty(l):
+ return l if l is not None and len(l) > 0 else None
+
+class Supplier():
+ def __init__(self, name, bom_field = None):
+ self._name = name
+ self._bom_field = bom_field if not None else name
+
+ @property
+ def bom_field(self):
+ return self._bom_field
+
+class Settings():
+ def __init__(self, suppliers = None, part_field = None):
+ self._suppliers = suppliers if suppliers is not None else []
+ self._part_field = part_field if part_field is not None else 'part'
+
+ @property
+ def suppliers(self):
+ return self._suppliers
+
+ @property
+ def part_field(self):
+ return self._part_field
+
+ @part_field.setter
+ def part_field(self, value):
+ self._part_field = value
+
+class CsvFormat():
+ def __init__(self, supplier = None, group_by_fields = None, required_fields = None):
+ self._supplier = supplier
+ self._group_by_fields = _none_if_empty(group_by_fields)
+ self._required_fields = _none_if_empty(required_fields)
+
+ @property
+ def supplier(self):
+ return self._supplier
+
+ @property
+ def group_by_fields(self):
+ return self._group_by_fields
+
+ @property
+ def required_fields(self):
+ return self._required_fields
+
+def _all(fs, c):
+ for f in fs:
+ if not f(c):
+ return False
+ return True
+
+def to_panda(bom, bom_settings, csv_format): # type: (Bom, BomSettings, CsvFormat) -> None
+ filters = []
+
+ print("csv_format.supplier.bom_field={}".format(csv_format.supplier.bom_field))
+ if csv_format.supplier is not None:
+ filters.append(lambda c: csv_format.supplier.bom_field in c)
+
+ if csv_format.group_by_fields is not None:
+ filters.append(lambda c: all([field in c for field in csv_format.group_by_fields]))
+
+ if csv_format.required_fields is not None:
+ filters.append(lambda c: all([field in c for field in csv_format.required_fields]))
+
+ f = functools.partial(_all, filters)
+ print("len(filters)={}".format(len(filters)))
+ print("len(bom.get_components())={}".format(len(bom.get_components())))
+
+ filtered = [c for ref, c in bom.get_components().items() if f(c)]
+ print("filtered:, len={}".format(len(filtered)))
+ filtered.sort(key=lambda c: c.ref)
+ print("sorted filtered:, len={}".format(len(filtered)))
+
+ counts=None
+ parts=[]
+
+ frame = {}
+ for n in bom.all_field_names():
+ frame[n] = []
+
+ if csv_format.group_by_fields is not None:
+ counts, parts, refs=([],[],[])
+ for group, comps in itertools.groupby(filtered, key=lambda c: [field for field in c for c in csv_format.group_by_fields]):
+ gs = list(group)
+ cs = list(comps)
+# counts.append(len(cs))
+# dpns.append(part)
+# mpns.append(part)
+# refs.append(functools.reduce(lambda a, b: a + ' ' + b, [c.ref for c in cs], ''))
+ print("group={}".format(gs))
+
+# return pd.DataFrame(data={
+# 'count': counts,
+# 'mpn': mpns,
+# 'dpn': dpns,
+# 'refs': refs,
+# })
+ else:
+ for ref, c in filtered:
+ for key, value in c:
+ frame[key] = value
+
+ return pd.DataFrame(data=frame)
diff --git a/src/ee/kicad/bom_tool/predef.py b/src/ee/kicad/bom_tool/predef.py
new file mode 100644
index 0000000..717f6d3
--- /dev/null
+++ b/src/ee/kicad/bom_tool/predef.py
@@ -0,0 +1,6 @@
+from ee.kicad.bom_tool import *
+
+digikey = Supplier('Digi-Key', bom_field = 'digikey')
+
+def digikeyCsvFormat(digikey_supplier):
+ return CsvFormat(supplier = digikey, group_by_fields = [digikey_supplier.bom_field])