Skip to content

Commit

Permalink
Merge pull request #57 from Ximi1970/feature-xlsx
Browse files Browse the repository at this point in the history
Feature xlsx
  • Loading branch information
SchrodingersGat authored May 30, 2019
2 parents e4df1e8 + a326349 commit 38525f3
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 2 deletions.
19 changes: 17 additions & 2 deletions KiBOM_CLI.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
@package
KiBOM - Bill of Materials generation for KiCad
Generate BOM in xml, csv, txt, tsv or html formats.
Generate BOM in xml, csv, txt, tsv, html or xlsx formats.
- Components are automatically grouped into BoM rows (grouping is configurable)
- Component groups count number of components and list component designators
Expand All @@ -24,6 +24,16 @@

import argparse

# Optional modules

try:
import xlsxwriter
except:
xlsxwriter_available = False
else:
xlsxwriter_available = True

#
here = os.path.abspath(os.path.dirname(sys.argv[0]))

sys.path.append(here)
Expand All @@ -47,7 +57,9 @@ def say(*arg):

def isExtensionSupported(filename):
result = False
extensions = [".xml",".csv",".txt",".tsv",".html"]
extensions = [".xml",".csv",".txt",".tsv",".html"]
if xlsxwriter_available:
extensions.append(".xlsx")
for e in extensions:
if filename.endswith(e):
result = True
Expand Down Expand Up @@ -94,6 +106,9 @@ def isExtensionSupported(filename):
pref.Read(config_file)
say("Config:",config_file)

#pass available modules
pref.xlsxwriter_available = xlsxwriter_available

#pass various command-line options through
pref.verbose = verbose
if args.number is not None:
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ optional arguments:
* If a suffix is not specified, CSV output format will be used
* HTML output can be specified within KiCad as: "%O.html" or "%O_BOM.html" (etc)
* XML output can be specified within KiCad as: "%O.xml" (etc)
* XSLX output can be specified within KiCad as: "%O.xlsx" (etc)

**-n --number** Specify number of boards for calculating part quantities

Expand Down Expand Up @@ -181,6 +182,7 @@ Multiple BoM output formats are supported:
* TXT (Text file output with tab separated values)
* XML
* HTML
* XLSX (Needs XlsxWriter Python module)

Output file format selection is set by the output filename. e.g. "bom.html" will be written to a HTML file, "bom.csv" will be written to a CSV file.

Expand Down Expand Up @@ -352,6 +354,10 @@ An XML file output can be generated simply by changing the file extension
<group Datasheet="http://www.ti.com/lit/ds/symlink/max232.pdf" Description="Dual RS232 driver/receiver, 5V supply, 120kb/s, 0C-70C" Footprint="DIP-16_W7.62mm" Notes="Do not fit" Part="MAX232" Quantity="1 (DNF)" Rating="" References="U1" Value="MAX232" Vendor=""/>
</KiCad_BOM>

### XLSX Output
An XLSX file output can be generated simply by changing the file extension


## Contributors

With thanks to the following contributors:
Expand All @@ -365,3 +371,4 @@ With thanks to the following contributors:
* https://github.com/marcelobarrosalmeida
* https://github.com/fauxpark
* https://github.com/Swij
* https://github.com/Ximi1970
8 changes: 8 additions & 0 deletions bomlib/bom_writer.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from bomlib.csv_writer import WriteCSV
from bomlib.xml_writer import WriteXML
from bomlib.html_writer import WriteHTML
from bomlib.xlsx_writer import WriteXLSX

import bomlib.columns as columns
from bomlib.component import *
Expand Down Expand Up @@ -69,6 +70,13 @@ def WriteBoM(filename, groups, net, headings = columns.ColumnList._COLUMNS_DEFAU
else:
print("Error writing XML output")

elif ( ext in ["xlsx"] ) and prefs.xlsxwriter_available:
if WriteXLSX(filename, groups, net, headings, prefs):
print("XLSX Output -> {fn}".format(fn=filename))
result = True
else:
print("Error writing XLSX output")

else:
print("Unsupported file extension: {ext}".format(ext=ext))

Expand Down
3 changes: 3 additions & 0 deletions bomlib/preferences.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ def __init__(self):
self.separatorCSV = None
self.includeVersionNumber = True

self.xlsxwriter_available = False
self.xlsxwriter2_available = False

# Default fields used to group components
self.groups = [
ColumnList.COL_PART,
Expand Down
148 changes: 148 additions & 0 deletions bomlib/xlsx_writer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# _*_ coding:latin-1 _*_

try:
import xlsxwriter
except:
def WriteXLSX(filename, groups, net, headings, prefs):
return False
else:
import bomlib.columns as columns
from bomlib.component import *
import os, shutil
from bomlib.preferences import BomPref

"""
Write BoM out to a XLSX file
filename = path to output file (must be a .xlsx file)
groups = [list of ComponentGroup groups]
net = netlist object
headings = [list of headings to display in the BoM file]
prefs = BomPref object
"""

def WriteXLSX(filename, groups, net, headings, prefs):

filename = os.path.abspath(filename)

if not filename.endswith(".xlsx"):
return False

nGroups = len(groups)
nTotal = sum([g.getCount() for g in groups])
nFitted = sum([g.getCount() for g in groups if g.isFitted()])
nBuild = nFitted * prefs.boards

workbook = xlsxwriter.Workbook(filename)
worksheet = workbook.add_worksheet()

if prefs.numberRows:
row_headings = ["Component"] + headings
else:
row_headings = headings

cellformats = {}
column_widths = {}
for i in range(len(row_headings)):
cellformats[i] = workbook.add_format({'align':'center_across'})
column_widths[i] = len(row_headings[i]) + 10

if not prefs.hideHeaders:
worksheet.write_string( 0, i, row_headings[i], cellformats[i])

count = 0
rowCount = 1

for i, group in enumerate(groups):
if prefs.ignoreDNF and not group.isFitted(): continue

row = group.getRow(headings)

if prefs.numberRows:
row = [str(rowCount)] + row

for columnCount in range(len(row)):

cell = row[columnCount].decode('utf-8')

worksheet.write_string(rowCount,columnCount,cell,cellformats[columnCount])

if len(cell) > column_widths[columnCount] - 5:
column_widths[columnCount] = len(cell) + 5

try:
count += group.getCount()
except:
pass

rowCount += 1

if not prefs.hideHeaders:
#blank rows
for i in range(5):
rowCount += 1

cellformat_left = workbook.add_format({'align':'left'})

worksheet.write_string( rowCount, 0, "Component Groups:", cellformats[0])
worksheet.write_number( rowCount, 1, nGroups, cellformat_left)
rowCount += 1

worksheet.write_string( rowCount, 0, "Component Count:", cellformats[0])
worksheet.write_number( rowCount, 1, nTotal, cellformat_left)
rowCount += 1

worksheet.write_string( rowCount, 0, "Fitted Components:", cellformats[0])
worksheet.write_number( rowCount, 1, nFitted, cellformat_left)
rowCount += 1

worksheet.write_string( rowCount, 0, "Number of PCBs:", cellformats[0])
worksheet.write_number( rowCount, 1, prefs.boards, cellformat_left)
rowCount += 1

worksheet.write_string( rowCount, 0, "Total components:", cellformats[0])
worksheet.write_number( rowCount, 1, nBuild, cellformat_left)
rowCount += 1

worksheet.write_string( rowCount, 0, "Schematic Version:", cellformats[0])
worksheet.write_string( rowCount, 1, net.getVersion(), cellformat_left)
rowCount += 1

if len(net.getVersion()) > column_widths[1]:
column_widths[1] = len(net.getVersion())


worksheet.write_string( rowCount, 0, "Schematic Date:", cellformats[0])
worksheet.write_string( rowCount, 1, net.getSheetDate(), cellformat_left)
rowCount += 1

if len(net.getSheetDate()) > column_widths[1]:
column_widths[1] = len(net.getSheetDate())


worksheet.write_string( rowCount, 0, "BoM Date:", cellformats[0])
worksheet.write_string( rowCount, 1, net.getDate(), cellformat_left)
rowCount += 1

if len(net.getDate()) > column_widths[1]:
column_widths[1] = len(net.getDate())

worksheet.write_string( rowCount, 0, "Schematic Source:", cellformats[0])
worksheet.write_string( rowCount, 1, net.getSource(), cellformat_left)
rowCount += 1

if len(net.getSource()) > column_widths[1]:
column_widths[1] = len(net.getSource())

worksheet.write_string( rowCount, 0, "KiCad Version:", cellformats[0])
worksheet.write_string( rowCount, 1, net.getTool(), cellformat_left)
rowCount += 1

if len(net.getTool()) > column_widths[1]:
column_widths[1] = len(net.getTool())

for i in range(len(column_widths)):
worksheet.set_column( i, i, column_widths[i])

workbook.close()

return True

0 comments on commit 38525f3

Please sign in to comment.