Moved internal filters to the base class.
So they can be used not only for internal BoM purposes.
This commit is contained in:
parent
d5fe46ab8e
commit
7882cb0f4f
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue