Skip to content

Instantly share code, notes, and snippets.

@pwuertz
Created February 7, 2017 16:05
Show Gist options
  • Save pwuertz/a8af404a975638371cd1165dec1c3872 to your computer and use it in GitHub Desktop.
Save pwuertz/a8af404a975638371cd1165dec1c3872 to your computer and use it in GitHub Desktop.
#!/usr/bin/python
import sys
import re
import csv
import collections
import xml.etree.ElementTree
def natural_sort(l):
"""
Natural sort for strings containing numbers
"""
convert = lambda text: int(text) if text.isdigit() else text.lower()
alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
return sorted(l, key=alphanum_key)
def generate_bom_table(fname):
"""
Generate BOM from KiCad XML file.
"""
xml_root = xml.etree.ElementTree.parse(fname).getroot()
# xml_root = xml.etree.ElementTree.fromstring(s)
# first pass, get field names
field_names = set()
for field in xml_root.findall("./components/comp/fields/field"):
field_names.add(field.get("name"))
field_names = list(field_names)
# second pass, group parts with identical (value, footprint, fields...)
part_groups = collections.OrderedDict()
for comp in xml_root.findall("./components/comp"):
# build attribute list for comp
fields = dict([(f.get("name"), f.text) for f in comp.findall("fields/field")])
fields_ordered = [fields.get(n, "") for n in field_names]
attr = tuple([comp.findtext("value"), comp.findtext("footprint")] + fields_ordered)
# store to part groups and refs
reference = comp.get("ref")
group_refs = part_groups.get(attr, [])
group_refs.append(reference)
part_groups[attr] = group_refs
bom_header = ["Qty", "Value", "Footprint", "Refs"] + field_names
bom_table = []
for attr, refs in part_groups.items():
value, footprint = attr[:2]
fields = list(attr[2:])
refs_str = ", ".join(natural_sort(refs))
line = tuple([len(refs), value, footprint, refs_str] + fields)
bom_table.append(line)
return bom_table, bom_header
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description='KiCad BOM export')
parser.add_argument('file', type=str, help="KiCad BOM XML")
args = parser.parse_args()
# generate BOM table
bom_table, bom_header = generate_bom_table(args.file)
# write BOM table to CSV
csv_writer = csv.writer(sys.stdout)
csv_writer.writerow(bom_header)
for row in bom_table:
csv_writer.writerow(row)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment