Moved internal filters to the base class.

So they can be used not only for internal BoM purposes.
This commit is contained in:
Salvador E. Tropea 2020-08-31 20:48:56 -03:00
parent d5fe46ab8e
commit 7882cb0f4f
3 changed files with 90 additions and 71 deletions

View File

@ -4,8 +4,23 @@
# License: GPL-3.0 # License: GPL-3.0
# Project: KiBot (formerly KiPlot) # Project: KiBot (formerly KiPlot)
from .registrable import RegFilter, Registrable, RegOutput from .registrable import RegFilter, Registrable, RegOutput
from .misc import IFILL_MECHANICAL
from .error import KiPlotConfigurationError from .error import KiPlotConfigurationError
from .bom.columnlist import ColumnList
from .macros import macros, document # noqa: F401 from .macros import macros, document # noqa: F401
from . import log
logger = log.get_logger(__name__)
DEFAULT_EXCLUDE = [{'column': ColumnList.COL_REFERENCE, 'regex': '^TP[0-9]*'},
{'column': ColumnList.COL_REFERENCE, 'regex': '^FID'},
{'column': ColumnList.COL_PART, 'regex': 'mount.*hole'},
{'column': ColumnList.COL_PART, 'regex': 'solder.*bridge'},
{'column': ColumnList.COL_PART, 'regex': 'solder.*jump'},
{'column': ColumnList.COL_PART, 'regex': 'test.*point'},
{'column': ColumnList.COL_FP, 'regex': 'test.*point'},
{'column': ColumnList.COL_FP, 'regex': 'mount.*hole'},
{'column': ColumnList.COL_FP, 'regex': 'fiducial'},
]
class DummyFilter(Registrable): class DummyFilter(Registrable):
@ -54,6 +69,7 @@ class BaseFilter(RegFilter):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self._unkown_is_error = True self._unkown_is_error = True
self._internal = False
with document: with document:
self.name = '' self.name = ''
""" Used to identify this particular filter definition """ """ Used to identify this particular filter definition """
@ -62,8 +78,56 @@ class BaseFilter(RegFilter):
self.comment = '' self.comment = ''
""" A comment for documentation purposes """ """ A comment for documentation purposes """
def config(self):
super().config()
if self.name[0] == '_' and not self._internal:
raise KiPlotConfigurationError('Filter names starting with `_` are reserved ({})'.format(self.name))
@staticmethod @staticmethod
def solve_filter(names, def_key, def_real, creator, target_name): def _create_mechanical(name):
o_tree = {'name': name}
o_tree['type'] = 'generic'
o_tree['comment'] = 'Internal default mechanical filter'
o_tree['exclude_any'] = DEFAULT_EXCLUDE
logger.debug('Creating internal filter: '+str(o_tree))
return o_tree
@staticmethod
def _create_kibom_dnx(name):
type = name[7:10]
if len(name) > 11:
subtype = name[11:]
else:
subtype = 'config'
o_tree = {'name': name}
o_tree['type'] = 'generic'
o_tree['comment'] = 'Internal KiBoM '+type.upper()+' filter ('+subtype+')'
o_tree['config_field'] = subtype
o_tree['exclude_value'] = True
o_tree['exclude_config'] = True
o_tree['keys'] = type+'_list'
if type[-1] == 'c':
o_tree['invert'] = True
logger.debug('Creating internal filter: '+str(o_tree))
return o_tree
@staticmethod
def _create_internal_filter(name):
if name == IFILL_MECHANICAL:
tree = BaseFilter._create_mechanical(name)
elif name.startswith('_kibom_dn') and len(name) >= 10:
tree = BaseFilter._create_kibom_dnx(name)
else:
return None
filter = RegFilter.get_class_for(tree['type'])()
filter._internal = True
filter.set_tree(tree)
filter.config()
RegOutput.add_filter(filter)
return filter
@staticmethod
def solve_filter(names, target_name, default=None):
""" Name can be: """ Name can be:
- A class, meaning we have to use a default. - A class, meaning we have to use a default.
- A string, the name of a filter. - A string, the name of a filter.
@ -72,42 +136,33 @@ class BaseFilter(RegFilter):
If def_real is not None we pass this name to creator. """ If def_real is not None we pass this name to creator. """
if isinstance(names, type): if isinstance(names, type):
# Nothing specified, use the default # Nothing specified, use the default
names = [def_key] if default is None:
return None
names = [default]
elif isinstance(names, str): elif isinstance(names, str):
# User provided, but only one, make a list # User provided, but only one, make a list
names = [names] names = [names]
# Here we should have a list of strings # Here we should have a list of strings
filters = [] filters = []
for name in names: for name in names:
if name and name[0] == '!': if not name:
continue
if name[0] == '!':
invert = True invert = True
name = name[1:] name = name[1:]
else: else:
invert = False invert = False
filter = None # Is already defined?
if name == def_key: if RegOutput.is_filter(name):
# Matched the default name, translate it to the real name
if def_real:
name = def_real
# Is already defined?
if RegOutput.is_filter(name):
filter = RegOutput.get_filter(name)
else: # Nope, create it
tree = creator(name)
filter = RegFilter.get_class_for(tree['type'])()
filter.set_tree(tree)
filter.config()
RegOutput.add_filter(filter)
elif name:
# A filter that is supposed to exist
if not RegOutput.is_filter(name):
raise KiPlotConfigurationError("Unknown filter `{}` used for `{}`".format(name, target_name))
filter = RegOutput.get_filter(name) filter = RegOutput.get_filter(name)
if filter: else: # Nope, can be created?
if invert: filter = BaseFilter._create_internal_filter(name)
filters.append(NotFilter(filter)) if filter is None:
else: raise KiPlotConfigurationError("Unknown filter `{}` used for `{}`".format(name, target_name))
filters.append(filter) if invert:
filters.append(NotFilter(filter))
else:
filters.append(filter)
# Finished collecting filters # Finished collecting filters
if not filters: if not filters:
return DummyFilter() return DummyFilter()

View File

@ -46,6 +46,9 @@ URL_PCBDRAW = 'https://github.com/INTI-CMNB/pcbdraw'
EXAMPLE_CFG = 'example.kibot.yaml' EXAMPLE_CFG = 'example.kibot.yaml'
AUTO_SCALE = 0 AUTO_SCALE = 0
# Internal filter names
IFILL_MECHANICAL = '_mechanical'
# Supported values for "do not fit" # Supported values for "do not fit"
DNF = { DNF = {
"dnf": 1, "dnf": 1,

View File

@ -12,6 +12,7 @@ from .gs import GS
from .optionable import Optionable, BaseOptions from .optionable import Optionable, BaseOptions
from .registrable import RegOutput from .registrable import RegOutput
from .error import KiPlotConfigurationError from .error import KiPlotConfigurationError
from .misc import IFILL_MECHANICAL
from .macros import macros, document, output_class # noqa: F401 from .macros import macros, document, output_class # noqa: F401
from .bom.columnlist import ColumnList, BoMError from .bom.columnlist import ColumnList, BoMError
from .bom.bom import do_bom from .bom.bom import do_bom
@ -174,17 +175,6 @@ class GroupFields(Optionable):
class BoMOptions(BaseOptions): class BoMOptions(BaseOptions):
DEFAULT_EXCLUDE = [{'column': ColumnList.COL_REFERENCE, 'regex': '^TP[0-9]*'},
{'column': ColumnList.COL_REFERENCE, 'regex': '^FID'},
{'column': ColumnList.COL_PART, 'regex': 'mount.*hole'},
{'column': ColumnList.COL_PART, 'regex': 'solder.*bridge'},
{'column': ColumnList.COL_PART, 'regex': 'solder.*jump'},
{'column': ColumnList.COL_PART, 'regex': 'test.*point'},
{'column': ColumnList.COL_FP, 'regex': 'test.*point'},
{'column': ColumnList.COL_FP, 'regex': 'mount.*hole'},
{'column': ColumnList.COL_FP, 'regex': 'fiducial'},
]
def __init__(self): def __init__(self):
with document: with document:
self.number = 1 self.number = 1
@ -282,31 +272,7 @@ class BoMOptions(BaseOptions):
self.variant.config_field = self.fit_field self.variant.config_field = self.fit_field
self.variant.variant = [] self.variant.variant = []
self.variant.name = 'default' self.variant.name = 'default'
self.variant.config() # Fill or adjust any detail
@staticmethod
def _create_mechanical(name):
o_tree = {'name': name}
o_tree['type'] = 'generic'
o_tree['comment'] = 'Internal default mechanical filter'
o_tree['exclude_any'] = BoMOptions.DEFAULT_EXCLUDE
logger.debug('Creating internal filter: '+str(o_tree))
return o_tree
@staticmethod
def _create_kibom_dnx(name):
type = name[7:10]
subtype = name[11:]
o_tree = {'name': name}
o_tree['type'] = 'generic'
o_tree['comment'] = 'Internal KiBoM '+type.upper()+' filter ('+subtype+')'
o_tree['config_field'] = subtype
o_tree['exclude_value'] = True
o_tree['exclude_config'] = True
o_tree['keys'] = type+'_list'
if type[-1] == 'c':
o_tree['invert'] = True
logger.debug('Creating internal filter: '+str(o_tree))
return o_tree
def config(self): def config(self):
super().config() super().config()
@ -335,15 +301,10 @@ class BoMOptions(BaseOptions):
# component_aliases # component_aliases
if isinstance(self.component_aliases, type): if isinstance(self.component_aliases, type):
self.component_aliases = DEFAULT_ALIASES self.component_aliases = DEFAULT_ALIASES
# exclude_filter # Filters
self.exclude_filter = BaseFilter.solve_filter(self.exclude_filter, '_mechanical', None, self.exclude_filter = BaseFilter.solve_filter(self.exclude_filter, 'exclude_filter', IFILL_MECHANICAL)
BoMOptions._create_mechanical, 'exclude_filter') self.dnf_filter = BaseFilter.solve_filter(self.dnf_filter, 'dnf_filter', '_kibom_dnf_'+self.fit_field)
# dnf_filter self.dnc_filter = BaseFilter.solve_filter(self.dnc_filter, 'dnc_filter', '_kibom_dnc_'+self.fit_field)
self.dnf_filter = BaseFilter.solve_filter(self.dnf_filter, '_kibom_dnf', '_kibom_dnf_'+self.fit_field,
BoMOptions._create_kibom_dnx, 'dnf_filter')
# dnc_filter
self.dnc_filter = BaseFilter.solve_filter(self.dnc_filter, '_kibom_dnc', '_kibom_dnc_'+self.fit_field,
BoMOptions._create_kibom_dnx, 'dnc_filter')
# Variants, make it an object # Variants, make it an object
self._normalize_variant() self._normalize_variant()
# Field names are handled in lowercase # Field names are handled in lowercase