* Added option to hide file headers

* Changed output to be a positional argument (required)
* Added blank cell coloring to HTML output
This commit is contained in:
Oliver 2016-06-14 20:07:47 +10:00
parent 13ad8dbd3c
commit 159f54347c
4 changed files with 81 additions and 59 deletions

View File

@ -36,10 +36,11 @@ def WriteCSV(filename, groups, net, headings, prefs):
writer = csv.writer(f, delimiter=delimiter, lineterminator="\n") writer = csv.writer(f, delimiter=delimiter, lineterminator="\n")
if prefs.numberRows: if not prefs.hideHeaders:
writer.writerow(["Component"] + headings) if prefs.numberRows:
else: writer.writerow(["Component"] + headings)
writer.writerow(headings) else:
writer.writerow(headings)
count = 0 count = 0
rowCount = 1 rowCount = 1
@ -63,19 +64,20 @@ def WriteCSV(filename, groups, net, headings, prefs):
rowCount += 1 rowCount += 1
#blank rows if not prefs.hideHeaders:
for i in range(5): #blank rows
writer.writerow([]) for i in range(5):
writer.writerow([])
writer.writerow(["Component Groups:",nGroups])
writer.writerow(["Component Count:",nTotal]) writer.writerow(["Component Groups:",nGroups])
writer.writerow(["Fitted Components:", nFitted]) writer.writerow(["Component Count:",nTotal])
writer.writerow(["Number of PCBs:",prefs.boards]) writer.writerow(["Fitted Components:", nFitted])
writer.writerow(["Total components:", nBuild]) writer.writerow(["Number of PCBs:",prefs.boards])
writer.writerow(["Schematic Version:",net.getVersion()]) writer.writerow(["Total components:", nBuild])
writer.writerow(["Schematic Date:",net.getSheetDate()]) writer.writerow(["Schematic Version:",net.getVersion()])
writer.writerow(["BoM Date:",net.getDate()]) writer.writerow(["Schematic Date:",net.getSheetDate()])
writer.writerow(["Schematic Source:",net.getSource()]) writer.writerow(["BoM Date:",net.getDate()])
writer.writerow(["KiCad Version:",net.getTool()]) writer.writerow(["Schematic Source:",net.getSource()])
writer.writerow(["KiCad Version:",net.getTool()])
return True return True

View File

@ -6,6 +6,7 @@ import os
BG_GEN = "#E6FFEE" BG_GEN = "#E6FFEE"
BG_KICAD = "#FFE6B3" BG_KICAD = "#FFE6B3"
BG_USER = "#E6F9FF" BG_USER = "#E6F9FF"
BG_EMPTY = "#FF8080"
#return a background color for a given column title #return a background color for a given column title
def bgColor(col): def bgColor(col):
@ -58,24 +59,26 @@ def WriteHTML(filename, groups, net, headings, prefs):
#PCB info #PCB info
html.write("<h2>KiBoM PCB Bill of Materials</h2>\n") if not prefs.hideHeaders:
html.write('<table border="1">\n') html.write("<h2>KiBoM PCB Bill of Materials</h2>\n")
html.write("<tr><td>Source File</td><td>{source}</td></tr>\n".format(source=net.getSource())) html.write('<table border="1">\n')
html.write("<tr><td>BoM Date</td><td>{date}</td></tr>\n".format(date=net.getDate())) html.write("<tr><td>Source File</td><td>{source}</td></tr>\n".format(source=net.getSource()))
html.write("<tr><td>Schematic Version</td><td>{version}</td></tr>\n".format(version=net.getVersion())) html.write("<tr><td>BoM Date</td><td>{date}</td></tr>\n".format(date=net.getDate()))
html.write("<tr><td>Schematic Date</td><td>{date}</td></tr>\n".format(date=net.getSheetDate())) html.write("<tr><td>Schematic Version</td><td>{version}</td></tr>\n".format(version=net.getVersion()))
html.write("<tr><td>KiCad Version</td><td>{version}</td></tr>\n".format(version=net.getTool())) html.write("<tr><td>Schematic Date</td><td>{date}</td></tr>\n".format(date=net.getSheetDate()))
html.write("<tr><td>Component Groups</td><td>{n}</td></tr>\n".format(n=nGroups)) html.write("<tr><td>KiCad Version</td><td>{version}</td></tr>\n".format(version=net.getTool()))
html.write("<tr><td>Component Count (per PCB)</td><td>{n}</td></tr>\n".format(n=nTotal)) html.write("<tr><td>Component Groups</td><td>{n}</td></tr>\n".format(n=nGroups))
html.write("<tr><td>Fitted Components (per PCB)</td><td>{n}</td></tr>\n".format(n=nFitted)) html.write("<tr><td>Component Count (per PCB)</td><td>{n}</td></tr>\n".format(n=nTotal))
html.write("<tr><td>Number of PCBs</td><td>{n}</td></tr>\n".format(n=prefs.boards)) html.write("<tr><td>Fitted Components (per PCB)</td><td>{n}</td></tr>\n".format(n=nFitted))
html.write("<tr><td>Total Component Count<br>(for {n} PCBs)</td><td>{t}</td></tr>\n".format(n=prefs.boards, t=nBuild)) html.write("<tr><td>Number of PCBs</td><td>{n}</td></tr>\n".format(n=prefs.boards))
html.write("</table>\n") html.write("<tr><td>Total Component Count<br>(for {n} PCBs)</td><td>{t}</td></tr>\n".format(n=prefs.boards, t=nBuild))
html.write("<br>\n") html.write("</table>\n")
html.write("<h2>Component Groups</h2>\n") html.write("<br>\n")
html.write('<p style="background-color: {bg}">Kicad Fields (default)</p>\n'.format(bg=BG_KICAD)) html.write("<h2>Component Groups</h2>\n")
html.write('<p style="background-color: {bg}">Generated Fields</p>\n'.format(bg=BG_GEN)) html.write('<p style="background-color: {bg}">Kicad Fields (default)</p>\n'.format(bg=BG_KICAD))
html.write('<p style="background-color: {bg}">User Fields</p>\n'.format(bg=BG_USER)) html.write('<p style="background-color: {bg}">Generated Fields</p>\n'.format(bg=BG_GEN))
html.write('<p style="background-color: {bg}">User Fields</p>\n'.format(bg=BG_USER))
html.write('<p style="background-color: {bg}">Empty Fields</p>\n'.format(bg=BG_EMPTY))
#component groups #component groups
html.write('<table border="1">\n') html.write('<table border="1">\n')
@ -109,7 +112,11 @@ def WriteHTML(filename, groups, net, headings, prefs):
html.write('\t<td align="center">{n}</td>\n'.format(n=rowCount)) html.write('\t<td align="center">{n}</td>\n'.format(n=rowCount))
for n, r in enumerate(row): for n, r in enumerate(row):
bg = bgColor(headings[n])
if len(r) == 0:
bg = BG_EMPTY
else:
bg = bgColor(headings[n])
html.write('\t<td align="center"{bg}>{val}</td>\n'.format(bg=' bgcolor={c}'.format(c=bg) if bg else '', val=link(r))) html.write('\t<td align="center"{bg}>{val}</td>\n'.format(bg=' bgcolor={c}'.format(c=bg) if bg else '', val=link(r)))

View File

@ -49,6 +49,7 @@ class BomPref:
self.useRegex = True #Test various columns with regex self.useRegex = True #Test various columns with regex
self.compareFootprints = True #test footprints when comparing components self.compareFootprints = True #test footprints when comparing components
self.boards = 1 self.boards = 1
self.hideHeaders = False
self.verbose = False #by default, is not verbose self.verbose = False #by default, is not verbose
self.configurations = [] #list of various configurations self.configurations = [] #list of various configurations

View File

@ -31,9 +31,10 @@ def say(*arg):
parser = argparse.ArgumentParser(description="KiBOM Bill of Materials generator script") parser = argparse.ArgumentParser(description="KiBOM Bill of Materials generator script")
parser.add_argument("netlist", help='xml netlist file. Use "%%I" when running from within KiCad') parser.add_argument("netlist", help='xml netlist file. Use "%%I" when running from within KiCad')
parser.add_argument("--output", "-o", help='BoM output file name.\nUse "%%O" when running from within KiCad to use the default output name (csv file).\nFor e.g. HTML output, use "%%O.html"\r\nIf output file is unspecified, default output filename (csv format) will be used', default=None) parser.add_argument("output", default="", help='BoM output file name.\nUse "%%O" when running from within KiCad to use the default output name (csv file).\nFor e.g. HTML output, use "%%O.html"')
parser.add_argument("--boards", "-b", help="Number of boards to build (default = 1)", type=int, default=1) parser.add_argument("-b", "--boards", help="Number of boards to build (default = 1)", type=int, default=1)
parser.add_argument("-v", "--verbose", help="Enable verbose output", action='count') parser.add_argument("-v", "--verbose", help="Enable verbose output", action='count')
parser.add_argument("-n", "--noheader", help="Do not generate file headers; data only.", action='count')
parser.add_argument("--cfg", help="BoM config file (script will try to use 'bom.ini' if not specified here)") parser.add_argument("--cfg", help="BoM config file (script will try to use 'bom.ini' if not specified here)")
args = parser.parse_args() args = parser.parse_args()
@ -48,25 +49,6 @@ verbose = args.verbose is not None
input_file = os.path.abspath(input_file) input_file = os.path.abspath(input_file)
say("Input:",input_file) say("Input:",input_file)
output_file = args.output
if output_file is None:
output_file = input_file.replace(".xml","_bom.csv")
#enfore a proper extension
valid = False
extensions = [".xml",".csv",".txt",".tsv",".html"]
for e in extensions:
if output_file.endswith(e):
valid = True
break
if not valid:
close("Extension must be one of",extensions)
output_file = os.path.abspath(output_file)
say("Output:",output_file)
#look for a config file! #look for a config file!
#bom.ini by default #bom.ini by default
@ -83,6 +65,8 @@ pref = BomPref()
#pass various command-line options through #pass various command-line options through
pref.verbose = verbose pref.verbose = verbose
pref.boards = args.boards pref.boards = args.boards
if args.noheader:
pref.hideHeaders = True
if os.path.exists(config_file): if os.path.exists(config_file):
pref.Read(config_file) pref.Read(config_file)
@ -115,14 +99,42 @@ for g in groups:
for f in g.fields: for f in g.fields:
columns.AddColumn(f) columns.AddColumn(f)
#don't add 'boards' column if only one board is specified
if pref.boards <= 1: if pref.boards <= 1:
columns.RemoveColumn(ColumnList.COL_GRP_BUILD_QUANTITY) columns.RemoveColumn(ColumnList.COL_GRP_BUILD_QUANTITY)
say("Removing:",ColumnList.COL_GRP_BUILD_QUANTITY) say("Removing:",ColumnList.COL_GRP_BUILD_QUANTITY)
#todo
write_to_bom = True
result = True
#Finally, write the BoM out to file #Finally, write the BoM out to file
result = WriteBoM(output_file, groups, net, columns.columns, pref) if write_to_bom:
output_file = args.output
if output_file is None:
output_file = input_file.replace(".xml","_bom.csv")
#enfore a proper extension
valid = False
extensions = [".xml",".csv",".txt",".tsv",".html"]
for e in extensions:
if output_file.endswith(e):
valid = True
break
if not valid:
close("Extension must be one of",extensions)
output_file = os.path.abspath(output_file)
say("Output:",output_file)
result = WriteBoM(output_file, groups, net, columns.columns, pref)
if result: if result:
sys.exit(0) sys.exit(0)
else: else:
sys.exit(-1) sys.exit(-1)