From 7882cb0f4f03021541112d3d92f64a09fba9a9d3 Mon Sep 17 00:00:00 2001 From: "Salvador E. Tropea" Date: Mon, 31 Aug 2020 20:48:56 -0300 Subject: [PATCH] Moved internal filters to the base class. So they can be used not only for internal BoM purposes. --- kibot/fil_base.py | 107 +++++++++++++++++++++++++++++++++++----------- kibot/misc.py | 3 ++ kibot/out_bom.py | 51 +++------------------- 3 files changed, 90 insertions(+), 71 deletions(-) diff --git a/kibot/fil_base.py b/kibot/fil_base.py index 39ccdc6c..4a2b93cf 100644 --- a/kibot/fil_base.py +++ b/kibot/fil_base.py @@ -4,8 +4,23 @@ # License: GPL-3.0 # Project: KiBot (formerly KiPlot) from .registrable import RegFilter, Registrable, RegOutput +from .misc import IFILL_MECHANICAL from .error import KiPlotConfigurationError +from .bom.columnlist import ColumnList 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): @@ -54,6 +69,7 @@ class BaseFilter(RegFilter): def __init__(self): super().__init__() self._unkown_is_error = True + self._internal = False with document: self.name = '' """ Used to identify this particular filter definition """ @@ -62,8 +78,56 @@ class BaseFilter(RegFilter): self.comment = '' """ 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 - 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: - A class, meaning we have to use a default. - 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 isinstance(names, type): # Nothing specified, use the default - names = [def_key] + if default is None: + return None + names = [default] elif isinstance(names, str): # User provided, but only one, make a list names = [names] # Here we should have a list of strings filters = [] for name in names: - if name and name[0] == '!': + if not name: + continue + if name[0] == '!': invert = True name = name[1:] else: invert = False - filter = None - if name == def_key: - # 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)) + # Is already defined? + if RegOutput.is_filter(name): filter = RegOutput.get_filter(name) - if filter: - if invert: - filters.append(NotFilter(filter)) - else: - filters.append(filter) + else: # Nope, can be created? + filter = BaseFilter._create_internal_filter(name) + if filter is None: + raise KiPlotConfigurationError("Unknown filter `{}` used for `{}`".format(name, target_name)) + if invert: + filters.append(NotFilter(filter)) + else: + filters.append(filter) # Finished collecting filters if not filters: return DummyFilter() diff --git a/kibot/misc.py b/kibot/misc.py index 8947524e..571770a2 100644 --- a/kibot/misc.py +++ b/kibot/misc.py @@ -46,6 +46,9 @@ URL_PCBDRAW = 'https://github.com/INTI-CMNB/pcbdraw' EXAMPLE_CFG = 'example.kibot.yaml' AUTO_SCALE = 0 +# Internal filter names +IFILL_MECHANICAL = '_mechanical' + # Supported values for "do not fit" DNF = { "dnf": 1, diff --git a/kibot/out_bom.py b/kibot/out_bom.py index 5b080bde..43a05483 100644 --- a/kibot/out_bom.py +++ b/kibot/out_bom.py @@ -12,6 +12,7 @@ from .gs import GS from .optionable import Optionable, BaseOptions from .registrable import RegOutput from .error import KiPlotConfigurationError +from .misc import IFILL_MECHANICAL from .macros import macros, document, output_class # noqa: F401 from .bom.columnlist import ColumnList, BoMError from .bom.bom import do_bom @@ -174,17 +175,6 @@ class GroupFields(Optionable): 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): with document: self.number = 1 @@ -282,31 +272,7 @@ class BoMOptions(BaseOptions): self.variant.config_field = self.fit_field self.variant.variant = [] self.variant.name = 'default' - - @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 + self.variant.config() # Fill or adjust any detail def config(self): super().config() @@ -335,15 +301,10 @@ class BoMOptions(BaseOptions): # component_aliases if isinstance(self.component_aliases, type): self.component_aliases = DEFAULT_ALIASES - # exclude_filter - self.exclude_filter = BaseFilter.solve_filter(self.exclude_filter, '_mechanical', None, - BoMOptions._create_mechanical, 'exclude_filter') - # dnf_filter - 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') + # Filters + self.exclude_filter = BaseFilter.solve_filter(self.exclude_filter, 'exclude_filter', IFILL_MECHANICAL) + self.dnf_filter = BaseFilter.solve_filter(self.dnf_filter, 'dnf_filter', '_kibom_dnf_'+self.fit_field) + self.dnc_filter = BaseFilter.solve_filter(self.dnc_filter, 'dnc_filter', '_kibom_dnc_'+self.fit_field) # Variants, make it an object self._normalize_variant() # Field names are handled in lowercase