Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dnc #91

Merged
merged 6 commits into from
Mar 13, 2020
Merged

Dnc #91

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ __pycache__/
*$py.class
*.pyc

*.kicad_mod
*.patch
.idea/

.env
Expand Down
6 changes: 2 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ dist: xenial
language: python

python:
- 2.7
- 3.6

install:
- pip3 install -r test/requirements.txt
- pip install -r test/requirements.txt

addons:
apt:
Expand All @@ -20,9 +21,6 @@ before_install:
script:
# Check Python code for style-guide
- flake8 .
# Test that the export script works with both Python2 and Python3
- python2 KiBOM_CLI.py test/kibom-test.xml test/out2.csv
- python3 KiBOM_CLI.py test/kibom-test.xml test/out3.csv
# Run the coverage tests
- bash ./run-tests.sh

Expand Down
2 changes: 1 addition & 1 deletion KiBOM_CLI.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
else:
xlsxwriter_available = True

KIBOM_VERSION = "1.6.0"
KIBOM_VERSION = "1.6.1"

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

Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ To specify a part as DNF (do not fit), the *fit_field* field can be set to one o
* "noload"
* "do not load"

**DNC Parts**

Parts can be marked as *do not change* or *fixed* by specifying the `dnc` attribute in the *fit_field* field.

**Note:**

If the *Value* field for the component contains any of these values, the component will also not be included
Expand Down
56 changes: 54 additions & 2 deletions bomlib/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import re
import sys

# String matches for marking a component as "do not fit"
DNF = [
"dnf",
"dnl",
Expand All @@ -25,6 +26,14 @@
"no stuff",
]

# String matches for marking a component as "do not change" or "fixed"
DNC = [
"dnc",
"do not change",
"no change",
"fixed"
]


class Component():
"""Class for a component, aka 'comp' in the xml netlist file.
Expand Down Expand Up @@ -102,6 +111,10 @@ def __eq__(self, other):
if self.isFitted() != other.isFitted():
return False

# 'fixed' value must be the same for both parts
if self.isFixed() != other.isFixed():
return False

if len(self.prefs.groups) == 0:
return False

Expand Down Expand Up @@ -301,6 +314,41 @@ def isFitted(self):

return include and not exclude

# Determine if a component is FIXED or not
def isFixed(self):

check = self.getField(self.prefs.configField).lower()

# Check the value field first
if self.getValue().lower() in DNC:
return False

# Empty is not fixed
if check == "":
return True

opts = check.split(" ")
for opt in opts:
if opt.lower() in DNC:
return False

opts = check.split(",")

result = False

for opt in opts:
# Options that start with '-' are explicitly removed from certain configurations
if opt.startswith('-') and opt[1:].lower() == self.prefs.pcbConfig.lower():
result = False
break
if opt.startswith("+"):
result = False
if opt[1:].lower() == self.prefs.pcbConfig.lower():
result = True

# by default, part is not fixed
return result

# Test if this part should be included, based on any regex expressions provided in the preferences
def testRegExclude(self):

Expand Down Expand Up @@ -475,6 +523,9 @@ def addComponent(self, c):
def isFitted(self):
return any([c.isFitted() for c in self.components])

def isFixed(self):
return any([c.isFixed() for c in self.components])

def getRefs(self):
# Return a list of the components
return " ".join([c.getRef() for c in self.components])
Expand Down Expand Up @@ -533,9 +584,10 @@ def updateFields(self, usealt=False, wrapN=None):
self.fields[ColumnList.COL_REFERENCE] = self.getRefs()

q = self.getCount()
self.fields[ColumnList.COL_GRP_QUANTITY] = "{n}{dnf}".format(
self.fields[ColumnList.COL_GRP_QUANTITY] = "{n}{dnf}{dnc}".format(
n=q,
dnf=" (DNF)" if not self.isFitted() else "")
dnf=" (DNF)" if not self.isFitted() else "",
dnc=" (DNC)" if not self.isFixed() else "")

self.fields[ColumnList.COL_GRP_BUILD_QUANTITY] = str(q * self.prefs.boards) if self.isFitted() else "0"
self.fields[ColumnList.COL_VALUE] = self.components[0].getValue()
Expand Down
3 changes: 3 additions & 0 deletions run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ coverage run -a KiBOM_CLI.py test/kibom-test.xml test/bom-out.xml
# Generate an XLSX file
coverage run -a KiBOM_CLI.py test/kibom-test.xml test/bom-out.xlsx

# Run the sanity checker on the output BOM files
coverage run -a test/test_bom.py

# Generate HTML code coverage output
coverage html

10 changes: 8 additions & 2 deletions test/kibom-test.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<export version="D">
<design>
<source>C:\KiCad\KiBoM\test\kibom-test.sch</source>
<date>12/03/2020 11:34:46 PM</date>
<date>13/03/2020 12:28:18 PM</date>
<tool>Eeschema (5.1.5)-2</tool>
<sheet number="1" name="/" tstamps="/">
<title_block>
Expand All @@ -20,7 +20,7 @@
</design>
<components>
<comp ref="R1">
<value>10K</value>
<value>10000</value>
<footprint>Resistor_SMD:R_0805_2012Metric</footprint>
<datasheet>~</datasheet>
<libsource lib="Device" part="R" description="Resistor"/>
Expand Down Expand Up @@ -63,6 +63,9 @@
<value>4K7</value>
<footprint>Resistor_SMD:R_0805_2012Metric</footprint>
<datasheet>~</datasheet>
<fields>
<field name="Config">DNF</field>
</fields>
<libsource lib="Device" part="R" description="Resistor"/>
<sheetpath names="/" tstamps="/"/>
<tstamp>5E6A3CA0</tstamp>
Expand All @@ -71,6 +74,9 @@
<value>4700</value>
<footprint>Resistor_SMD:R_0805_2012Metric</footprint>
<datasheet>~</datasheet>
<fields>
<field name="Config">DNC</field>
</fields>
<libsource lib="Device" part="R" description="Resistor"/>
<sheetpath names="/" tstamps="/"/>
<tstamp>5E6A3F38</tstamp>
Expand Down
58 changes: 58 additions & 0 deletions test/test_bom.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from __future__ import print_function

import csv
import os
import sys


print("Checking generated BOM...")

BOM_FILE = "bom-out_bom_A.csv"

BOM_FILE = os.path.join(os.path.dirname(__file__), BOM_FILE)

lines = []

with open(BOM_FILE, 'r') as bom_file:
reader = csv.reader(bom_file, delimiter=',')

lines = [line for line in reader]

# Check that the header row contains the expected information
assert 'Component' in lines[0]

component_rows = []

idx = 1

while idx < len(lines):
row = lines[idx]

# Break on the first 'empty' row
if len(row) == 0:
break

component_rows.append(row)

idx += 1

# We know how many component rows there should be
assert len(component_rows) == 5

# Create a list of components
component_refs = []

for row in component_rows:
refs = row[3].split(" ")

for ref in refs:
# Ensure no component is duplicated in the BOM!
if ref in component_refs:
raise AssertionError("Component {ref} is duplicated".format(ref=ref))

# R6 should be excluded from the BOM (marked as DNF)
assert 'R6' not in component_refs

print("All tests passed... OK...")

sys.exit(0)