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
# 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()

View File

@ -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,

View File

@ -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