Compare commits

...

47 Commits

Author SHA1 Message Date
Salvador E. Tropea e49efcf21d Removed manual Digi-Key plug-in installation
- Now in the docker images
2022-03-21 18:38:58 -03:00
Salvador E. Tropea 3896f1b910 Switched to KiCost/master 2022-03-21 18:08:24 -03:00
Salvador E. Tropea dc5924901b Fixed command line for `--list`
- PCB and SCH can be needed
- Adapted the test for --list
2021-11-15 13:12:15 -03:00
Salvador E. Tropea 2e4f5d6596 Internal BoM: the field used for variants doesn't produce conflicts.
- Fixes: #100
2021-11-15 12:14:55 -03:00
Salvador E. Tropea b86b5371d7 `--list`: problems with layers and fields specific for the project.
-  Fixes INTI-CMNB/kibot_variants_arduprog#4
2021-11-15 11:34:57 -03:00
Salvador E. Tropea 3d53b874e2 Fixed problems with schematic fields containing double quotes.
- Fixes #98
2021-11-15 11:12:39 -03:00
Salvador E. Tropea 324b3772e0 Useless change to trigger a test. 2021-10-28 18:42:22 -03:00
Salvador E. Tropea 7bd8c068b8 KiCost refresh 2021-10-28 18:40:21 -03:00
Salvador E. Tropea 4595f2a7f8 dapted to the new KiCost configuration mechanism 2021-10-28 18:10:12 -03:00
Salvador E. Tropea 103a338ece Added `extra_info_display` to the Specs. 2021-10-27 15:58:33 -03:00
Salvador E. Tropea ccfb6ce734 Int BoM + KiCost: Added option to control the distributor description
- Disabled by default
- Also fixed KiCost tests to avoid using Digi-Key plug-in when not
  needed
2021-10-27 15:08:12 -03:00
Salvador E. Tropea 3d6840cd85 Enabled description column. 2021-10-26 13:45:55 -03:00
Salvador E. Tropea bd76069be3 Now Spec columns can be renamed, joined, etc. 2021-10-26 10:46:57 -03:00
Salvador E. Tropea e2d71c38a0 Useless change to trigger a test. 2021-10-25 17:15:17 -03:00
Salvador E. Tropea 0156240a72 Fixed KiCost submodule tracking 2021-10-25 17:12:35 -03:00
Salvador E. Tropea b50bc4f6d9 Fixed extra os imort in xlsx_writer 2021-10-25 16:58:30 -03:00
Salvador E. Tropea ef1097375c Removed DIGIKEY_* debug definitions 2021-10-25 16:56:18 -03:00
Salvador E. Tropea 13d2e43c15 Updated docs (sort_style) 2021-10-25 13:57:59 -03:00
Salvador E. Tropea 8e9d5f69e6 Specs sheet: fixed column width comutation 2021-10-25 13:57:13 -03:00
Salvador E. Tropea 5c8f6334a5 Specs sheet: fixed headings row didn't compute width/height 2021-10-25 13:22:44 -03:00
Salvador E. Tropea d5d4c9f1a6 Updated KiCost submodule 2021-10-25 12:23:01 -03:00
Salvador E. Tropea b895cc7604 Internal BoM: Fixed message about wrong distributor
- The name was `None` instead of the real name
2021-10-25 12:00:57 -03:00
Salvador E. Tropea 1c018e6511 Added "Row" column to the Specs, also differentiated the generated cols 2021-10-20 14:36:10 -03:00
Salvador E. Tropea 20ead17d4a Internal BoM: two other options for the sorting criteria. 2021-10-20 13:55:36 -03:00
Salvador E. Tropea 79a363e49f Unified the BoM XLSX vertical align (centered) 2021-10-20 13:19:49 -03:00
Salvador E. Tropea b2afeadc5c Now KiCost spreadsheet uses our sorting. 2021-10-20 13:13:09 -03:00
Salvador E. Tropea 58fb9fe09a Added Specs columns configuration. 2021-10-20 12:36:08 -03:00
Salvador E. Tropea 7a6a264c5f Adapted to the new Digi-Key cache style and fixed return value 2021-10-20 11:54:33 -03:00
Salvador E. Tropea 616cdcd6bf Added catch for KiCost errors. 2021-10-20 11:50:34 -03:00
Salvador E. Tropea adfc509fdd Added options to control KiCost APIs.
- Removed the hardcoded ones.
2021-10-20 10:08:17 -03:00
Salvador E. Tropea 87bc028362 Internal BoM: Added Specs sheet generation. 2021-10-19 13:52:55 -03:00
Salvador E. Tropea f0384e501b Updated KiCost. 2021-10-19 09:29:00 -03:00
Salvador E. Tropea 51e2b0789a Forced Digi-Key API in the KiCost sheet.
- This is what we want to test
2021-10-19 09:28:14 -03:00
Salvador E. Tropea fcfe64e695 Fixed warning message (missing where info) 2021-10-19 09:27:33 -03:00
Salvador E. Tropea 2ab0e6a489 Removed unused requested constant 2021-10-19 09:26:53 -03:00
Salvador E. Tropea cdc212e89e Generic filter: added options to match if a field is/isn't defined. 2021-10-18 17:04:44 -03:00
Salvador E. Tropea 499b3520a6 Option to hide component from PDF PCB Print
- option `hide_excluded` to hide components marked by the
  `exclude_filter`.
- https://forum.kicad.info/t/fab-drawing-for-only-through-hole-parts/
2021-10-18 16:59:37 -03:00
Salvador E. Tropea e62e38b6ea Added fallback for values+units we can't understand 2021-10-18 16:51:32 -03:00
Salvador E. Tropea 969b3843de Changed the mechanism to avoid merging components with empty fields 2021-10-18 16:42:58 -03:00
Salvador E. Tropea 7187fe5ebc Removed docker image generation for this branch 2021-10-18 15:58:24 -03:00
Salvador E. Tropea 4ead7e6ef5 Avoid grouping components when they lack the grouping fields.
- This is for the internal BoM when `merge_blank_fields` is disabled
2021-10-18 15:55:19 -03:00
Salvador E. Tropea cc272dd31c Added Digi-Key plug-in dependencies installation. 2021-10-18 15:46:52 -03:00
Salvador E. Tropea 48dec2995e Fixed pip command name 2021-10-18 15:27:45 -03:00
Salvador E. Tropea 4d22b52403 Added kicost-digikey-api-v3 installation to the test workflow. 2021-10-18 15:25:56 -03:00
Salvador E. Tropea f752a72bfe Added support for KiCad symbol libs without EOF comment. 2021-10-18 14:45:58 -03:00
Salvador E. Tropea a136c2f7e7 Updated KiCost. 2021-10-18 14:42:31 -03:00
Salvador E. Tropea ea2d7916be Changed KiCost to official repo and the DK plug-in branch. 2021-10-12 10:36:12 -03:00
26 changed files with 446 additions and 75 deletions

View File

@ -53,34 +53,3 @@ jobs:
with:
name: Test_Output
path: output
push_to_registry:
name: Push Docker image to Docker Hub
runs-on: ubuntu-latest
needs: test
steps:
- name: Check out the repo
uses: actions/checkout@v2
- name: Log in to Docker Hub
uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
with:
images: setsoft/kicad_auto
- name: Build and push Docker image
uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
with:
context: tools/dev_image
push: true
tags: setsoft/kicad_auto:dev
labels: ${{ steps.meta.outputs.labels }}

3
.gitmodules vendored
View File

@ -1,3 +1,4 @@
[submodule "submodules/KiCost"]
path = submodules/KiCost
url = https://github.com/INTI-CMNB/KiCost.git
url = https://github.com/hildogjr/KiCost.git
branch = api_ext_plugin

View File

@ -12,17 +12,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- skip_bottom: bottom components aren't rotated.
- XLSX BoM: option to control the logo scale (#84)
- Import mechanism for filters and variants (#88)
- PDF PCB Print: option `hide_excluded` to hide components marked by the
`exclude_filter`.
https://forum.kicad.info/t/fab-drawing-for-only-through-hole-parts/
- Internal BoM: option to avoid merging components with empty fields.
Is named `merge_both_blank` and defaults to true.
- Internal BoM: when a `Value` field can't be interpreted as a `number+unit`,
and it contain at least one space, now we try to use the text before the
space. This helps for cases like "10K 1%".
- Generic filter: options to match if a field is/isn't defined.
- Internal BoM: two other options for the sorting criteria.
### Changed
- Internal BoM: now components with different Tolerance, Voltage, Current
and/or Power fields aren't grouped together.
These fields are now part of the default `group_fields`. (#79)
- Internal BoM: the field used for variants doesn't produce conflicts. (#100)
### Fixed
- Position files now defaults to use the auxiliar origin as KiCad.
Can be disabled to use absolute coordinates. (#87)
- Board View: flipped output. (#89)
- Board View: problems with netnames using spaces. (#90)
- Schematic load: problems with fields containing double quotes. (#98)
- `--list`: problems with layers and fields specific for the project.
(INTI-CMNB/kibot_variants_arduprog#4)
## [0.11.0] - 2021-04-25
### Added

View File

@ -305,6 +305,8 @@ Currently the only type available is `generic`.
- `column`: [string=''] Name of the column to apply the regular expression.
- *field*: Alias for column.
- `invert`: [boolean=false] Invert the regex match result.
- `match_if_field`: [boolean=false] Match if the field exists, no regex applied. Not affected by `invert`.
- `match_if_no_field`: [boolean=false] Match if the field doesn't exists, no regex applied. Not affected by `invert`.
- `regex`: [string=''] Regular expression to match.
- *regexp*: Alias for regex.
- `skip_if_no_field`: [boolean=false] Skip this test if the field doesn't exist.
@ -326,6 +328,8 @@ Currently the only type available is `generic`.
- `column`: [string=''] Name of the column to apply the regular expression.
- *field*: Alias for column.
- `invert`: [boolean=false] Invert the regex match result.
- `match_if_field`: [boolean=false] Match if the field exists, no regex applied. Not affected by `invert`.
- `match_if_no_field`: [boolean=false] Match if the field doesn't exists, no regex applied. Not affected by `invert`.
- `regex`: [string=''] Regular expression to match.
- *regexp*: Alias for regex.
- `skip_if_no_field`: [boolean=false] Skip this test if the field doesn't exist.
@ -713,9 +717,10 @@ Next time you need this list just use an alias, like this:
- `ignore_dnf`: [boolean=true] Exclude DNF (Do Not Fit) components.
- `int_qtys`: [boolean=true] Component quantities are always expressed as integers. Using the ceil() function.
- `merge_blank_fields`: [boolean=true] Component groups with blank fields will be merged into the most compatible group, where possible.
- `merge_both_blank`: [boolean=true] When creating groups two components with empty/missing field will be interpreted as with the same value.
- `no_conflict`: [list(string)] List of fields where we tolerate conflicts.
Use it to avoid undesired warnings.
By default the field indicated in `fit_field` and the field `part` are excluded.
By default the field indicated in `fit_field`, the field used for variants and the field `part` are excluded.
- `no_distributors`: [string|list(string)] Exclude this distributors list. They are removed after computing `distributors`.
- `normalize_locale`: [boolean=false] When normalizing values use the locale decimal point.
- `normalize_values`: [boolean=false] Try to normalize the R, L and C values, producing uniform units and prefixes.
@ -723,6 +728,7 @@ Next time you need this list just use an alias, like this:
- `output`: [string='%f-%i%v.%x'] filename for the output (%i=bom). Affected by global options.
- `ref_id`: [string=''] A prefix to add to all the references from this project. Used for multiple projects.
- `ref_separator`: [string=' '] Separator used for the list of references.
- `sort_style`: [string='type_value'] [type_value,type_value_ref,ref] Sorting criteria.
- `source_by_id`: [boolean=false] Generate the `Source BoM` column using the reference ID instead of the project name.
- `use_alt`: [boolean=false] Print grouped references in the alternate compressed style eg: R1-R7,R18.
- `variant`: [string=''] Board variant, used to determine which components
@ -737,9 +743,24 @@ Next time you need this list just use an alias, like this:
- `hide_stats_info`: [boolean=false] Hide statistics information.
- `highlight_empty`: [boolean=true] Use a color for empty cells. Applies only when `col_colors` is `true`.
- `kicost`: [boolean=false] Enable KiCost worksheet creation.
- `kicost_api_disable`: [string|list(string)=''] List of KiCost APIs to disable.
- `kicost_api_enable`: [string|list(string)=''] List of KiCost APIs to enable.
- `kicost_dist_desc`: [boolean=false] Used to add a column with the distributor's description. So you can chek this is the right component.
- `logo`: [string|boolean=''] PNG file to use as logo, use false to remove.
- `logo_scale`: [number=2] Scaling factor for the logo. Note that this value isn't honored by all spreadsheet software.
- `max_col_width`: [number=60] [20,999] Maximum column width (characters).
- `specs`: [boolean=false] Enable Specs worksheet creation. Contains specifications for the components.
Works with only some KiCost APIs.
- `specs_columns`: [list(dict)|list(string)] Which columns are included in the Specs worksheet. Use `References` for the references,
'Row' for the order and 'Sep' to separate groups at the same level. By default all are included.
Column names are distributor specific, the following aren't: '_desc', '_value', '_tolerance', '_footprint',
'_power', '_current', '_voltage', '_frequency', '_temp_coeff', '_manf', '_size'.
* Valid keys:
- `comment`: [string=''] Used as explanation for this column. The XLSX output uses it.
- `field`: [string=''] Name of the field to use for this column.
- `join`: [list(string)|string=''] List of fields to join to this column.
- `level`: [number=0] Used to group columns. The XLSX output uses it to collapse columns.
- `name`: [string=''] Name to display in the header. The field is used when empty.
- `style`: [string='modern-blue'] Head style: modern-blue, modern-green, modern-red and classic.
- `title`: [string='KiBot Bill of Materials'] BoM title.
@ -1275,6 +1296,7 @@ Next time you need this list just use an alias, like this:
- `dnf_filter`: [string|list(string)=''] Name of the filter to mark components as not fitted.
A short-cut to use for simple cases where a variant is an overkill.
- `drill_marks`: [string='full'] What to use to indicate the drill places, can be none, small or full (for real scale).
- `hide_excluded`: [boolean=false] Hide components in the Fab layer that are marked as excluded by a variant.
- `mirror`: [boolean=false] Print mirrored (X axis inverted). ONLY for KiCad 6.
- `monochrome`: [boolean=false] Print in black and white.
- `output`: [string='%f-%i%v.%x'] Filename for the output PDF (%i=layers, %x=pdf). Affected by global options.
@ -1890,7 +1912,7 @@ KiBot: KiCad automation tool for documents generation
Usage:
kibot [-b BOARD] [-e SCHEMA] [-c CONFIG] [-d OUT_DIR] [-s PRE]
[-q | -v...] [-i] [-m MKFILE] [-g DEF]... [TARGET...]
kibot [-v...] [-c PLOT_CONFIG] --list
kibot [-v...] [-b BOARD] [-e SCHEMA] [-c PLOT_CONFIG] --list
kibot [-v...] [-b BOARD] [-d OUT_DIR] [-p | -P] --example
kibot [-v...] --help-filters
kibot [-v...] --help-list-outputs

View File

@ -165,9 +165,11 @@ outputs:
int_qtys: true
# [boolean=true] Component groups with blank fields will be merged into the most compatible group, where possible
merge_blank_fields: true
# [boolean=true] When creating groups two components with empty/missing field will be interpreted as with the same value
merge_both_blank: true
# [list(string)] List of fields where we tolerate conflicts.
# Use it to avoid undesired warnings.
# By default the field indicated in `fit_field` and the field `part` are excluded
# By default the field indicated in `fit_field`, the field used for variants and the field `part` are excluded
no_conflict: ['Config', 'Part']
# [string|list(string)] Exclude this distributors list. They are removed after computing `distributors`
no_distributors:
@ -183,6 +185,8 @@ outputs:
ref_id: ''
# [string=' '] Separator used for the list of references
ref_separator: ' '
# [string='type_value'] [type_value,type_value_ref,ref] Sorting criteria
sort_style: 'type_value'
# [boolean=false] Generate the `Source BoM` column using the reference ID instead of the project name
source_by_id: false
# [boolean=false] Print grouped references in the alternate compressed style eg: R1-R7,R18
@ -208,12 +212,36 @@ outputs:
highlight_empty: true
# [boolean=false] Enable KiCost worksheet creation
kicost: false
# [string|list(string)=''] List of KiCost APIs to disable
kicost_api_disable: ''
# [string|list(string)=''] List of KiCost APIs to enable
kicost_api_enable: ''
# [boolean=false] Used to add a column with the distributor's description. So you can chek this is the right component
kicost_dist_desc: false
# [string|boolean=''] PNG file to use as logo, use false to remove
logo: ''
# [number=2] Scaling factor for the logo. Note that this value isn't honored by all spreadsheet software
logo_scale: 2
# [number=60] [20,999] Maximum column width (characters)
max_col_width: 60
# [boolean=false] Enable Specs worksheet creation. Contains specifications for the components.
# Works with only some KiCost APIs
specs: false
# [list(dict)|list(string)] Which columns are included in the Specs worksheet. Use `References` for the references,
# 'Row' for the order and 'Sep' to separate groups at the same level. By default all are included.
# Column names are distributor specific, the following aren't: '_desc', '_value', '_tolerance', '_footprint',
# '_power', '_current', '_voltage', '_frequency', '_temp_coeff', '_manf', '_size'
specs_columns:
# [string=''] Used as explanation for this column. The XLSX output uses it
- comment: ''
# [string=''] Name of the field to use for this column
field: 'Row'
# [list(string)|string=''] List of fields to join to this column
join: ''
# [number=0] Used to group columns. The XLSX output uses it to collapse columns
level: 0
# [string=''] Name to display in the header. The field is used when empty
name: 'Line'
# [string='modern-blue'] Head style: modern-blue, modern-green, modern-red and classic
style: 'modern-blue'
# [string='KiBot Bill of Materials'] BoM title
@ -879,6 +907,8 @@ outputs:
dnf_filter: ''
# [string='full'] What to use to indicate the drill places, can be none, small or full (for real scale)
drill_marks: 'full'
# [boolean=false] Hide components in the Fab layer that are marked as excluded by a variant
hide_excluded: false
# [boolean=false] Print mirrored (X axis inverted). ONLY for KiCad 6
mirror: false
# [boolean=false] Print in black and white

View File

@ -10,7 +10,7 @@
Usage:
kibot [-b BOARD] [-e SCHEMA] [-c CONFIG] [-d OUT_DIR] [-s PRE]
[-q | -v...] [-i] [-m MKFILE] [-g DEF]... [TARGET...]
kibot [-v...] [-c PLOT_CONFIG] --list
kibot [-v...] [-b BOARD] [-e SCHEMA] [-c PLOT_CONFIG] --list
kibot [-v...] [-b BOARD] [-d OUT_DIR] [-p | -P] --example
kibot [-v...] --help-filters
kibot [-v...] --help-list-outputs
@ -90,7 +90,9 @@ def list_pre_and_outs(logger, outputs):
if len(outputs):
logger.info('Outputs:')
for o in outputs:
config_output(o, dry=True)
# Note: we can't do a `dry` config because some layer and field names can be validated only if we
# load the schematic and the PCB.
config_output(o, dry=False)
logger.info('- '+str(o))
@ -341,15 +343,16 @@ def main():
with open(plot_config) as cf_file:
outputs = cr.read(cf_file)
# Determine the SCH file
GS.set_sch(solve_schematic(args.schematic, args.board_file, plot_config))
# Determine the PCB file
GS.set_pcb(solve_board_file(GS.sch_file, args.board_file))
# Is just list the available targets?
if args.list:
list_pre_and_outs(logger, outputs)
sys.exit(0)
# Determine the SCH file
GS.set_sch(solve_schematic(args.schematic, args.board_file, plot_config))
# Determine the PCB file
GS.set_pcb(solve_board_file(GS.sch_file, args.board_file))
if args.makefile:
# Only create a makefile
generate_makefile(args.makefile, plot_config, outputs)

View File

@ -12,7 +12,7 @@ All the logic to convert a list of components into the rows and columns used to
import locale
from copy import deepcopy
from math import ceil
from .units import compare_values, comp_match
from .units import compare_values, comp_match, get_last_warning
from .bom_writer import write_bom
from .columnlist import ColumnList
from ..misc import DNF, W_FIELDCONF
@ -70,6 +70,9 @@ def compare_field(c1, c2, field, cfg):
# If blank comparisons are allowed
if (c1_value == "" or c2_value == "") and cfg.merge_blank_fields:
return True
if not cfg.merge_both_blank and c1_value == "" and c2_value == "":
# Avoid merging two components with empty field
return False
return c1_value == c2_value
@ -346,7 +349,7 @@ class ComponentGroup(object):
return row
def get_value_sort(comp):
def get_value_sort(comp, fallback_ref=False):
""" Try to better sort R, L and C components """
res = comp.value_sort
if res:
@ -358,6 +361,8 @@ def get_value_sort(comp):
# milli Ohms
value = "{0:15d}".format(int(value * 1000 * mult + 0.1))
return value
if fallback_ref:
return comp.ref_prefix + "{0:15d}".format(_suffix_to_num(comp.ref_suffix))
return comp.value
@ -400,7 +405,14 @@ def group_components(cfg, components):
continue
# Cache the value used to sort
if c.ref_prefix in RLC_PREFIX and c.value.lower() not in DNF:
c.value_sort = comp_match(c.value, c.ref_prefix)
c.value_sort = comp_match(c.value, c.ref_prefix, c.ref)
if c.value_sort is None and (' ' in c.value):
# Try with the data before a space
value = c.value.split(' ')[0]
value_sort = comp_match(value, c.ref_prefix)
if value_sort is not None:
c.value_sort = value_sort
logger.warning(get_last_warning() + "Using `{}` for {} instead".format(value, c.ref))
else:
c.value_sort = None
# Try to add the component to an existing group
@ -429,8 +441,16 @@ def group_components(cfg, components):
if cfg.normalize_values:
g.fields[ColumnList.COL_VALUE_L] = normalize_value(g.components[0], decimal_point)
# Sort the groups
# First priority is the Type of component (e.g. R?, U?, L?)
groups = sorted(groups, key=lambda g: [g.components[0].ref_prefix, get_value_sort(g.components[0])])
if cfg.sort_style == 'type_value':
# First priority is the Type of component (e.g. R?, U?, L?)
# Second is the value
groups = sorted(groups, key=lambda g: [g.components[0].ref_prefix, get_value_sort(g.components[0])])
elif cfg.sort_style == 'type_value_ref':
# First priority is the Type of component (e.g. R?, U?, L?)
# Second is the value, but if we don't have a value we use the reference
groups = sorted(groups, key=lambda g: [g.components[0].ref_prefix, get_value_sort(g.components[0], True)])
else: # ref
groups = sorted(groups, key=lambda g: [g.components[0].ref_prefix, _suffix_to_num(g.components[0].ref_suffix)])
# Enumerate the groups and compute stats
n_total = 0
n_fitted = 0

View File

@ -43,6 +43,12 @@ UNIT_ALL = UNIT_R + UNIT_C + UNIT_L
match = None
# Current locale decimal point value
decimal_point = None
# Last warning
last_warning = ''
def get_last_warning():
return last_warning
def get_unit(unit, ref_prefix):
@ -98,12 +104,13 @@ def match_string():
return r"(\d*\.?\d*)\s*(" + group_string(PREFIX_ALL) + ")*(" + group_string(UNIT_ALL) + r")*(\d*)$"
def comp_match(component, ref_prefix):
def comp_match(component, ref_prefix, ref=None):
"""
Return a normalized value and units for a given component value string
e.g. comp_match('10R2') returns (10, R)
e.g. comp_match('3.3mOhm') returns (0.0033, R)
"""
global last_warning
original = component
# Remove useless spaces
component = component.strip()
@ -130,14 +137,17 @@ def comp_match(component, ref_prefix):
# Ignore case
match = re.compile(match_string(), flags=re.IGNORECASE)
where = ' in {}'.format(ref) if ref is not None else ''
result = match.match(component)
if not result:
logger.warning(W_BADVAL1 + "Malformed value: `{}` (no match)".format(original))
last_warning = W_BADVAL1
logger.warning(W_BADVAL1 + "Malformed value: `{}` (no match{})".format(original, where))
return None
value, prefix, units, post = result.groups()
if value == '.':
logger.warning(W_BADVAL2 + "Malformed value: `{}` (reduced to decimal point)".format(original))
last_warning = W_BADVAL2
logger.warning(W_BADVAL2 + "Malformed value: `{}` (reduced to decimal point{})".format(original, where))
return None
if value == '':
value = '0'
@ -148,7 +158,9 @@ def comp_match(component, ref_prefix):
# We will also have a trailing number
if post:
if "." in value:
logger.warning(W_BADVAL3 + "Malformed value: `{}` (unit split, but contains decimal point)".format(original))
last_warning = W_BADVAL3
logger.warning(W_BADVAL3 + "Malformed value: `{}` (unit split, but contains decimal point{})".
format(original, where))
return None
value = float(value)
postValue = float(post) / (10 ** len(post))

View File

@ -17,7 +17,8 @@ from base64 import b64decode
from .columnlist import ColumnList
from .kibot_logo import KIBOT_LOGO
from .. import log
from ..misc import W_NOKICOST, W_UNKDIST
from ..misc import W_NOKICOST, W_UNKDIST, KICOST_ERROR, W_BADFIELD
from ..error import trace_dump
from ..__main__ import __version__
try:
from xlsxwriter import Workbook
@ -37,14 +38,16 @@ try:
sys.path.insert(0, rel_path)
# Init the logger first
logger = log.get_logger(__name__)
from kicost.global_vars import set_logger
from kicost.global_vars import set_logger, KiCostError
set_logger(logger)
from kicost import PartGroup
from kicost.kicost import query_part_info
from kicost.spreadsheet import create_worksheet, Spreadsheet
from kicost.distributors import (init_distributor_dict, set_distributors_logger, get_distributors_list,
get_dist_name_from_label, set_distributors_progress)
get_dist_name_from_label, set_distributors_progress, is_valid_api,
configure_from_environment, configure_apis)
from kicost.edas import set_edas_logger
from kicost.config import load_config
# Progress mechanism: use the one declared in __main__ (TQDM)
from kicost.__main__ import ProgressConsole
set_distributors_progress(ProgressConsole)
@ -66,10 +69,11 @@ GREY_L = "#f3f3f3"
HEAD_COLOR_R = "#982020"
HEAD_COLOR_G = "#009879"
HEAD_COLOR_B = "#0e4e8e"
DEFAULT_FMT = {'text_wrap': True, 'align': 'center_across', 'valign': 'vjustify'}
DEFAULT_FMT = {'text_wrap': True, 'align': 'center_across', 'valign': 'vcenter'}
KICOST_COLUMNS = {'refs': ColumnList.COL_REFERENCE,
'desc': ColumnList.COL_DESCRIPTION,
'qty': ColumnList.COL_GRP_BUILD_QUANTITY}
SPECS_GENERATED = set((ColumnList.COL_REFERENCE_L, ColumnList.COL_ROW_NUMBER_L, 'sep'))
def bg_color(col):
@ -246,6 +250,75 @@ def create_color_ref(workbook, col_colors, hl_empty, fmt_cols, do_kicost, kicost
worksheet.write_string(row, 0, label, format)
def get_spec(part, name):
if name[0] != '_':
return part.specs.get(name, ['', ''])
name = name[1:]
for k, v in part.dd.items():
val = v.extra_info.get(name, None)
if val:
return [name, val]
return ['', '']
def create_meta(workbook, name, columns, parts, fmt_head, fmt_cols, max_w, rename, levels, comments, join):
worksheet = workbook.add_worksheet(name)
col_w = []
row_h = 1
for c, col in enumerate(columns):
name = rename.get(col.lower(), col) if rename else col
worksheet.write_string(0, c, name, fmt_head)
text_l = max(len(col), 6)
if text_l > max_w:
h = len(wrap(col, max_w))
row_h = max(row_h, h)
text_l = max_w
col_w.append(text_l)
if row_h > 1:
worksheet.set_row(0, 15.0*row_h)
for r, part in enumerate(parts):
# Add the references as another spec
part.specs[ColumnList.COL_REFERENCE_L] = (ColumnList.COL_REFERENCE, part.collapsed_refs)
# Also add the row
part.specs[ColumnList.COL_ROW_NUMBER_L] = (ColumnList.COL_ROW_NUMBER, str(r+1))
row_h = 1
for c, col in enumerate(columns):
col_l = col.lower()
if col_l == 'sep':
col_w[c] = 0
continue
v = get_spec(part, col_l)
text = v[1]
# Append text from other fields
if join:
for j in join:
if j[0] == col_l:
for c_join in j[1:]:
v = part.specs.get(c_join, None)
if v:
text += ' ' + v[1]
text_l = len(text)
if not text_l:
continue
fmt_kind = 0 if col_l in SPECS_GENERATED else 2
worksheet.write_string(r+1, c, text, fmt_cols[fmt_kind][r % 2])
if text_l > col_w[c]:
if text_l > max_w:
h = len(wrap(text, max_w))
row_h = max(row_h, h)
text_l = max_w
col_w[c] = text_l
if row_h > 1:
worksheet.set_row(r+1, 15.0*row_h)
for i, width in enumerate(col_w):
ops = {'level': levels[i] if levels else 0}
if not width:
ops['hidden'] = 1
if comments and comments[i]:
worksheet.write_comment(0, i, comments[i])
worksheet.set_column(i, i, width, None, ops)
def adjust_widths(worksheet, column_widths, max_width, levels):
c_levels = len(levels)
for i, width in enumerate(column_widths):
@ -375,7 +448,9 @@ def remove_unknown_distributors(distributors, available, silent):
d = d.lower()
if d not in available:
# Is the label of the column?
d = get_dist_name_from_label(d)
new_d = get_dist_name_from_label(d)
if new_d is not None:
d = new_d
if d not in available:
if not silent:
logger.warning(W_UNKDIST+'Unknown distributor `{}`'.format(d))
@ -412,7 +487,40 @@ def compute_qtys(cfg, g):
return [str(g.get_count(sch.name)) for sch in cfg.aggregate]
def create_kicost_sheet(workbook, groups, image_data, fmt_title, fmt_info, fmt_subtitle, cfg):
def create_meta_sheets(workbook, used_parts, fmt_head, fmt_cols, cfg, ss):
if cfg.xlsx.specs:
meta_names = ['Specs', 'Specs (DNF)']
for ws in range(2):
spec_cols = {}
spec_cols_l = set()
parts = used_parts[ws]
for part in parts:
for name_l, v in part.specs.items():
spec_cols_l.add(name_l)
spec = v[0]
if spec in spec_cols:
spec_cols[spec] += 1
else:
spec_cols[spec] = 1
if len(spec_cols):
columns = cfg.xlsx.s_columns
if columns is None:
# Use all columns, sort them by relevance (most used) and alphabetically
c = len(parts)
columns = sorted(spec_cols, key=lambda k: (c - spec_cols[k], k))
columns.insert(0, ColumnList.COL_REFERENCE)
else:
# Inform about missing columns
for c in columns:
col = c.lower()
if ((col[0] == '_' and col[1:] not in ss.extra_info_display) or
(col[0] != '_' and col not in spec_cols_l and col not in SPECS_GENERATED)):
logger.warning(W_BADFIELD+'Invalid Specs column name `{}` {}'.format(c, col[1:]))
create_meta(workbook, meta_names[ws], columns, parts, fmt_head, fmt_cols, cfg.xlsx.max_col_width,
cfg.xlsx.s_rename, cfg.xlsx.s_levels, cfg.xlsx.s_comments, cfg.xlsx.s_join)
def _create_kicost_sheet(workbook, groups, image_data, fmt_title, fmt_info, fmt_subtitle, fmt_head, fmt_cols, cfg):
if not KICOST_SUPPORT:
logger.warning(W_NOKICOST, 'KiCost sheet requested but failed to load KiCost support')
return
@ -426,6 +534,19 @@ def create_kicost_sheet(workbook, groups, image_data, fmt_title, fmt_info, fmt_s
# Force KiCost to use our logger
set_distributors_logger(logger)
set_edas_logger(logger)
# Load KiCost config (includes APIs config)
api_options = load_config()
# Environment with overwrite
configure_from_environment(api_options, True)
# Filter which APIs we want
for api in cfg.xlsx.kicost_api_disable:
if is_valid_api(api):
api_options[api]['enable'] = False
for api in cfg.xlsx.kicost_api_enable:
if is_valid_api(api):
api_options[api]['enable'] = True
# Configure the APIs
configure_apis(api_options)
# Start with a clean list of available distributors
init_distributor_dict()
# Create the projects information structure
@ -437,6 +558,13 @@ def create_kicost_sheet(workbook, groups, image_data, fmt_title, fmt_info, fmt_s
Spreadsheet.ADJUST_ROW_AND_COL_SIZE = True
Spreadsheet.MAX_COL_WIDTH = cfg.xlsx.max_col_width
Spreadsheet.PART_NSEQ_SEPRTR = cfg.ref_separator
if hasattr(Spreadsheet, 'SUPPRESS_DIST_DESC'):
Spreadsheet.SUPPRESS_DIST_DESC = not cfg.xlsx.kicost_dist_desc
# Keep our sorting
try:
Spreadsheet.SORT_GROUPS = False
except Exception:
pass
# Make the version less intrusive
Spreadsheet.WRK_FORMATS['about_msg']['font_size'] = 8
# Don 't add project info, we add our own data
@ -475,6 +603,7 @@ def create_kicost_sheet(workbook, groups, image_data, fmt_title, fmt_info, fmt_s
id = new_id.lower()
if id in cfg.column_rename:
v['label'] = cfg.column_rename[id]
used_parts = []
for ws in range(2):
# Second pass is DNF
dnf = ws == 1
@ -523,6 +652,9 @@ def create_kicost_sheet(workbook, groups, image_data, fmt_title, fmt_info, fmt_s
if cfg.xlsx.title:
wks.set_row(0, 32)
wks.merge_range(0, col1, 0, ss.globals_width, cfg.xlsx.title, fmt_title)
used_parts.append(parts)
# Specs sheets
create_meta_sheets(workbook, used_parts, fmt_head, fmt_cols, cfg, ss)
colors = {}
colors['Best price'] = ss.wrk_formats['best_price']
colors['No manufacturer or distributor code'] = ss.wrk_formats['not_manf_codes']
@ -536,6 +668,15 @@ def create_kicost_sheet(workbook, groups, image_data, fmt_title, fmt_info, fmt_s
return colors
def create_kicost_sheet(workbook, groups, image_data, fmt_title, fmt_info, fmt_subtitle, fmt_head, fmt_cols, cfg):
try:
return _create_kicost_sheet(workbook, groups, image_data, fmt_title, fmt_info, fmt_subtitle, fmt_head, fmt_cols, cfg)
except KiCostError as e:
trace_dump()
logger.error('KiCost error: `{}` ({})'.format(e.msg, e.id))
exit(KICOST_ERROR)
def write_xlsx(filename, groups, col_fields, head_names, cfg):
"""
Write BoM out to a XLSX file
@ -660,7 +801,8 @@ def write_xlsx(filename, groups, col_fields, head_names, cfg):
# Optionally add KiCost information
kicost_colors = None
if cfg.xlsx.kicost:
kicost_colors = create_kicost_sheet(workbook, groups, image_data, fmt_title, fmt_info, fmt_subtitle, cfg)
kicost_colors = create_kicost_sheet(workbook, groups, image_data, fmt_title, fmt_info, fmt_subtitle, fmt_head,
fmt_cols, cfg)
# Add a sheet for the color references
create_color_ref(workbook, cfg.xlsx.col_colors, hl_empty, fmt_cols, cfg.xlsx.kicost and KICOST_SUPPORT, kicost_colors)

View File

@ -124,6 +124,10 @@ class Generic(BaseFilter): # noqa: F821
if reg.skip_if_no_field and not c.is_field(reg.column):
# Skip the check if the field doesn't exist
continue
if reg.match_if_field and c.is_field(reg.column):
return True
if reg.match_if_no_field and not c.is_field(reg.column):
return True
field_value = c.get_field_value(reg.column)
res = reg.regex.search(field_value)
if reg.invert:
@ -145,6 +149,10 @@ class Generic(BaseFilter): # noqa: F821
if reg.skip_if_no_field and not c.is_field(reg.column):
# Skip the check if the field doesn't exist
continue
if reg.match_if_field and c.is_field(reg.column):
return True
if reg.match_if_no_field and not c.is_field(reg.column):
return True
field_value = c.get_field_value(reg.column)
res = reg.regex.search(field_value)
if reg.invert:

View File

@ -18,7 +18,7 @@ from .config import KiConf, un_quote
from ..gs import GS
from ..misc import (W_BADPOLI, W_POLICOORDS, W_BADSQUARE, W_BADCIRCLE, W_BADARC, W_BADTEXT, W_BADPIN, W_BADCOMP, W_BADDRAW,
W_UNKDCM, W_UNKAR, W_ARNOPATH, W_ARNOREF, W_MISCFLD, W_EXTRASPC, W_NOLIB, W_INCPOS, W_NOANNO, W_MISSLIB,
W_MISSDCM, W_MISSCMP, W_MISFLDNAME)
W_MISSDCM, W_MISSCMP, W_MISFLDNAME, W_NOENDLIB)
from .. import log
logger = log.get_logger(__name__)
@ -105,16 +105,16 @@ class LibComponentField(object):
""" A field for a component in the library.
Almost the same as a field in the schematic, but incompatible!!! """
# F n "text" posx posy dimension orientation visibility hjustify vjustify/italic/bold "name"
field_re = re.compile(r'F\s*(\d+)\s+' # 0 Field number
r'"([^"]*)"\s+' # 1 Field value
r'(-?\d+)\s+' # 2 Pos X
r'(-?\d+)\s+' # 3 Pos Y
r'(\d+)\s+' # 4 Dimension
r'([HV])\s+' # 5 Orientation
r'([VI])\s+' # 6 Visibility
r'([LRCBT])\s+' # 7 HJustify
r'([LRCBT][IN][BN])\s*' # 8 VJustify+Italic+Bold
r'("[^"]*")?') # 9 Name for user fields
field_re = re.compile(r'F\s*(\d+)\s+' # 0 Field number
r'"((?:[^\\]|(?:\\.))*)"\s+' # 1 Field value
r'(-?\d+)\s+' # 2 Pos X
r'(-?\d+)\s+' # 3 Pos Y
r'(\d+)\s+' # 4 Dimension
r'([HV])\s+' # 5 Orientation
r'([VI])\s+' # 6 Visibility
r'([LRCBT])\s+' # 7 HJustify
r'([LRCBT][IN][BN])\s*' # 8 VJustify+Italic+Bold
r'("(?:[^\\]|(?:\\.))*")?') # 9 Name for user fields
def __init__(self):
super().__init__()
@ -510,6 +510,10 @@ class LibComponent(object):
self.draw = []
line = f.get_line()
while not line.startswith('ENDDEF'):
if len(line) == 0:
# Skip empty lines
line = f.get_line()
continue
if line[0] == 'F':
# A field
field = LibComponentField.parse(line, lib_name, f)
@ -655,7 +659,11 @@ class SymLib(object):
self.alias[a] = o
else:
raise SchLibError('Unknown library entry', line, f)
line = f.get_line()
try:
line = f.get_line()
except SchLibError:
logger.warning(W_NOENDLIB + 'Library without end of file comment: `{}`'.format(file))
break
class DocLibEntry(object):
@ -713,8 +721,8 @@ class DocLib(object):
class SchematicField(object):
# F n "text" orientation posx posy dimension flags hjustify vjustify/italic/bold "name"
field_re = re.compile(r'F\s*(\d+)\s+"([^"]*)"\s+([HV])\s+(-?\d+)\s+(-?\d+)\s+(\d+)\s+(\d+)'
r'\s+([LRCBT])\s+([LRCBT][IN][BN])\s*("[^"]*")?')
field_re = re.compile(r'F\s*(\d+)\s+"((?:[^\\]|(?:\\.))*)"\s+([HV])\s+(-?\d+)\s+(-?\d+)\s+(\d+)\s+(\d+)'
r'\s+([LRCBT])\s+([LRCBT][IN][BN])\s*("(?:[^\\]|(?:\\.))*")?')
def __init__(self):
super().__init__()

View File

@ -34,6 +34,7 @@ PCBDRAW_ERR = 20
SVG_SCH_PRINT = 21
CORRUPTED_SCH = 22
WRONG_INSTALL = 23
KICOST_ERROR = 24
error_level_to_name = ['NONE',
'INTERNAL_ERROR',
'WRONG_ARGUMENTS',
@ -58,6 +59,7 @@ error_level_to_name = ['NONE',
'SVG_SCH_PRINT',
'CORRUPTED_SCH',
'WRONG_INSTALL',
'KICOST_ERROR',
]
CMD_EESCHEMA_DO = 'eeschema_do'
URL_EESCHEMA_DO = 'https://github.com/INTI-CMNB/kicad-automation-scripts'
@ -201,6 +203,7 @@ W_NOKICOST = '(W066) '
W_UNKOUT = '(W067) '
W_NOFILTERS = '(W068) '
W_NOVARIANTS = '(W069) '
W_NOENDLIB = '(W070) '
class Rect(object):

View File

@ -104,6 +104,10 @@ class BoMRegex(Optionable):
""" {regex} """
self.skip_if_no_field = False
""" Skip this test if the field doesn't exist """
self.match_if_field = False
""" Match if the field exists, no regex applied. Not affected by `invert` """
self.match_if_no_field = False
""" Match if the field doesn't exists, no regex applied. Not affected by `invert` """
self.invert = False
""" Invert the regex match result """
@ -286,6 +290,38 @@ class VariantOptions(BaseOptions):
for gi in self.old_badhes:
gi.SetLayer(self.badhes)
def remove_fab(self, board, comps_hash):
""" Remove from Fab the excluded components. """
ffab = board.GetLayerID('F.Fab')
bfab = board.GetLayerID('B.Fab')
old_ffab = []
old_bfab = []
rescue = board.GetLayerID('Rescue')
for m in board.GetModules():
ref = m.GetReference()
c = comps_hash.get(ref, None)
if not c.included:
# Remove any graphical item in the *.Fab layers
for gi in m.GraphicalItems():
l_gi = gi.GetLayer()
if l_gi == ffab:
gi.SetLayer(rescue)
old_ffab.append(gi)
if l_gi == bfab:
gi.SetLayer(rescue)
old_bfab.append(gi)
# Store the data to undo the above actions
self.old_ffab = old_ffab
self.old_bfab = old_bfab
self.ffab = ffab
self.bfab = bfab
def restore_fab(self, board, comps_hash):
for gi in self.old_ffab:
gi.SetLayer(self.ffab)
for gi in self.old_bfab:
gi.SetLayer(self.bfab)
def run(self, output_dir):
""" Makes the list of components available """
if not self.dnf_filter and not self.variant:

View File

@ -163,9 +163,60 @@ class BoMXLSX(BoMLinkable):
""" Head style: modern-blue, modern-green, modern-red and classic """
self.kicost = False
""" Enable KiCost worksheet creation """
self.kicost_api_enable = Optionable
""" [string|list(string)=''] List of KiCost APIs to enable """
self.kicost_api_disable = Optionable
""" [string|list(string)=''] List of KiCost APIs to disable """
self.kicost_dist_desc = False
""" Used to add a column with the distributor's description. So you can chek this is the right component """
self.specs = False
""" Enable Specs worksheet creation. Contains specifications for the components.
Works with only some KiCost APIs """
self.specs_columns = BoMColumns
""" [list(dict)|list(string)] Which columns are included in the Specs worksheet. Use `References` for the references,
'Row' for the order and 'Sep' to separate groups at the same level. By default all are included.
Column names are distributor specific, the following aren't: '_desc', '_value', '_tolerance', '_footprint',
'_power', '_current', '_voltage', '_frequency', '_temp_coeff', '_manf', '_size' """
self.logo_scale = 2
""" Scaling factor for the logo. Note that this value isn't honored by all spreadsheet software """
def process_columns_config(self, cols):
if isinstance(cols, type):
return (None, None, None, None, None)
columns = []
column_levels = []
column_comments = []
column_rename = {}
join = []
# Create the different lists
for col in cols:
if isinstance(col, str):
# Just a string, add to the list of used
new_col = col
new_col_l = new_col.lower()
level = 0
comment = ''
if new_col_l[0] == '_':
column_rename[new_col_l] = new_col_l[1:].capitalize()
else:
# A complete entry
new_col = col.field
new_col_l = new_col.lower()
# A column rename
if col.name:
column_rename[new_col_l] = col.name
elif new_col_l[0] == '_':
column_rename[new_col_l] = new_col_l[1:].capitalize()
# Attach other columns
if col.join:
join.append(col.join)
level = col.level
comment = col.comment
columns.append(new_col)
column_levels.append(level)
column_comments.append(comment)
return (columns, column_levels, column_comments, column_rename, join)
def config(self, parent):
super().config(parent)
# Style
@ -173,6 +224,18 @@ class BoMXLSX(BoMLinkable):
self.style = 'modern-blue'
if self.style not in VALID_STYLES:
raise KiPlotConfigurationError('Unknown style `{}`'.format(self.style))
# KiCost APIs
if isinstance(self.kicost_api_enable, type):
self.kicost_api_enable = []
elif isinstance(self.kicost_api_enable, str):
self.kicost_api_enable = [self.kicost_api_enable]
if isinstance(self.kicost_api_disable, type):
self.kicost_api_disable = []
elif isinstance(self.kicost_api_disable, str):
self.kicost_api_disable = [self.kicost_api_disable]
# Specs columns
(self.s_columns, self.s_levels, self.s_comments, self.s_rename,
self.s_join) = self.process_columns_config(self.specs_columns)
class ComponentAliases(Optionable):
@ -270,6 +333,8 @@ class BoMOptions(BaseOptions):
""" Connectors with the same footprints will be grouped together, independent of the name of the connector """
self.merge_blank_fields = True
""" Component groups with blank fields will be merged into the most compatible group, where possible """
self.merge_both_blank = True
""" When creating groups two components with empty/missing field will be interpreted as with the same value """
self.group_fields = GroupFields
""" [list(string)] List of fields used for sorting individual components into groups.
Components which match (comparing *all* fields) will be grouped together.
@ -293,7 +358,7 @@ class BoMOptions(BaseOptions):
self.no_conflict = NoConflict
""" [list(string)] List of fields where we tolerate conflicts.
Use it to avoid undesired warnings.
By default the field indicated in `fit_field` and the field `part` are excluded """
By default the field indicated in `fit_field`, the field used for variants and the field `part` are excluded """
self.aggregate = Aggregate
""" [list(dict)] Add components from other projects """
self.ref_id = ''
@ -306,6 +371,8 @@ class BoMOptions(BaseOptions):
""" [string|list(string)] Include this distributors list. Default is all the available """
self.no_distributors = Optionable
""" [string|list(string)] Exclude this distributors list. They are removed after computing `distributors` """
self.sort_style = 'type_value'
""" [type_value,type_value_ref,ref] Sorting criteria """
self._format_example = 'CSV'
super().__init__()
@ -457,6 +524,9 @@ class BoMOptions(BaseOptions):
if isinstance(self.no_conflict, type):
no_conflict.add(self.fit_field)
no_conflict.add('part')
var_field = self.variant.get_variant_field()
if var_field is not None:
no_conflict.add(var_field)
else:
for field in self.no_conflict:
no_conflict.add(field.lower())

View File

@ -41,6 +41,8 @@ class PDF_Pcb_PrintOptions(VariantOptions):
""" Print layers in separated pages """
self.mirror = False
""" Print mirrored (X axis inverted). ONLY for KiCad 6 """
self.hide_excluded = False
""" Hide components in the Fab layer that are marked as excluded by a variant """
super().__init__()
self._expand_ext = 'pdf'
@ -75,6 +77,8 @@ class PDF_Pcb_PrintOptions(VariantOptions):
comps_hash = self.get_refs_hash()
self.cross_modules(board, comps_hash)
self.remove_paste_and_glue(board, comps_hash)
if self.hide_excluded:
self.remove_fab(board, comps_hash)
# Save the PCB to a temporal file
with NamedTemporaryFile(mode='w', suffix='.kicad_pcb', delete=False) as f:
fname = f.name
@ -84,6 +88,8 @@ class PDF_Pcb_PrintOptions(VariantOptions):
fproj = self._copy_project(fname)
self.uncross_modules(board, comps_hash)
self.restore_paste_and_glue(board, comps_hash)
if self.hide_excluded:
self.restore_fab(board, comps_hash)
return fname, fproj
def get_targets(self, out_dir):

View File

@ -39,6 +39,10 @@ class BaseVariant(RegVariant):
""" [string|list(string)=''] Name of the filter to mark components as 'Do Not Change'.
Use '_kibom_dnc' for the default KiBoM behavior """
def get_variant_field(self):
''' Returns the name of the field used to determine if the component belongs to teh variant '''
return None
def filter(self, comps):
# Apply all the filters
comps = apply_pre_transform(comps, self.pre_transform)

View File

@ -32,6 +32,10 @@ class IBoM(BaseVariant): # noqa: F821
self.variants_whitelist = Optionable
""" [string|list(string)=''] List of board variants to include in the BOM """
def get_variant_field(self):
''' Returns the name of the field used to determine if the component belongs to teh variant '''
return self.variant_field
def config(self, parent):
super().config(parent)
self.pre_transform = BaseFilter.solve_filter(self.pre_transform, 'pre_transform', is_transform=True)

View File

@ -33,6 +33,10 @@ class KiBoM(BaseVariant): # noqa: F821
self.variant = Optionable
""" [string|list(string)=''] Board variant(s) """
def get_variant_field(self):
''' Returns the name of the field used to determine if the component belongs to teh variant '''
return self.config_field
def set_def_filters(self, exclude_filter, dnf_filter, dnc_filter):
""" Filters delegated to the variant """
self._def_exclude_filter = exclude_filter

View File

@ -36,6 +36,10 @@ class KiCost(BaseVariant): # noqa: F821
""" Valid separators for variants in the variant field.
Each character is a valid separator """
def get_variant_field(self):
''' Returns the name of the field used to determine if the component belongs to teh variant '''
return self.variant_field
def config(self, parent):
super().config(parent)
self.pre_transform = BaseFilter.solve_filter(self.pre_transform, 'pre_transform',

@ -1 +1 @@
Subproject commit 7906366a496dc5cc3549152a16815aa403e0ea61
Subproject commit 28488c34332cdaf83aa159b387a8b75b22af3f58

View File

@ -1915,7 +1915,7 @@ F 0 "R1" V 1093 3450 50 0000 C CNN
F 1 "R" V 1184 3450 50 0000 C CNN
F 2 "" V 1230 3450 50 0001 C CNN
F 3 "~" H 1300 3450 50 0001 C CNN
F 4 "Hi!" H 1300 3450 50 0001 C CNN "Test"
F 4 "Hi! \"quoted text\"" H 1300 3450 50 0001 C CNN "Test"
1 1300 3450
0 1 1 0
$EndComp

View File

@ -303,7 +303,7 @@ def test_auto_pcb_and_cfg_5(test_dir):
def test_list(test_dir):
ctx = context.TestContext(test_dir, 'List', '3Rs', 'pre_and_position', POS_DIR)
ctx.run(extra=['--list'], no_verbose=True, no_out_dir=True, no_board_file=True)
ctx.run(extra=['--list'], no_verbose=True, no_out_dir=True)
assert ctx.search_out('run_erc: True')
assert ctx.search_out('run_drc: True')

View File

@ -23,6 +23,13 @@ MODE_SCH = 1
MODE_PCB = 0
# Defined as True to collect real world queries
ADD_QUERY_TO_KNOWN = False
# ***** DEBUG!!!
# Test Digi-Key API. We need
# os.environ['DIGIKEY_CACHE_TTL'] = '-1'
# os.environ['DIGIKEY_STORAGE_PATH'] = op.abspath(op.join(op.dirname(__file__), '../../submodules/KiCost/tests/digikey'))
# logger.setLevel(1) # Max. KiCost debug
# ***** End of DEBUG!!!
ng_ver = os.environ.get('KIAUS_USE_NIGHTLY')
if ng_ver:

View File

@ -29,3 +29,4 @@ outputs:
name: Manufacturer P/N
xlsx:
kicost: true
kicost_api_disable: 'Digi-Key'

View File

@ -39,3 +39,4 @@ outputs:
- Digi-Key
xlsx:
kicost: true
kicost_api_disable: 'Digi-Key'

View File

@ -36,3 +36,4 @@ outputs:
- 'Voltage'
xlsx:
kicost: true
kicost_api_disable: 'Digi-Key'