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:
parent
4a304a5959
commit
b69d66902c
|
|
@ -1,5 +1,7 @@
|
|||
from columns import ColumnList
|
||||
|
||||
from preferences import BomPref
|
||||
|
||||
import units
|
||||
|
||||
from sort import natural_sort
|
||||
|
|
@ -12,10 +14,15 @@ 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 ""
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
@ -336,6 +293,11 @@ class netlist():
|
|||
|
||||
self._curr_element = None
|
||||
|
||||
if not prefs:
|
||||
prefs = BomPref() #default values
|
||||
|
||||
self.prefs = prefs
|
||||
|
||||
# component blacklist regexs, made from exluded_* above.
|
||||
self.excluded_references = []
|
||||
self.excluded_values = []
|
||||
|
|
@ -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,19 +457,7 @@ 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 = []
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||

|
||||
|
|
|
|||
Loading…
Reference in New Issue