Changed how variant field renamer is implemented.
- Now is a separated filter type (`var_rename`). - Now all variants support a `pre_transform` filter list. - An internal `_var_rename` filter is defined (default).
This commit is contained in:
parent
986f0c7157
commit
204ad189de
|
|
@ -271,7 +271,7 @@ Currently the only type available is `generic`.
|
|||
#### Supported filters:
|
||||
|
||||
- generic: Generic filter
|
||||
This filter is based on regular exressions.
|
||||
This filter is based on regular expressions.
|
||||
It also provides some shortcuts for common situations.
|
||||
Note that matches aren't case sensitive and spaces at the beggining and the end are removed.
|
||||
* Valid keys:
|
||||
|
|
@ -312,6 +312,12 @@ Currently the only type available is `generic`.
|
|||
Use `dnf_list` for ['dnf', 'dnl', 'dnp', 'do not fit', 'do not load', 'do not place', 'no stuff', 'nofit', 'noload', 'noplace', 'nostuff', 'not fitted', 'not loaded', 'not placed'].
|
||||
Use `dnc_list` for ['dnc', 'do not change', 'fixed', 'no change'].
|
||||
- `name`: [string=''] Used to identify this particular filter definition.
|
||||
- var_rename: Var_Rename
|
||||
This filter implements the VARIANT:FIELD=VALUE renamer to get FIELD=VALUE when VARIANT is in use.
|
||||
* Valid keys:
|
||||
- `comment`: [string=''] A comment for documentation purposes.
|
||||
- `name`: [string=''] Used to identify this particular filter definition.
|
||||
- `separator`: [string=':'] Separator used between the variant and the field name.
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
# License: GPL-3.0
|
||||
# Project: KiBot (formerly KiPlot)
|
||||
from .registrable import RegFilter, Registrable, RegOutput
|
||||
from .misc import IFILL_MECHANICAL
|
||||
from .misc import IFILT_MECHANICAL, IFILT_VAR_RENAME
|
||||
from .error import KiPlotConfigurationError
|
||||
from .bom.columnlist import ColumnList
|
||||
from .macros import macros, document # noqa: F401
|
||||
|
|
@ -65,11 +65,11 @@ class NotFilter(Registrable):
|
|||
return not self._filter.filter(comp)
|
||||
|
||||
|
||||
def reset_filters(comps):
|
||||
for c in comps:
|
||||
c.included = True
|
||||
c.fitted = True
|
||||
c.fixed = False
|
||||
def apply_pre_transform(comps, filter):
|
||||
if filter:
|
||||
logger.debug('Applying transform filter `{}`'.format(filter.name))
|
||||
for c in comps:
|
||||
filter.filter(c)
|
||||
|
||||
|
||||
def apply_exclude_filter(comps, filter):
|
||||
|
|
@ -125,6 +125,14 @@ class BaseFilter(RegFilter):
|
|||
logger.debug('Creating internal filter: '+str(o_tree))
|
||||
return o_tree
|
||||
|
||||
@staticmethod
|
||||
def _create_var_rename(name):
|
||||
o_tree = {'name': name}
|
||||
o_tree['type'] = 'var_rename'
|
||||
o_tree['comment'] = 'Internal default variant field renamer filter'
|
||||
logger.debug('Creating internal filter: '+str(o_tree))
|
||||
return o_tree
|
||||
|
||||
@staticmethod
|
||||
def _create_kibom_dnx(name):
|
||||
type = name[7:10]
|
||||
|
|
@ -146,10 +154,12 @@ class BaseFilter(RegFilter):
|
|||
|
||||
@staticmethod
|
||||
def _create_internal_filter(name):
|
||||
if name == IFILL_MECHANICAL:
|
||||
if name == IFILT_MECHANICAL:
|
||||
tree = BaseFilter._create_mechanical(name)
|
||||
elif name.startswith('_kibom_dn') and len(name) >= 10:
|
||||
tree = BaseFilter._create_kibom_dnx(name)
|
||||
elif name == IFILT_VAR_RENAME:
|
||||
tree = BaseFilter._create_var_rename(name)
|
||||
else:
|
||||
return None
|
||||
filter = RegFilter.get_class_for(tree['type'])()
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class DNFList(Optionable):
|
|||
@filter_class
|
||||
class Generic(BaseFilter): # noqa: F821
|
||||
""" Generic filter
|
||||
This filter is based on regular exressions.
|
||||
This filter is based on regular expressions.
|
||||
It also provides some shortcuts for common situations.
|
||||
Note that matches aren't case sensitive and spaces at the beggining and the end are removed """
|
||||
def __init__(self):
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020 Salvador E. Tropea
|
||||
# Copyright (c) 2020 Instituto Nacional de Tecnología Industrial
|
||||
# License: GPL-3.0
|
||||
# Project: KiBot (formerly KiPlot)
|
||||
"""
|
||||
Implements the VARIANT:FIELD=VALUE renamer to get FIELD=VALUE when VARIANT is in use.
|
||||
"""
|
||||
# from re import compile, IGNORECASE
|
||||
# from .optionable import Optionable
|
||||
# from .bom.columnlist import ColumnList
|
||||
from .gs import GS
|
||||
# from .misc import DNF, DNC
|
||||
from .macros import macros, document, filter_class # noqa: F401
|
||||
# from .out_base import BoMRegex
|
||||
from . import log
|
||||
|
||||
logger = log.get_logger(__name__)
|
||||
|
||||
|
||||
@filter_class
|
||||
class Var_Rename(BaseFilter): # noqa: F821
|
||||
""" Var_Rename
|
||||
This filter implements the VARIANT:FIELD=VALUE renamer to get FIELD=VALUE when VARIANT is in use """
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
with document:
|
||||
self.separator = ':'
|
||||
""" Separator used between the variant and the field name """
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
if not self.separator:
|
||||
self.separator = ':'
|
||||
|
||||
def filter(self, comp):
|
||||
""" Look for fields containing VARIANT:FIELD used to change fields according to the variant """
|
||||
if not GS.variant:
|
||||
# No variant in use, nothing to do
|
||||
return
|
||||
for variant in GS.variant:
|
||||
for name, value in comp.get_user_fields():
|
||||
res = name.strip().split(self.separator)
|
||||
if len(res) == 2:
|
||||
f_variant = res[0].lower()
|
||||
f_field = res[1].lower()
|
||||
if f_variant == variant:
|
||||
if GS.debug_level > 2:
|
||||
logger.debug('ref: {} value: {} -> {}'.format(comp.ref, comp.get_field_value(f_field), value))
|
||||
comp.set_field(f_field, value)
|
||||
|
|
@ -55,6 +55,8 @@ class GS(object):
|
|||
pcb_date = None
|
||||
pcb_rev = None
|
||||
pcb_comp = None
|
||||
# Current variant/s
|
||||
variant = None
|
||||
# Global defaults
|
||||
# This is used as default value for classes supporting "output" option
|
||||
def_global_output = '%f-%i%v.%x'
|
||||
|
|
|
|||
|
|
@ -72,7 +72,8 @@ AUTO_SCALE = 0
|
|||
KICAD_VERSION_5_99 = 5099000
|
||||
|
||||
# Internal filter names
|
||||
IFILL_MECHANICAL = '_mechanical'
|
||||
IFILT_MECHANICAL = '_mechanical'
|
||||
IFILT_VAR_RENAME = '_var_rename'
|
||||
# KiCad 5 GUI values for the attribute
|
||||
UI_THT = 0 # 1 for KiCad 6
|
||||
UI_SMD = 1 # 2 for KiCad 6
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
# Copyright (c) 2020 Instituto Nacional de Tecnología Industrial
|
||||
# License: GPL-3.0
|
||||
# Project: KiBot (formerly KiPlot)
|
||||
from copy import deepcopy
|
||||
from .gs import GS
|
||||
from .kiplot import load_sch
|
||||
from .misc import Rect, KICAD_VERSION_5_99, W_WRONGPASTE
|
||||
|
|
@ -13,7 +14,7 @@ else:
|
|||
from pcbnew import EDGE_MODULE, wxPoint, LSET
|
||||
from .registrable import RegOutput
|
||||
from .optionable import Optionable, BaseOptions
|
||||
from .fil_base import BaseFilter, apply_fitted_filter, reset_filters
|
||||
from .fil_base import BaseFilter, apply_fitted_filter
|
||||
from .macros import macros, document # noqa: F401
|
||||
from . import log
|
||||
|
||||
|
|
@ -259,9 +260,9 @@ class VariantOptions(BaseOptions):
|
|||
return
|
||||
load_sch()
|
||||
# Get the components list from the schematic
|
||||
comps = GS.sch.get_components()
|
||||
# Note: we work with a copy to avoid changes by filters affecting other outputs
|
||||
comps = deepcopy(GS.sch.get_components())
|
||||
# Apply the filter
|
||||
reset_filters(comps)
|
||||
apply_fitted_filter(comps, self.dnf_filter)
|
||||
# Apply the variant
|
||||
if self.variant:
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ Internal BoM (Bill of Materials) output for KiBot.
|
|||
This is somehow compatible with KiBoM.
|
||||
"""
|
||||
import os
|
||||
from copy import deepcopy
|
||||
from .gs import GS
|
||||
from .optionable import Optionable, BaseOptions
|
||||
from .registrable import RegOutput
|
||||
|
|
@ -17,7 +18,7 @@ from .macros import macros, document, output_class # noqa: F401
|
|||
from .bom.columnlist import ColumnList, BoMError
|
||||
from .bom.bom import do_bom
|
||||
from .var_kibom import KiBoM
|
||||
from .fil_base import BaseFilter, apply_exclude_filter, apply_fitted_filter, apply_fixed_filter, reset_filters
|
||||
from .fil_base import BaseFilter, apply_exclude_filter, apply_fitted_filter, apply_fixed_filter
|
||||
from . import log
|
||||
# To debug the `with document` we can use:
|
||||
# from .mcpyrate.debug import macros, step_expansion
|
||||
|
|
@ -373,8 +374,9 @@ class BoMOptions(BaseOptions):
|
|||
# Get the components list from the schematic
|
||||
comps = GS.sch.get_components()
|
||||
get_board_comps_data(comps)
|
||||
# We work with a copy to avoid changes by filters affecting other outputs
|
||||
comps = deepcopy(comps)
|
||||
# Apply all the filters
|
||||
reset_filters(comps)
|
||||
apply_exclude_filter(comps, self.exclude_filter)
|
||||
apply_fitted_filter(comps, self.dnf_filter)
|
||||
apply_fixed_filter(comps, self.dnc_filter)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
# Project: KiBot (formerly KiPlot)
|
||||
from .registrable import RegVariant
|
||||
from .optionable import Optionable
|
||||
from .fil_base import apply_exclude_filter, apply_fitted_filter, apply_fixed_filter
|
||||
from .fil_base import apply_exclude_filter, apply_fitted_filter, apply_fixed_filter, BaseFilter, apply_pre_transform
|
||||
from .macros import macros, document # noqa: F401
|
||||
|
||||
|
||||
|
|
@ -23,6 +23,9 @@ class BaseVariant(RegVariant):
|
|||
self.file_id = ''
|
||||
""" Text to use as the """
|
||||
# * Filters
|
||||
self.pre_transform = Optionable
|
||||
""" [string|list(string)=''] Name of the filter to transform fields before applying other filters.
|
||||
Use '_var_rename' to transform VARIANT:FIELD fields """
|
||||
self.exclude_filter = Optionable
|
||||
""" [string|list(string)=''] Name of the filter to exclude components from BoM processing.
|
||||
Use '_mechanical' for the default KiBoM behavior """
|
||||
|
|
@ -33,8 +36,13 @@ 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 config(self):
|
||||
super().config()
|
||||
self.pre_transform = BaseFilter.solve_filter(self.pre_transform, 'pre_transform')
|
||||
|
||||
def filter(self, comps):
|
||||
# Apply all the filters
|
||||
apply_pre_transform(comps, self.pre_transform)
|
||||
apply_exclude_filter(comps, self.exclude_filter)
|
||||
apply_fitted_filter(comps, self.dnf_filter)
|
||||
apply_fixed_filter(comps, self.dnc_filter)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ Implements the IBoM variants mechanism.
|
|||
"""
|
||||
from .optionable import Optionable
|
||||
from .gs import GS
|
||||
from .misc import IFILL_MECHANICAL
|
||||
from .misc import IFILT_MECHANICAL
|
||||
from .fil_base import BaseFilter
|
||||
from .macros import macros, document, variant_class # noqa: F401
|
||||
from . import log
|
||||
|
|
@ -48,7 +48,7 @@ class IBoM(BaseVariant): # noqa: F821
|
|||
|
||||
def config(self):
|
||||
super().config()
|
||||
self.exclude_filter = BaseFilter.solve_filter(self.exclude_filter, 'exclude_filter', IFILL_MECHANICAL)
|
||||
self.exclude_filter = BaseFilter.solve_filter(self.exclude_filter, 'exclude_filter', IFILT_MECHANICAL)
|
||||
self.dnf_filter = BaseFilter.solve_filter(self.dnf_filter, 'dnf_filter')
|
||||
self.dnc_filter = BaseFilter.solve_filter(self.dnc_filter, 'dnc_filter')
|
||||
self.variants_blacklist = self._force_list(self.variants_blacklist)
|
||||
|
|
@ -67,6 +67,7 @@ class IBoM(BaseVariant): # noqa: F821
|
|||
return False
|
||||
|
||||
def filter(self, comps):
|
||||
GS.variant = self.variants_whitelist
|
||||
super().filter(comps)
|
||||
logger.debug("Applying IBoM style variants `{}`".format(self.name))
|
||||
# Make black/white lists case insensitive
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ Implements the KiBoM variants mechanism.
|
|||
"""
|
||||
from .optionable import Optionable
|
||||
from .gs import GS
|
||||
from .misc import IFILL_MECHANICAL
|
||||
from .misc import IFILT_MECHANICAL
|
||||
from .fil_base import BaseFilter
|
||||
from .macros import macros, document, variant_class # noqa: F401
|
||||
from . import log
|
||||
|
|
@ -32,10 +32,6 @@ class KiBoM(BaseVariant): # noqa: F821
|
|||
""" Name of the field used to clasify components """
|
||||
self.variant = Optionable
|
||||
""" [string|list(string)=''] Board variant(s) """
|
||||
self.field_changer = False
|
||||
""" Enable the VARIANT.FIELD to FIELD rename mechanism """
|
||||
self.field_variant_separator = '.'
|
||||
""" Separator used for the VARIANT.FIELD rename mechanism """
|
||||
|
||||
def set_def_filters(self, exclude_filter, dnf_filter, dnc_filter):
|
||||
""" Filters delegated to the variant """
|
||||
|
|
@ -61,7 +57,7 @@ class KiBoM(BaseVariant): # noqa: F821
|
|||
# 3) KiBoM default behavior
|
||||
# exclude_filter
|
||||
if not self._def_exclude_filter:
|
||||
self._def_exclude_filter = IFILL_MECHANICAL
|
||||
self._def_exclude_filter = IFILT_MECHANICAL
|
||||
self.exclude_filter = BaseFilter.solve_filter(self.exclude_filter, 'exclude_filter', self._def_exclude_filter)
|
||||
# dnf_filter
|
||||
if not self._def_dnf_filter:
|
||||
|
|
@ -97,21 +93,8 @@ class KiBoM(BaseVariant): # noqa: F821
|
|||
# No match
|
||||
return not exclusive
|
||||
|
||||
def _rename_var_fields(self, comp):
|
||||
""" Look for fields containing VARIANT:FIELD used to change fields according to the variant """
|
||||
for variant in self.variant:
|
||||
for name, value in comp.get_user_fields():
|
||||
res = name.strip().split(self.field_variant_separator)
|
||||
if len(res) == 2:
|
||||
f_variant = res[0].lower()
|
||||
f_field = res[1].lower()
|
||||
if f_variant == variant:
|
||||
if GS.debug_level > 2:
|
||||
logger.debug('ref: {} value: {} -> {}'.format(comp.ref, comp.get_field_value(f_field), value))
|
||||
comp.set_field(f_field, value)
|
||||
|
||||
|
||||
def filter(self, comps):
|
||||
GS.variant = self.variant
|
||||
super().filter(comps)
|
||||
logger.debug("Applying KiBoM style variants `{}`".format(self.name))
|
||||
for c in comps:
|
||||
|
|
@ -121,8 +104,6 @@ class KiBoM(BaseVariant): # noqa: F821
|
|||
value = c.value.lower()
|
||||
config = c.get_field_value(self.config_field).lower()
|
||||
c.fitted = self._variant_comp_is_fitted(value, config)
|
||||
if c.fitted and self.field_changer:
|
||||
self._rename_var_fields(c)
|
||||
elif not c.fitted and GS.debug_level > 2:
|
||||
if not c.fitted and GS.debug_level > 2:
|
||||
logger.debug('ref: {} value: {} config: {} variant: {} -> False'.
|
||||
format(c.ref, value, config, self.variant))
|
||||
|
|
|
|||
|
|
@ -1226,6 +1226,18 @@ def test_int_bom_variant_t2b():
|
|||
ctx.clean_up()
|
||||
|
||||
|
||||
def test_int_bom_variant_t2c():
|
||||
prj = 'kibom-variant_2'
|
||||
ctx = context.TestContextSCH('test_int_bom_variant_t2c', prj, 'int_bom_var_t2c_csv', BOM_DIR)
|
||||
ctx.run()
|
||||
rows, header, info = ctx.load_csv(prj+'-bom_(test).csv')
|
||||
ref_column = header.index(REF_COLUMN_NAME)
|
||||
val_column = header.index(VALUE_COLUMN_NAME)
|
||||
check_kibom_test_netlist(rows, ref_column, 2, ['R2'], ['R1', 'C1', 'C2'])
|
||||
check_value(rows, ref_column, 'R1', val_column, '3k3')
|
||||
ctx.clean_up()
|
||||
|
||||
|
||||
def test_int_bom_variant_t2s():
|
||||
prj = 'kibom-variant_2'
|
||||
ctx = context.TestContextSCH('test_int_bom_variant_t2s', prj, 'int_bom_var_t2s_csv', BOM_DIR)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,11 @@
|
|||
kibot:
|
||||
version: 1
|
||||
|
||||
filters:
|
||||
- name: 'Variant rename'
|
||||
type: var_rename
|
||||
separator: ':'
|
||||
|
||||
variants:
|
||||
- name: 'production'
|
||||
comment: 'Production variant'
|
||||
|
|
@ -14,8 +19,7 @@ variants:
|
|||
type: kibom
|
||||
file_id: '_(test)'
|
||||
variant: test
|
||||
field_changer: true
|
||||
field_variant_separator: ':'
|
||||
pre_transform: 'Variant rename'
|
||||
|
||||
outputs:
|
||||
- name: 'bom_internal'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
# Example KiBot config file
|
||||
kibot:
|
||||
version: 1
|
||||
|
||||
variants:
|
||||
- name: 'production'
|
||||
comment: 'Production variant'
|
||||
type: kibom
|
||||
file_id: '_(production)'
|
||||
variant: production
|
||||
|
||||
- name: 'test'
|
||||
comment: 'Test variant'
|
||||
type: kibom
|
||||
file_id: '_(test)'
|
||||
variant: test
|
||||
pre_transform: '_var_rename'
|
||||
|
||||
outputs:
|
||||
- name: 'bom_internal'
|
||||
comment: "Bill of Materials in CSV format"
|
||||
type: bom
|
||||
dir: BoM
|
||||
|
||||
- name: 'bom_internal_production'
|
||||
comment: "Bill of Materials in CSV format for production"
|
||||
type: bom
|
||||
dir: BoM
|
||||
options:
|
||||
variant: production
|
||||
|
||||
- name: 'bom_internal_test'
|
||||
comment: "Bill of Materials in CSV format for test"
|
||||
type: bom
|
||||
dir: BoM
|
||||
options:
|
||||
variant: test
|
||||
Loading…
Reference in New Issue