Preferences file now passed through to the netlist reader, allowing more options to be stored in the .ini file

Changed ".bom" to "bom.ini"
Removed old code from netlist_reader.py
This commit is contained in:
Oliver 2016-05-15 20:18:03 +10:00
parent 4a304a5959
commit b69d66902c
5 changed files with 84 additions and 79 deletions

View File

@ -1,5 +1,7 @@
from columns import ColumnList
from preferences import BomPref
import units
from sort import natural_sort
@ -12,9 +14,14 @@ class Component():
with accessors. The xmlElement is held in field 'element'.
"""
def __init__(self, xml_element):
def __init__(self, xml_element, prefs=None):
self.element = xml_element
self.libpart = None
if not prefs:
prefs = BomPref()
self.prefs = prefs
# Set to true when this component is included in a component group
self.grouped = False
@ -59,6 +66,11 @@ class Component():
valueResult = self.compareValue(other)
#if connector comparison is overridden, set valueResult to True
if self.prefs.groupConnectors:
if "conn" in self.getDescription().lower():
valueResult = True
return valueResult and self.compareFootprint(other) and self.compareLibName(other) and self.comparePartName(other) and self.isFitted() == other.isFitted()
def setLibPart(self, part):
@ -155,11 +167,16 @@ class ComponentGroup():
"""
Initialize the group with no components, and default fields
"""
def __init__(self):
def __init__(self, prefs=None):
self.components = []
self.fields = dict.fromkeys(ColumnList._COLUMNS_PROTECTED) #columns loaded from KiCAD
self.csvFields = dict.fromkeys(ColumnList._COLUMNS_DEFAULT) #columns loaded from .csv file
if not prefs:
prefs = BomPref()
self.prefs = prefs
def getField(self, field):
if not field in self.fields.keys(): return ""
if not self.fields[field]: return ""

View File

@ -24,50 +24,7 @@ import pdb
from component import Component, ComponentGroup
from sort import natural_sort
#-----<Configure>----------------------------------------------------------------
# excluded_fields is a list of regular expressions. If any one matches a field
# from either a component or a libpart, then that will not be included as a
# column in the BOM. Otherwise all columns from all used libparts and components
# will be unionized and will appear. Some fields are impossible to blacklist, such
# as Ref, Value, Footprint, and Datasheet. Additionally Qty and Item are supplied
# unconditionally as columns, and may not be removed.
excluded_fields = [
#'Price@1000'
]
# You may exlude components from the BOM by either:
#
# 1) adding a custom field named "Installed" to your components and filling it
# with a value of "NU" (Normally Uninstalled).
# See netlist.getInterestingComponents(), or
#
# 2) blacklisting it in any of the three following lists:
# regular expressions which match component 'Reference' fields of components that
# are to be excluded from the BOM.
excluded_references = [
'TP[0-9]+' # all test points
]
# regular expressions which match component 'Value' fields of components that
# are to be excluded from the BOM.
excluded_values = [
'MOUNTHOLE',
'SCOPETEST',
'MOUNT_HOLE',
'SOLDER_BRIDGE.*'
]
# regular expressions which match component 'Footprint' fields of components that
# are to be excluded from the BOM.
excluded_footprints = [
#'MOUNTHOLE'
]
from preferences import BomPref
# When comparing part names, components will match if they are both elements of the
# same set defined here
@ -318,7 +275,7 @@ class netlist():
scripts
"""
def __init__(self, fname=""):
def __init__(self, fname="", prefs=None):
"""Initialiser for the genericNetlist class
Keywords:
@ -335,6 +292,11 @@ class netlist():
self.tree = []
self._curr_element = None
if not prefs:
prefs = BomPref() #default values
self.prefs = prefs
# component blacklist regexs, made from exluded_* above.
self.excluded_references = []
@ -359,7 +321,7 @@ class netlist():
# If this element is a component, add it to the components list
if self._curr_element.name == "comp":
self.components.append(Component(self._curr_element))
self.components.append(Component(self._curr_element, prefs=self.prefs))
# Assign the design element
if self._curr_element.name == "design":
@ -449,13 +411,13 @@ class netlist():
del self.excluded_values[:]
del self.excluded_footprints[:]
for rex in excluded_references:
for rex in self.prefs.excluded_references:
self.excluded_references.append( re.compile( rex ) )
for rex in excluded_values:
for rex in self.prefs.excluded_values:
self.excluded_values.append( re.compile( rex ) )
for rex in excluded_footprints:
for rex in self.prefs.excluded_footprints:
self.excluded_footprints.append( re.compile( rex ) )
# the subset of components to return, considered as "interesting".
@ -495,20 +457,8 @@ class netlist():
return ret
def groupComponents(self, components = None):
"""Return a list of component lists. Components are grouped together
when the value, library and part identifiers match.
ALSO THE FOOTPRINTS MUST MATCH YOU DINGBAT
Keywords:
components -- is a list of components, typically an interesting subset
of all components, or None. If None, then all components are looked at.
"""
if not components:
components = self.components
def groupComponents(self, components):
groups = []
"""

View File

@ -12,9 +12,13 @@ class BomPref:
SECTION_IGNORE = "IGNORE_COLUMNS"
SECTION_GENERAL = "BOM_OPTIONS"
SECTION_EXCLUDE_VALUES = "EXCLUDE_COMPONENT_VALUES"
SECTION_EXCLUDE_REFS = "EXCLUDE_COMPONENT_REFS"
SECTION_EXCLUDE_FP = "EXCLUDE_COMPONENT_FP"
OPT_IGNORE_DNF = "ignore_dnf"
OPT_NUMBER_ROWS = "number_rows"
OPT_GROUP_CONN = "group_connectors"
def __init__(self):
self.ignore = [
@ -23,6 +27,25 @@ class BomPref:
] #list of headings to ignore in BoM generation
self.ignoreDNF = False #ignore rows for do-not-fit parts
self.numberRows = True #add row-numbers to BoM output
self.groupConnectors = True #group connectors and ignore component value
#default reference exclusions
self.excluded_references = [
"TP[0-9]+"
]
#default value exclusions
self.excluded_values = [
'MOUNTHOLE',
'SCOPETEST',
'MOUNT_HOLE',
'MOUNTING_HOLE',
'SOLDER_BRIDGE.*'
]
#default footprint exclusions
self.excluded_footprints = [
]
#read KiBOM preferences from file
def Read(self, file, verbose=False):
@ -39,22 +62,16 @@ class BomPref:
#read general options
if self.SECTION_GENERAL in cf.sections():
if cf.has_option(self.SECTION_GENERAL, self.OPT_IGNORE_DNF):
self.ignoreDNF = (cf.get(self.SECTION_GENERAL, self.OPT_IGNORE_DNF) == "1")
self.ignoreDNF = cf.get(self.SECTION_GENERAL, self.OPT_IGNORE_DNF) == "1"
if cf.has_option(self.SECTION_GENERAL, self.OPT_NUMBER_ROWS):
self.numberRows = (cf.get(self.SECTION_GENERAL, self.OPT_NUMBER_ROWS) == "1")
self.numberRows = cf.get(self.SECTION_GENERAL, self.OPT_NUMBER_ROWS) == "1"
if cf.has_option(self.SECTION_GENERAL, self.OPT_GROUP_CONN):
self.groupConnectors = cf.get(self.SECTION_GENERAL, self.OPT_GROUP_CONN) == "1"
#read out ignored-rows
if self.SECTION_IGNORE in cf.sections():
self.ignore = [i for i in cf.options(self.SECTION_IGNORE)]
if verbose:
print("Preferences:")
print(self.OPT_IGNORE_DNF + ' = ' + str(self.ignoreDNF))
print(self.OPT_NUMBER_ROWS + ' = ' + str(self.numberRows))
for i in self.ignore:
print("Ignoring column '" + i + "'")
#write KiBOM preferences to file
def Write(self, file):
file = os.path.abspath(file)
@ -67,6 +84,8 @@ class BomPref:
cf.set(self.SECTION_GENERAL, self.OPT_IGNORE_DNF, 1 if self.ignoreDNF else 0)
cf.set(self.SECTION_GENERAL, "; If number_rows option is set to 1, each row in the BoM will be prepended with an incrementing row number")
cf.set(self.SECTION_GENERAL, self.OPT_NUMBER_ROWS, 1 if self.numberRows else 0)
cf.set(self.SECTION_GENERAL, "; If group_connectors option is set to 1, connectors with the same footprints will be grouped together, independent of the name of the connector")
cf.set(self.SECTION_GENERAL, self.OPT_GROUP_CONN, 1 if self.groupConnectors else 0)
cf.add_section(self.SECTION_IGNORE)
cf.set(self.SECTION_IGNORE, "; Any column heading that appears here will be excluded from the Generated BoM")
@ -75,5 +94,23 @@ class BomPref:
for i in self.ignore:
cf.set(self.SECTION_IGNORE, i)
cf.add_section(self.SECTION_EXCLUDE_VALUES)
cf.set(self.SECTION_EXCLUDE_VALUES, "; A series of reg-ex strings for ignoring component values")
cf.set(self.SECTION_EXCLUDE_VALUES, "; Any components with values that match any of these reg-ex strings will be ignored")
for e in self.excluded_values:
cf.set(self.SECTION_EXCLUDE_VALUES, e)
cf.add_section(self.SECTION_EXCLUDE_REFS)
cf.set(self.SECTION_EXCLUDE_REFS, "; A series of reg-ex strings for ignoring component references")
cf.set(self.SECTION_EXCLUDE_REFS, "; Any components with references that match any of these reg-ex strings will be ignored")
for e in self.excluded_references:
cf.set(self.SECTION_EXCLUDE_REFS, e)
cf.add_section(self.SECTION_EXCLUDE_FP)
cf.set(self.SECTION_EXCLUDE_FP, "; A series of reg-ex strings for ignoring component footprints")
cf.set(self.SECTION_EXCLUDE_FP, "; Any components with footprints that match any of these reg-ex strings will be ignored")
for e in self.excluded_footprints:
cf.set(self.SECTION_EXCLUDE_FP, e)
with open(file, 'wb') as configfile:
cf.write(configfile)

View File

@ -59,11 +59,11 @@ ignoreDNF = False
numberRows = True
#Look for a '.bom' preference file
pref_file = os.path.join(os.path.dirname(input_file) , ".bom")
pref_file = os.path.join(os.path.dirname(input_file) , "bom.ini")
#read preferences from file. If file does not exists, default preferences will be used
pref = BomPref()
pref.Read(pref_file, verbose=True)
pref.Read(pref_file)
#write preference file back out (first run will generate a file with default preferences)
pref.Write(pref_file)
@ -75,7 +75,7 @@ components = []
groups = []
#read out the netlist
net = netlist(input_file)
net = netlist(input_file, prefs = pref)
#extract the components
components = net.getInterestingComponents()

View File

@ -56,10 +56,11 @@ Multiple BoM output formats are supported:
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.
### Configuration File
BoM generation options can be configured (on a per-project basis) by editing the *.bom* file in the PCB project directory. This file is generated the first time that the KiBoM script is run, and allows configuration of the following options.
BoM generation options can be configured (on a per-project basis) by editing the *bom.ini* file in the PCB project directory. This file is generated the first time that the KiBoM script is run, and allows configuration of the following options.
* Number Rows: Add row numbers to the BoM output
* Ignore DNF: Component groups marked as 'DNF' (do not fit) will be excluded from the BoM output
* Ignore Columns: A list of columns can be marked as 'ignore', and will not be output to the BoM file. By default, the *Part_Lib* and *Footprint_Lib* columns are ignored.
* Group Connectors: If this option is set, connector comparison based on the 'Value' field is ignored. This allows multiple connectors which are named for their function (e.g. "Power", "ICP" etc) can be grouped together.
Example configuration file (.ini format)
![alt tag](example/config.png?raw=True "Configuration")