254 lines
7.2 KiB
Python
254 lines
7.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright (c) 2020-2023 Salvador E. Tropea
|
|
# Copyright (c) 2020-2023 Instituto Nacional de Tecnología Industrial
|
|
# License: GPL-3.0
|
|
# Project: KiBot (formerly KiPlot)
|
|
from collections import OrderedDict
|
|
from copy import copy
|
|
from .gs import GS
|
|
from .optionable import Optionable
|
|
from .error import KiPlotConfigurationError
|
|
from . import log
|
|
|
|
logger = log.get_logger()
|
|
|
|
|
|
def fname(file):
|
|
if file:
|
|
return ", while importing from `{}`".format(file)
|
|
return ""
|
|
|
|
|
|
class Registrable(object):
|
|
""" This class adds the mechanism to register plug-ins """
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
@classmethod
|
|
def register(cl, name, aclass):
|
|
cl._registered[name] = aclass
|
|
|
|
@classmethod
|
|
def is_registered(cl, name):
|
|
return name in cl._registered
|
|
|
|
@classmethod
|
|
def get_class_for(cl, name):
|
|
return cl._registered[name]
|
|
|
|
@classmethod
|
|
def get_registered(cl):
|
|
return cl._registered
|
|
|
|
def __str__(self):
|
|
return "'{}' ({}) [{}]".format(self.comment, self.name, self.type)
|
|
|
|
|
|
class RegOutput(Optionable, Registrable):
|
|
""" An optionable that is also registrable.
|
|
Used by BaseOutput.
|
|
Here because it doesn't need macros. """
|
|
_registered = {}
|
|
# Defined filters
|
|
_def_filters = {}
|
|
# Defined variants
|
|
_def_variants = {}
|
|
# Defined groups
|
|
_def_groups = {}
|
|
# List of defined outputs
|
|
_def_outputs = OrderedDict()
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
@staticmethod
|
|
def reset():
|
|
# Defined filters
|
|
RegOutput._def_filters = {}
|
|
# Defined variants
|
|
RegOutput._def_variants = {}
|
|
# Defined groups
|
|
RegOutput._def_groups = {}
|
|
# List of defined outputs
|
|
RegOutput._def_outputs = OrderedDict()
|
|
|
|
@staticmethod
|
|
def add_variants(variants):
|
|
for k, v in variants.items():
|
|
# Do we have sub-PCBs
|
|
if v.sub_pcbs:
|
|
# Add a variant for each sub-PCB
|
|
for sp in v.sub_pcbs:
|
|
name = k+'['+sp.name+']'
|
|
vn = copy(v)
|
|
vn._sub_pcb = sp
|
|
if sp.file_id:
|
|
vn.file_id = sp.file_id
|
|
else:
|
|
vn.file_id += '_'+sp.name
|
|
RegOutput._def_variants[name] = vn
|
|
else:
|
|
RegOutput._def_variants[k] = v
|
|
|
|
@staticmethod
|
|
def is_variant(name):
|
|
return name in RegOutput._def_variants
|
|
|
|
@staticmethod
|
|
def get_variant(name):
|
|
return RegOutput._def_variants[name]
|
|
|
|
@staticmethod
|
|
def get_variants():
|
|
return RegOutput._def_variants
|
|
|
|
@staticmethod
|
|
def add_filters(filters):
|
|
RegOutput._def_filters.update(filters)
|
|
|
|
@staticmethod
|
|
def is_filter(name):
|
|
return name in RegOutput._def_filters
|
|
|
|
@staticmethod
|
|
def get_filter(name):
|
|
return RegOutput._def_filters[name]
|
|
|
|
@staticmethod
|
|
def add_filter(obj):
|
|
RegOutput._def_filters[obj.name] = obj
|
|
|
|
@staticmethod
|
|
def add_output(obj, file=None):
|
|
if obj.name in RegOutput._def_outputs:
|
|
raise KiPlotConfigurationError("Output name `{}` already defined".format(obj.name)+fname(file))
|
|
if obj.name in RegOutput._def_groups:
|
|
raise KiPlotConfigurationError("Output name `{}` already defined as group".format(obj.name)+fname(file))
|
|
RegOutput._def_outputs[obj.name] = obj
|
|
|
|
@staticmethod
|
|
def add_outputs(objs, file=None):
|
|
for o in objs:
|
|
RegOutput.add_output(o, file)
|
|
|
|
@staticmethod
|
|
def add_group(name, lst, file=None):
|
|
if name in RegOutput._def_groups:
|
|
raise KiPlotConfigurationError("Group name `{}` already defined".format(name)+fname(file))
|
|
if name in RegOutput._def_outputs:
|
|
raise KiPlotConfigurationError("Group name `{}` already defined as output".format(name)+fname(file))
|
|
RegOutput._def_groups[name] = lst
|
|
|
|
@staticmethod
|
|
def add_groups(objs, file=None):
|
|
logger.debug('Adding groups: '+str(objs))
|
|
for n, lst in objs.items():
|
|
RegOutput.add_group(n, lst, file)
|
|
|
|
@staticmethod
|
|
def add_to_group(out, group):
|
|
items = RegOutput._def_groups.get(group)
|
|
if items is not None:
|
|
if out not in items:
|
|
items.append(out)
|
|
return True
|
|
RegOutput.add_group(group, [out])
|
|
|
|
@staticmethod
|
|
def get_groups():
|
|
return RegOutput._def_groups
|
|
|
|
@staticmethod
|
|
def get_group_names():
|
|
return RegOutput._def_groups.keys()
|
|
|
|
@staticmethod
|
|
def get_outputs():
|
|
return RegOutput._def_outputs.values()
|
|
|
|
@staticmethod
|
|
def get_output(name):
|
|
return RegOutput._def_outputs.get(name, None)
|
|
|
|
@staticmethod
|
|
def is_output_or_group(name):
|
|
return name in RegOutput._def_outputs or name in RegOutput._def_groups
|
|
|
|
@staticmethod
|
|
def check_variant(variant):
|
|
if variant:
|
|
if isinstance(variant, RegVariant):
|
|
return variant
|
|
if not RegOutput.is_variant(variant):
|
|
raise KiPlotConfigurationError("Unknown variant name `{}`".format(variant))
|
|
return RegOutput.get_variant(variant)
|
|
return None
|
|
|
|
@staticmethod
|
|
def solve_groups(targets, where, level=0):
|
|
""" Replaces any group by its members.
|
|
Returns a new list.
|
|
Assumes the outputs and groups are valid. """
|
|
new_targets = []
|
|
# Avoid infinite loops
|
|
level += 1
|
|
if level > 20:
|
|
raise KiPlotConfigurationError("More than 20 levels of nested groups, possible loop")
|
|
for t in targets:
|
|
if t in RegOutput._def_outputs:
|
|
new_targets.append(t)
|
|
else:
|
|
new_grp = RegOutput._def_groups.get(t, None)
|
|
if new_grp is None:
|
|
raise KiPlotConfigurationError('Unknown output/group `{}` (in `{}`)'.format(t, where))
|
|
# Recursive expand
|
|
new_targets.extend(RegOutput.solve_groups(new_grp, t, level))
|
|
return new_targets
|
|
|
|
|
|
class RegVariant(Optionable, Registrable):
|
|
""" An optionable that is also registrable.
|
|
Used by BaseVariant.
|
|
Here because it doesn't need macros. """
|
|
_registered = {}
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
|
|
class RegFilter(Optionable, Registrable):
|
|
""" An optionable that is also registrable.
|
|
Used by BaseFilter.
|
|
Here because it doesn't need macros. """
|
|
_registered = {}
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
|
|
class RegDependency(Registrable):
|
|
""" Used to register output tools dependencies """
|
|
_registered = {}
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
@classmethod
|
|
def register(cl, aclass):
|
|
name = aclass.name
|
|
if name in cl._registered:
|
|
# Already registered, add the roles
|
|
old_reg = cl._registered[name]
|
|
old_reg.roles.extend(aclass.roles)
|
|
else:
|
|
cl._registered[name] = aclass
|
|
|
|
|
|
def solve_variant(variant):
|
|
if isinstance(variant, str):
|
|
return RegOutput.check_variant(variant)
|
|
return variant
|
|
|
|
|
|
GS.solve_variant = solve_variant
|