aboutsummaryrefslogtreecommitdiff
path: root/src/ee/kicad
diff options
context:
space:
mode:
Diffstat (limited to 'src/ee/kicad')
-rw-r--r--src/ee/kicad/bom/__init__.py221
-rw-r--r--src/ee/kicad/bom/io.py81
-rw-r--r--src/ee/kicad/bom_tool/__init__.py185
-rw-r--r--src/ee/kicad/bom_tool/predef.py5
4 files changed, 254 insertions, 238 deletions
diff --git a/src/ee/kicad/bom/__init__.py b/src/ee/kicad/bom/__init__.py
index d0798a4..2a32521 100644
--- a/src/ee/kicad/bom/__init__.py
+++ b/src/ee/kicad/bom/__init__.py
@@ -2,124 +2,131 @@ import re
import sys
__all__ = [
- 'Part',
- 'Library',
- 'Bom',
- 'Comp',
- 'split_ref',
+ '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]+)(.*)")
+ """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
-class Part:
- def __init__(self, name):
- self.name = name
+ return (ref, val, rest)
-class Library:
- def __init__(self, name):
- self.name = name
- self.parts = {}
- def add_part(self, part):
- try:
- return self.parts[part]
- except KeyError:
- p = Part(part)
- self.parts[part] = p
- return p
+split_ref.r = re.compile("([A-Za-z]+)([0-9]+)(.*)")
-class Bom(object):
- def __init__(self):
- self.libraries = {}
- self._components = {}
- def add_component(self, component):
- self._components[component.ref] = component
+class Part:
+ def __init__(self, name):
+ self.name = name
- def get_component(self, name):
- return self._components[name]
- def get_components(self):
- return self._components
+class Library:
+ def __init__(self, name):
+ self.name = name
+ self.parts = {}
- 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 add_part(self, part):
+ try:
+ return self.parts[part]
+ except KeyError:
+ p = Part(part)
+ self.parts[part] = p
+ return p
+
+
+class Bom(object):
+ def __init__(self):
+ self.libraries = {}
+ self._components = {}
+
+ def add_component(self, component):
+ self._components[component.ref] = component
+
+ def get_component(self, name):
+ return self._components[name]
+
+ def get_components(self):
+ 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:
+ return self.libraries[name]
+ except KeyError:
+ lib = Library(name)
+ 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)
- def find_library(self, name):
- try:
- return self.libraries[name]
- except KeyError:
- lib = Library(name)
- 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
- self.value = value
- self.footprint = footprint
- self.library = library
- self.part = part
- self.fields = {}
-
- 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]
+ def __init__(self, ref, value, library, part, footprint):
+ self.ref = ref
+ self.value = value
+ self.footprint = footprint
+ self.library = library
+ self.part = part
+ self.fields = {}
+
+ 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/io.py b/src/ee/kicad/bom/io.py
index c7eef44..d7c0367 100644
--- a/src/ee/kicad/bom/io.py
+++ b/src/ee/kicad/bom/io.py
@@ -1,44 +1,45 @@
import xml.etree.ElementTree as ElementTree
from ee.kicad.bom import *
+
def read_bom(path):
- def child_text(e, child_tag):
- child = e.find(child_tag)
-
- return child.text if child is not None else None
-
- def add_comp(b, comp):
- ref = comp.get("ref")
- value = child_text(comp, "value")
- footprint = child_text(comp, "footprint")
- libsource = comp.find("libsource")
- l, p = (None, None)
- if libsource is not None:
- lib = libsource.get("lib")
- part = libsource.get("part")
- if lib is not None and part is not None:
- l = b.find_library(lib)
- p = l.add_part(part)
-
- c = Comp(ref, value, l, p, footprint)
-
- fields = comp.find("fields")
- if fields is not None:
- for f in fields.findall("field"):
- key = f.get("name")
- value = f.text
- c.add_field(key, value)
-
- b.add_component(c)
- return c
-
- with open(path) as f:
- tree = ElementTree.parse(path)
- root = tree.getroot()
-
- b = Bom()
- comp = root.find("components").findall("comp")
- for c in comp:
- add_comp(b, c)
-
- return b
+ def child_text(e, child_tag):
+ child = e.find(child_tag)
+
+ return child.text if child is not None else None
+
+ def add_comp(b, comp):
+ ref = comp.get("ref")
+ value = child_text(comp, "value")
+ footprint = child_text(comp, "footprint")
+ libsource = comp.find("libsource")
+ l, p = (None, None)
+ if libsource is not None:
+ lib = libsource.get("lib")
+ part = libsource.get("part")
+ if lib is not None and part is not None:
+ l = b.find_library(lib)
+ p = l.add_part(part)
+
+ c = Comp(ref, value, l, p, footprint)
+
+ fields = comp.find("fields")
+ if fields is not None:
+ for f in fields.findall("field"):
+ key = f.get("name")
+ value = f.text
+ c.add_field(key, value)
+
+ b.add_component(c)
+ return c
+
+ with open(path) as f:
+ tree = ElementTree.parse(path)
+ root = tree.getroot()
+
+ b = Bom()
+ comp = root.find("components").findall("comp")
+ for c in comp:
+ add_comp(b, c)
+
+ return b
diff --git a/src/ee/kicad/bom_tool/__init__.py b/src/ee/kicad/bom_tool/__init__.py
index 9f450c9..f5d2e4f 100644
--- a/src/ee/kicad/bom_tool/__init__.py
+++ b/src/ee/kicad/bom_tool/__init__.py
@@ -3,108 +3,115 @@ 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
+ 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
+ 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
- @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'
+ 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 suppliers(self):
+ return self._suppliers
- @property
- def part_field(self):
- return self._part_field
+ @property
+ def part_field(self):
+ return self._part_field
+
+ @part_field.setter
+ def part_field(self, value):
+ self._part_field = value
- @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)
+ 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 supplier(self):
- return self._supplier
+ @property
+ def group_by_fields(self):
+ return self._group_by_fields
- @property
- def group_by_fields(self):
- return self._group_by_fields
+ @property
+ def required_fields(self):
+ return self._required_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)
+ 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
index 717f6d3..bfe8631 100644
--- a/src/ee/kicad/bom_tool/predef.py
+++ b/src/ee/kicad/bom_tool/predef.py
@@ -1,6 +1,7 @@
from ee.kicad.bom_tool import *
-digikey = Supplier('Digi-Key', bom_field = 'digikey')
+digikey = Supplier('Digi-Key', bom_field='digikey')
+
def digikeyCsvFormat(digikey_supplier):
- return CsvFormat(supplier = digikey, group_by_fields = [digikey_supplier.bom_field])
+ return CsvFormat(supplier=digikey, group_by_fields=[digikey_supplier.bom_field])