Moved some repeated code in BoM writers.

All the writers computed some stats. Now they are computed in one place
avoiding repetition.
This commit is contained in:
Salvador E. Tropea 2020-08-01 16:55:33 -03:00
parent 670e379f65
commit 64576e3975
7 changed files with 42 additions and 50 deletions

View File

@ -32,6 +32,11 @@ def write_bom(filename, ext, groups, headings, cfg):
# Allow renaming the columns
head_names = [h if h.lower() not in cfg.column_rename else cfg.column_rename[h.lower()] for h in headings]
result = False
# Some stats
cfg.n_groups = len(groups)
cfg.n_total = sum([g.get_count() for g in groups])
cfg.n_fitted = sum([g.get_count() for g in groups if g.is_fitted()])
cfg.n_build = cfg.n_fitted * cfg.number
# CSV file writing
if ext in ["csv", "tsv", "txt"]:
result = write_csv(filename, ext, groups, headings, head_names, cfg)

View File

@ -27,11 +27,6 @@ def write_csv(filename, ext, groups, headings, head_names, cfg):
elif ext == "tsv" or ext == "txt":
delimiter = "\t"
n_groups = len(groups)
n_total = sum([g.get_count() for g in groups])
n_fitted = sum([g.get_count() for g in groups if g.is_fitted()])
n_build = n_fitted * cfg.number
with open(filename, "wt") as f:
writer = csv.writer(f, delimiter=delimiter, lineterminator="\n")
# Headers
@ -63,11 +58,11 @@ def write_csv(filename, ext, groups, headings, head_names, cfg):
for i in range(5):
writer.writerow([])
writer.writerow(["Component Groups:", n_groups])
writer.writerow(["Component Count:", n_total])
writer.writerow(["Fitted Components:", n_fitted])
writer.writerow(["Component Groups:", cfg.n_groups])
writer.writerow(["Component Count:", cfg.n_total])
writer.writerow(["Fitted Components:", cfg.n_fitted])
writer.writerow(["Number of PCBs:", cfg.number])
writer.writerow(["Total components:", n_build])
writer.writerow(["Total components:", cfg.n_build])
writer.writerow(["Schematic Revision:", cfg.revision])
writer.writerow(["Schematic Date:", cfg.date])
writer.writerow(["PCB Variant:", ' + '.join(cfg.variant)])

View File

@ -84,11 +84,6 @@ def write_html(filename, groups, headings, head_names, cfg):
head_names = [list of headings to display in the BoM file]
prefs = BomPref object
"""
n_groups = len(groups)
n_total = sum([g.get_count() for g in groups])
n_fitted = sum([g.get_count() for g in groups if g.is_fitted()])
n_build = n_fitted * cfg.number
link_datasheet = cfg.datasheet_as_link
link_digikey = None
if cfg.digikey_link:
@ -107,18 +102,18 @@ def write_html(filename, groups, headings, head_names, cfg):
html.write("<h2>KiBoM PCB Bill of Materials</h2>\n")
if not cfg.hide_pcb_info:
html.write('<table border="1">\n')
html.write("<tr><td>Source File</td><td>{source}</td></tr>\n".format(source=cfg.source))
html.write("<tr><td>Source File</td><td>{}</td></tr>\n".format(cfg.source))
# html.write("<tr><td>BoM Date</td><td>{date}</td></tr>\n".format(date=cfg.date)) Same as schematic
html.write("<tr><td>Schematic Revision</td><td>{version}</td></tr>\n".format(version=cfg.revision))
html.write("<tr><td>Schematic Date</td><td>{date}</td></tr>\n".format(date=cfg.date))
html.write("<tr><td>PCB Variant</td><td>{variant}</td></tr>\n".format(variant=', '.join(cfg.variant)))
html.write("<tr><td>Schematic Revision</td><td>{}</td></tr>\n".format(cfg.revision))
html.write("<tr><td>Schematic Date</td><td>{}</td></tr>\n".format(cfg.date))
html.write("<tr><td>PCB Variant</td><td>{}</td></tr>\n".format(', '.join(cfg.variant)))
# html.write("<tr><td>KiCad Version</td><td>{version}</td></tr>\n".format(version=net.getTool())) TODO?
html.write("<tr><td>Component Groups</td><td>{n}</td></tr>\n".format(n=n_groups))
html.write("<tr><td>Component Count (per PCB)</td><td>{n}</td></tr>\n".format(n=n_total))
html.write("<tr><td>Fitted Components (per PCB)</td><td>{n}</td></tr>\n".format(n=n_fitted))
html.write("<tr><td>Number of PCBs</td><td>{n}</td></tr>\n".format(n=cfg.number))
html.write("<tr><td>Component Groups</td><td>{}</td></tr>\n".format(cfg.n_groups))
html.write("<tr><td>Component Count (per PCB)</td><td>{}</td></tr>\n".format(cfg.n_total))
html.write("<tr><td>Fitted Components (per PCB)</td><td>{}</td></tr>\n".format(cfg.n_fitted))
html.write("<tr><td>Number of PCBs</td><td>{}</td></tr>\n".format(cfg.number))
html.write("<tr><td>Total Component Count<br>(for {n} PCBs)</td><td>{t}</td></tr>\n".
format(n=cfg.number, t=n_build))
format(n=cfg.number, t=cfg.n_build))
html.write("</table>\n")
html.write("<br>\n")

View File

@ -65,11 +65,6 @@ def write_xlsx(filename, groups, col_fields, head_names, cfg):
logger.error('Python xlsxwriter module not installed (Debian: python3-xlsxwriter)')
return False
n_groups = len(groups)
n_total = sum([g.get_count() for g in groups])
n_fitted = sum([g.get_count() for g in groups if g.is_fitted()])
n_build = n_fitted * cfg.number
workbook = Workbook(filename)
worksheet = workbook.add_worksheet()
@ -136,11 +131,11 @@ def write_xlsx(filename, groups, col_fields, head_names, cfg):
title_fmt.set_bold()
formats = [title_fmt, cellformat_left]
row_count = add_info(worksheet, column_widths, row_count, formats, "Component Groups:", n_groups)
row_count = add_info(worksheet, column_widths, row_count, formats, "Component Count:", n_total)
row_count = add_info(worksheet, column_widths, row_count, formats, "Fitted Components:", n_fitted)
row_count = add_info(worksheet, column_widths, row_count, formats, "Component Groups:", cfg.n_groups)
row_count = add_info(worksheet, column_widths, row_count, formats, "Component Count:", cfg.n_total)
row_count = add_info(worksheet, column_widths, row_count, formats, "Fitted Components:", cfg.n_fitted)
row_count = add_info(worksheet, column_widths, row_count, formats, "Number of PCBs:", cfg.number)
row_count = add_info(worksheet, column_widths, row_count, formats, "Total components:", n_build)
row_count = add_info(worksheet, column_widths, row_count, formats, "Total components:", cfg.n_build)
row_count = add_info(worksheet, column_widths, row_count, formats, "Schematic Revision:", cfg.revision)
row_count = add_info(worksheet, column_widths, row_count, formats, "Schematic Date:", cfg.date)
# row_count = add_info(worksheet, column_widths, row_count, formats, "BoM Date:", cfg.date) Same as sch

View File

@ -17,11 +17,6 @@ def write_xml(filename, groups, headings, head_names, cfg):
headings = [list of headings to display in the BoM file]
cfg = BomPref object
"""
n_groups = len(groups)
n_total = sum([g.get_count() for g in groups])
n_fitted = sum([g.get_count() for g in groups if g.is_fitted()])
n_build = n_fitted * cfg.number
attrib = {}
attrib['Schematic_Source'] = cfg.source
attrib['Schematic_Revision'] = cfg.revision
@ -29,11 +24,11 @@ def write_xml(filename, groups, headings, head_names, cfg):
attrib['PCB_Variant'] = ', '.join(cfg.variant)
# attrib['BOM_Date'] = net.getDate() same as schematic
# attrib['KiCad_Version'] = net.getTool() TODO?
attrib['Component_Groups'] = str(n_groups)
attrib['Component_Count'] = str(n_total)
attrib['Fitted_Components'] = str(n_fitted)
attrib['Component_Groups'] = str(cfg.n_groups)
attrib['Component_Count'] = str(cfg.n_total)
attrib['Fitted_Components'] = str(cfg.n_fitted)
attrib['Number_of_PCBs'] = str(cfg.number)
attrib['Total_Components'] = str(n_build)
attrib['Total_Components'] = str(cfg.n_build)
xml = ElementTree.Element('KiCad_BOM', attrib=attrib, encoding='utf-8')
for group in groups:

View File

@ -1,5 +1,9 @@
"""
KiCad configuration classes.
Notes about coverage:
I'm excluding all the Darwin and Windows code from coverage.
I don't know how to test it on GitHub CI/CD.
"""
import os
import re
@ -14,7 +18,8 @@ from .. import log
# Check python version to determine which version of ConfirParser to import
if sys.version_info.major >= 3:
import configparser as ConfigParser
else:
else: # pragma: no cover
# For future Python 2 support
import ConfigParser
logger = log.get_logger(__name__)
@ -71,10 +76,10 @@ class LibAlias(object):
lib.descr = un_quote(m.group(5))
return lib
def __str__(self):
if not self.name:
return 'empty LibAlias'
return self.name+' -> `'+self.uri+'`'
# def __str__(self):
# if not self.name:
# return 'empty LibAlias'
# return self.name+' -> `'+self.uri+'`'
class KiConf(object):
@ -125,7 +130,7 @@ class KiConf(object):
cfg = os.path.join(home, '.config', 'kicad', KICAD_COMMON)
if os.path.isfile(cfg):
return cfg
elif system == 'Darwin':
elif system == 'Darwin': # pragma: no cover
# MacOSX: ~/Library/Preferences/kicad/
home = os.environ.get('HOME')
if not home:
@ -134,7 +139,7 @@ class KiConf(object):
cfg = os.path.join(home, 'Library', 'Preferences', 'kicad', KICAD_COMMON)
if os.path.isfile(cfg):
return cfg
elif system == 'Windows':
elif system == 'Windows': # pragma: no cover
# Windows: C:\Users\username\AppData\Roaming\kicad
# or C:\Documents and Settings\username\Application Data\kicad
username = os.environ.get('username')
@ -173,7 +178,7 @@ class KiConf(object):
dir = os.path.join(sysconfig.get_path('data', 'posix_prefix'), share)
if os.path.isdir(dir):
return dir
elif system == 'Darwin':
elif system == 'Darwin': # pragma: no cover
app_data = os.path.join('Library', 'Application Support', 'kicad', 'library')
home = os.environ.get('HOME')
if home:
@ -183,7 +188,7 @@ class KiConf(object):
dir = os.path.join('/', app_data)
if os.path.isdir(dir):
return dir
elif system == 'Windows':
elif system == 'Windows': # pragma: no cover
dir = os.path.join('C:', 'Program Files', 'KiCad', share)
if os.path.isdir(dir):
return dir

View File

@ -262,6 +262,8 @@ class BoM(BaseOutput): # noqa: F821
Used to generate the BoM in CSV, HTML, TSV, TXT, XML or XLSX format using the internal BoM.
Is compatible with KiBoM, but doesn't need to update the XML netlist because the components
are loaded from the schematic.
Important differences with KiBoM output:
- All options are in the main `options` section, not in `conf` subsection.
This output is what you get from the 'Tools/Generate Bill of Materials' menu in eeschema. """
def __init__(self):
super().__init__()