parent
eab8550c11
commit
1b48e614a7
|
|
@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
## [Unreleased]
|
||||
### Added
|
||||
- `erc_warnings` pre-flight option to consider ERC warnings as errors.
|
||||
- Pattern expansion in the `dir` option for outputs (#58)
|
||||
|
||||
### Changed
|
||||
- Errors and warnings from KiAuto now are printed as errors and warnings.
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ class CfgYamlReader(object):
|
|||
o_var = reg_class.get_class_for(otype)()
|
||||
o_var.set_tree(o_tree)
|
||||
try:
|
||||
o_var.config()
|
||||
o_var.config(None)
|
||||
except KiPlotConfigurationError as e:
|
||||
config_error("In section `"+name_type+"`: "+str(e))
|
||||
return o_var
|
||||
|
|
@ -167,7 +167,7 @@ class CfgYamlReader(object):
|
|||
glb = GS.global_opts_class()
|
||||
glb.set_tree(gb)
|
||||
try:
|
||||
glb.config()
|
||||
glb.config(None)
|
||||
except KiPlotConfigurationError as e:
|
||||
config_error("In `global` section: "+str(e))
|
||||
|
||||
|
|
|
|||
|
|
@ -43,8 +43,8 @@ class DrillMarks(AnyLayerOptions):
|
|||
raise KiPlotConfigurationError("Unknown drill mark type: {}".format(val))
|
||||
self._drill_marks = val
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
self._drill_marks = DrillMarks._drill_marks_map[self._drill_marks]
|
||||
|
||||
def _configure_plot_ctrl(self, po, output_dir):
|
||||
|
|
|
|||
|
|
@ -118,8 +118,8 @@ class BaseFilter(RegFilter):
|
|||
self.comment = ''
|
||||
""" A comment for documentation purposes """
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
if self.name[0] == '_' and not self._internal:
|
||||
raise KiPlotConfigurationError('Filter names starting with `_` are reserved ({})'.format(self.name))
|
||||
|
||||
|
|
@ -184,7 +184,7 @@ class BaseFilter(RegFilter):
|
|||
filter = RegFilter.get_class_for(tree['type'])()
|
||||
filter._internal = True
|
||||
filter.set_tree(tree)
|
||||
filter.config()
|
||||
filter.config(None)
|
||||
RegOutput.add_filter(filter)
|
||||
return filter
|
||||
|
||||
|
|
|
|||
|
|
@ -83,8 +83,8 @@ class Generic(BaseFilter): # noqa: F821
|
|||
col = col[:-1]
|
||||
return col
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
# include_only
|
||||
if isinstance(self.include_only, type):
|
||||
self.include_only = None
|
||||
|
|
|
|||
|
|
@ -64,8 +64,8 @@ class Rot_Footprint(BaseFilter): # noqa: F821
|
|||
""" [list(list(string))] A list of pairs regular expression/rotation.
|
||||
Components matching the regular expression will be rotated the indicated angle """
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
self._rot = []
|
||||
if isinstance(self.rotations, list):
|
||||
for r in self.rotations:
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ class Var_Rename(BaseFilter): # noqa: F821
|
|||
self.variant_to_value = False
|
||||
""" Rename fields matching the variant to the value of the component """
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
if not self.separator:
|
||||
self.separator = ':'
|
||||
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ class Globals(FiltersOptions):
|
|||
return new_val
|
||||
return current
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
GS.global_output = self.set_global(GS.global_output, self.output, 'output')
|
||||
GS.global_variant = self.set_global(GS.global_variant, self.variant, 'variant')
|
||||
GS.global_kiauto_wait_start = self.set_global(GS.global_kiauto_wait_start, self.kiauto_wait_start, 'kiauto_wait_start')
|
||||
|
|
|
|||
|
|
@ -326,7 +326,7 @@ def config_output(out, dry=False):
|
|||
if out.is_sch():
|
||||
load_sch()
|
||||
try:
|
||||
out.config()
|
||||
out.config(None)
|
||||
except KiPlotConfigurationError as e:
|
||||
config_error("In section '"+out.name+"' ("+out.type+"): "+str(e))
|
||||
|
||||
|
|
@ -334,7 +334,8 @@ def config_output(out, dry=False):
|
|||
def run_output(out):
|
||||
GS.current_output = out.name
|
||||
try:
|
||||
out.run(get_output_dir(out.dir))
|
||||
out_dir = out.expand_dirname(out.dir)
|
||||
out.run(get_output_dir(out_dir))
|
||||
out._done = True
|
||||
except PlotError as e:
|
||||
logger.error("In output `"+str(out)+"`: "+str(e))
|
||||
|
|
|
|||
|
|
@ -105,8 +105,8 @@ class Layer(Optionable):
|
|||
self._unkown_is_error = True
|
||||
self._protel_extension = None
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
if not self.layer:
|
||||
raise KiPlotConfigurationError("Missing or empty `layer` attribute for layer entry ({})".format(self._tree))
|
||||
if not self.description:
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@ class Optionable(object):
|
|||
self._error_context = ''
|
||||
self._tree = {}
|
||||
self._configured = False
|
||||
# File/directory pattern expansion
|
||||
self._expand_id = ''
|
||||
self._expand_ext = ''
|
||||
super().__init__()
|
||||
if GS.global_output is not None and getattr(self, 'output', None):
|
||||
setattr(self, 'output', GS.global_output)
|
||||
|
|
@ -146,7 +149,7 @@ class Optionable(object):
|
|||
v = cur_val()
|
||||
# Delegate the validation to the object
|
||||
v.set_tree(new_val)
|
||||
v.config()
|
||||
v.config(self)
|
||||
elif isinstance(v, list):
|
||||
new_val = []
|
||||
for element in v:
|
||||
|
|
@ -157,7 +160,7 @@ class Optionable(object):
|
|||
if isinstance(element, dict):
|
||||
nv = cur_val()
|
||||
nv.set_tree(element)
|
||||
nv.config()
|
||||
nv.config(self)
|
||||
new_val.append(nv)
|
||||
else:
|
||||
new_val.append(element)
|
||||
|
|
@ -168,7 +171,8 @@ class Optionable(object):
|
|||
def set_tree(self, tree):
|
||||
self._tree = tree
|
||||
|
||||
def config(self):
|
||||
def config(self, parent):
|
||||
self._parent = parent
|
||||
if self._tree and not self._configured:
|
||||
self._perform_config_mapping()
|
||||
self._configured = True
|
||||
|
|
@ -189,7 +193,7 @@ class Optionable(object):
|
|||
return self.variant.file_id
|
||||
return ''
|
||||
|
||||
def expand_filename(self, out_dir, name, id='', ext=''):
|
||||
def expand_filename_pcb(self, name):
|
||||
""" Expands %* values in filenames.
|
||||
Uses data from the PCB. """
|
||||
if GS.board:
|
||||
|
|
@ -200,18 +204,18 @@ class Optionable(object):
|
|||
name = name.replace('%D', GS.today)
|
||||
name = name.replace('%F', GS.pcb_no_ext)
|
||||
name = name.replace('%f', GS.pcb_basename)
|
||||
name = name.replace('%i', id)
|
||||
name = name.replace('%i', self._expand_id)
|
||||
name = name.replace('%p', GS.pcb_title)
|
||||
name = name.replace('%r', GS.pcb_rev)
|
||||
name = name.replace('%T', GS.time)
|
||||
name = name.replace('%v', self._find_variant() if self else '')
|
||||
name = name.replace('%x', ext)
|
||||
name = name.replace('%x', self._expand_ext)
|
||||
# sanitize the name to avoid characters illegal in file systems
|
||||
name = name.replace('\\', '/')
|
||||
name = re.sub(r'[?%*:|"<>]', '_', name)
|
||||
return os.path.abspath(os.path.join(out_dir, name))
|
||||
return name
|
||||
|
||||
def expand_filename_sch(self, out_dir, name, id='', ext=''):
|
||||
def expand_filename_sch(self, name):
|
||||
""" Expands %* values in filenames.
|
||||
Uses data from the SCH. """
|
||||
if GS.sch_file:
|
||||
|
|
@ -222,16 +226,16 @@ class Optionable(object):
|
|||
name = name.replace('%D', GS.today)
|
||||
name = name.replace('%F', GS.sch_no_ext)
|
||||
name = name.replace('%f', GS.sch_basename)
|
||||
name = name.replace('%i', id)
|
||||
name = name.replace('%i', self._expand_id)
|
||||
name = name.replace('%p', GS.sch_title)
|
||||
name = name.replace('%r', GS.sch_rev)
|
||||
name = name.replace('%T', GS.time)
|
||||
name = name.replace('%v', self._find_variant() if self else '')
|
||||
name = name.replace('%x', ext)
|
||||
name = name.replace('%x', self._expand_ext)
|
||||
# sanitize the name to avoid characters illegal in file systems
|
||||
name = name.replace('\\', '/')
|
||||
name = re.sub(r'[?%*:|"<>]', '_', name)
|
||||
return os.path.abspath(os.path.join(out_dir, name))
|
||||
return name
|
||||
|
||||
|
||||
class BaseOptions(Optionable):
|
||||
|
|
@ -243,3 +247,17 @@ class BaseOptions(Optionable):
|
|||
def read_vals_from_po(self, po):
|
||||
""" Set attributes from a PCB_PLOT_PARAMS (plot options) """
|
||||
return
|
||||
|
||||
def expand_filename(self, dir, name, id, ext):
|
||||
cur_id = self._expand_id
|
||||
cur_ext = self._expand_ext
|
||||
self._expand_id = id
|
||||
self._expand_ext = ext
|
||||
if self._parent._sch_related:
|
||||
name = self.expand_filename_sch(name)
|
||||
else:
|
||||
name = self.expand_filename_pcb(name)
|
||||
res = os.path.abspath(os.path.join(dir, name))
|
||||
self._expand_id = cur_id
|
||||
self._expand_ext = cur_ext
|
||||
return res
|
||||
|
|
|
|||
|
|
@ -73,8 +73,8 @@ class AnyDrill(BaseOptions):
|
|||
self._map_ext = {'hpgl': 'plt', 'ps': 'ps', 'gerber': 'gbr', 'dxf': 'dxf', 'svg': 'svg', 'pdf': 'pdf'}
|
||||
self._unified_output = False
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
# Solve the map for both cases
|
||||
if isinstance(self.map, str):
|
||||
self.map_ext = self._map_ext[self.map]
|
||||
|
|
@ -91,6 +91,8 @@ class AnyDrill(BaseOptions):
|
|||
self.report = self.report.filename
|
||||
elif not isinstance(self.report, str):
|
||||
self.report = None
|
||||
self._expand_id = 'drill'
|
||||
self._expand_ext = self._ext
|
||||
|
||||
def solve_id(self, d):
|
||||
if not d:
|
||||
|
|
@ -127,6 +129,8 @@ class AnyDrill(BaseOptions):
|
|||
return filenames
|
||||
|
||||
def run(self, output_dir):
|
||||
if self.output:
|
||||
output_dir = os.path.dirname(output_dir)
|
||||
# dialog_gendrill.cpp:357
|
||||
if self.use_aux_axis_as_origin:
|
||||
offset = get_aux_origin(GS.board)
|
||||
|
|
@ -145,6 +149,7 @@ class AnyDrill(BaseOptions):
|
|||
files = self.get_file_names(output_dir)
|
||||
for k_f, f in files.items():
|
||||
if f:
|
||||
logger.debug("Renaming {} -> {}".format(k_f, f))
|
||||
os.rename(k_f, f)
|
||||
# Generate the report
|
||||
if self.report:
|
||||
|
|
@ -152,7 +157,7 @@ class AnyDrill(BaseOptions):
|
|||
logger.debug("Generating drill report: "+drill_report_file)
|
||||
drill_writer.GenDrillReportFile(drill_report_file)
|
||||
|
||||
def get_targets(self, parent, out_dir):
|
||||
def get_targets(self, out_dir):
|
||||
targets = []
|
||||
files = self.get_file_names(out_dir)
|
||||
for k_f, f in files.items():
|
||||
|
|
|
|||
|
|
@ -72,8 +72,8 @@ class AnyLayerOptions(VariantOptions):
|
|||
""" [list(dict)] A list of customized reports for the manufacturer """
|
||||
super().__init__()
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
if isinstance(self.custom_reports, type):
|
||||
self.custom_reports = []
|
||||
|
||||
|
|
@ -243,8 +243,8 @@ class AnyLayer(BaseOutput):
|
|||
""" [list(dict)|list(string)|string] [all,selected,copper,technical,user]
|
||||
List of PCB layers to plot """
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
# We need layers
|
||||
if isinstance(self.layers, type):
|
||||
raise KiPlotConfigurationError("Missing `layers` list")
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
# Copyright (c) 2020-2021 Instituto Nacional de Tecnología Industrial
|
||||
# License: GPL-3.0
|
||||
# Project: KiBot (formerly KiPlot)
|
||||
import os
|
||||
from .gs import GS
|
||||
from .kiplot import load_sch, get_board_comps_data
|
||||
from .misc import Rect, KICAD_VERSION_5_99, W_WRONGPASTE
|
||||
|
|
@ -53,7 +54,7 @@ class BaseOutput(RegOutput):
|
|||
if not (hasattr(self, "options") and hasattr(self.options, "get_targets")):
|
||||
logger.error("Output {} doesn't implement get_targets(), plese report it".format(self))
|
||||
return []
|
||||
return self.options.get_targets(self, out_dir)
|
||||
return self.options.get_targets(out_dir)
|
||||
|
||||
def get_dependencies(self):
|
||||
""" Returns a list of files needed to create this output """
|
||||
|
|
@ -63,16 +64,28 @@ class BaseOutput(RegOutput):
|
|||
return [GS.sch_file]
|
||||
return [GS.pcb_file]
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
if getattr(self, 'options', None) and isinstance(self.options, type):
|
||||
# No options, get the defaults
|
||||
self.options = self.options()
|
||||
# Configure them using an empty tree
|
||||
self.options.config()
|
||||
self.options.config(self)
|
||||
|
||||
def expand_dirname(self, out_dir):
|
||||
if self._sch_related:
|
||||
return self.options.expand_filename_sch(out_dir)
|
||||
return self.options.expand_filename_pcb(out_dir)
|
||||
|
||||
def expand_filename(self, out_dir, name):
|
||||
if self._sch_related:
|
||||
name = self.options.expand_filename_sch(name)
|
||||
else:
|
||||
name = self.options.expand_filename_pcb(name)
|
||||
return os.path.abspath(os.path.join(out_dir, name))
|
||||
|
||||
def run(self, output_dir):
|
||||
self.options.run(output_dir)
|
||||
self.options.run(self.expand_filename(output_dir, self.options.output))
|
||||
|
||||
|
||||
class BoMRegex(Optionable):
|
||||
|
|
@ -103,8 +116,8 @@ class VariantOptions(BaseOptions):
|
|||
super().__init__()
|
||||
self._comps = None
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
self.variant = RegOutput.check_variant(self.variant)
|
||||
self.dnf_filter = BaseFilter.solve_filter(self.dnf_filter, 'dnf_filter')
|
||||
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ class BoMColumns(Optionable):
|
|||
self._field_example = 'Row'
|
||||
self._name_example = 'Line'
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
if not self.field:
|
||||
raise KiPlotConfigurationError("Missing or empty `field` in columns list ({})".format(str(self._tree)))
|
||||
# Ensure this is None or a list
|
||||
|
|
@ -92,8 +92,8 @@ class BoMLinkable(Optionable):
|
|||
self.title = 'KiBot Bill of Materials'
|
||||
""" BoM title """
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
# digikey_link
|
||||
if isinstance(self.digikey_link, type):
|
||||
self.digikey_link = []
|
||||
|
|
@ -121,8 +121,8 @@ class BoMHTML(BoMLinkable):
|
|||
""" Page style. Internal styles: modern-blue, modern-green, modern-red and classic.
|
||||
Or you can provide a CSS file name. Please use .css as file extension. """
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
# Style
|
||||
if not self.style:
|
||||
self.style = 'modern-blue'
|
||||
|
|
@ -157,8 +157,8 @@ class BoMXLSX(BoMLinkable):
|
|||
self.style = 'modern-blue'
|
||||
""" Head style: modern-blue, modern-green, modern-red and classic. """
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
# Style
|
||||
if not self.style:
|
||||
self.style = 'modern-blue'
|
||||
|
|
@ -200,8 +200,8 @@ class Aggregate(Optionable):
|
|||
self.number = 1
|
||||
""" Number of boards to build (components multiplier). Use negative to substract """
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
if not self.file:
|
||||
raise KiPlotConfigurationError("Missing or empty `file` in aggregate list ({})".format(str(self._tree)))
|
||||
if not self.name:
|
||||
|
|
@ -323,26 +323,28 @@ class BoMOptions(BaseOptions):
|
|||
# Delegate any filter to the variant
|
||||
self.variant.set_def_filters(self.exclude_filter, self.dnf_filter, self.dnc_filter)
|
||||
self.exclude_filter = self.dnf_filter = self.dnc_filter = None
|
||||
self.variant.config() # Fill or adjust any detail
|
||||
self.variant.config(self) # Fill or adjust any detail
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
self.format = self._guess_format()
|
||||
self._expand_id = 'bom'
|
||||
self._expand_ext = self.format.lower()
|
||||
# HTML options
|
||||
if self.format == 'html' and isinstance(self.html, type):
|
||||
# If no options get the defaults
|
||||
self.html = BoMHTML()
|
||||
self.html.config()
|
||||
self.html.config(self)
|
||||
# CSV options
|
||||
if self.format in ['csv', 'tsv', 'txt'] and isinstance(self.csv, type):
|
||||
# If no options get the defaults
|
||||
self.csv = BoMCSV()
|
||||
self.csv.config()
|
||||
self.csv.config(self)
|
||||
# XLSX options
|
||||
if self.format == 'xlsx' and isinstance(self.xlsx, type):
|
||||
# If no options get the defaults
|
||||
self.xlsx = BoMXLSX()
|
||||
self.xlsx.config()
|
||||
self.xlsx.config(self)
|
||||
# group_fields
|
||||
if isinstance(self.group_fields, type):
|
||||
self.group_fields = ColumnList.DEFAULT_GROUPING
|
||||
|
|
@ -434,9 +436,8 @@ class BoMOptions(BaseOptions):
|
|||
comps.extend(new_comps)
|
||||
prj.source = os.path.basename(prj.file)
|
||||
|
||||
def run(self, output_dir):
|
||||
def run(self, output):
|
||||
format = self.format.lower()
|
||||
output = self.expand_filename_sch(output_dir, self.output, 'bom', format)
|
||||
# Add some info needed for the output to the config object.
|
||||
# So all the configuration is contained in one object.
|
||||
self.source = GS.sch_basename
|
||||
|
|
@ -482,8 +483,8 @@ class BoMOptions(BaseOptions):
|
|||
c.ref = c.ref[l_id:]
|
||||
c.ref_id = ''
|
||||
|
||||
def get_targets(self, parent, out_dir):
|
||||
return [self.expand_filename_sch(out_dir, self.output, 'bom', self.format.lower())]
|
||||
def get_targets(self, out_dir):
|
||||
return [self._parent.expand_filename(out_dir, self.output)]
|
||||
|
||||
|
||||
@output_class
|
||||
|
|
|
|||
|
|
@ -62,11 +62,13 @@ class CompressOptions(BaseOptions):
|
|||
""" [list(dict)] Which files will be included """
|
||||
super().__init__()
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
if isinstance(self.files, type):
|
||||
self.files = []
|
||||
logger.warning(W_EMPTYZIP+'No files provided, creating an empty archive')
|
||||
self._expand_id = parent.name
|
||||
self._expand_ext = self.solve_extension()
|
||||
|
||||
def create_zip(self, output, files):
|
||||
extra = {}
|
||||
|
|
@ -113,7 +115,7 @@ class CompressOptions(BaseOptions):
|
|||
ext += '.'+sub_ext
|
||||
return ext
|
||||
|
||||
def get_files(self, output, parent, no_out_run=False):
|
||||
def get_files(self, output, no_out_run=False):
|
||||
output_real = os.path.realpath(output)
|
||||
files = OrderedDict()
|
||||
for f in self.files:
|
||||
|
|
@ -126,7 +128,7 @@ class CompressOptions(BaseOptions):
|
|||
files_list = out.get_targets(get_output_dir(out.dir, dry=True))
|
||||
break
|
||||
if files_list is None:
|
||||
logger.error('Unknown output `{}` selected in {}'.format(f.from_output, parent))
|
||||
logger.error('Unknown output `{}` selected in {}'.format(f.from_output, self._parent))
|
||||
exit(WRONG_ARGUMENTS)
|
||||
if not no_out_run:
|
||||
for file in files_list:
|
||||
|
|
@ -156,20 +158,19 @@ class CompressOptions(BaseOptions):
|
|||
files[fname_real] = dest
|
||||
return files
|
||||
|
||||
def get_targets(self, parent, out_dir):
|
||||
return [self.expand_filename(out_dir, self.output, parent.name, self.solve_extension())]
|
||||
def get_targets(self, out_dir):
|
||||
return [self._parent.expand_filename(out_dir, self.output)]
|
||||
|
||||
def get_dependencies(self, parent):
|
||||
output = self.get_targets(parent, GS.out_dir)[0]
|
||||
files = self.get_files(output, parent, no_out_run=True)
|
||||
def get_dependencies(self):
|
||||
output = self.get_targets(GS.out_dir)[0]
|
||||
files = self.get_files(output, no_out_run=True)
|
||||
return files.keys()
|
||||
|
||||
def run(self, output_dir, parent):
|
||||
def run(self, output):
|
||||
# Output file name
|
||||
output = self.get_targets(parent, output_dir)[0]
|
||||
logger.debug('Collecting files')
|
||||
# Collect the files
|
||||
files = self.get_files(output, parent)
|
||||
files = self.get_files(output)
|
||||
logger.debug('Generating `{}` archive'.format(output))
|
||||
if self.format == 'ZIP':
|
||||
self.create_zip(output, files)
|
||||
|
|
@ -191,7 +192,4 @@ class Compress(BaseOutput): # noqa: F821
|
|||
""" [dict] Options for the `compress` output """
|
||||
|
||||
def get_dependencies(self):
|
||||
return self.options.get_dependencies(self)
|
||||
|
||||
def run(self, output_dir):
|
||||
self.options.run(output_dir, self)
|
||||
return self.options.get_dependencies()
|
||||
|
|
|
|||
|
|
@ -90,15 +90,17 @@ class IBoMOptions(VariantOptions):
|
|||
super().__init__()
|
||||
self.add_to_doc('variant', WARNING_MIX)
|
||||
self.add_to_doc('dnf_filter', WARNING_MIX)
|
||||
self._expand_id = 'ibom'
|
||||
self._expand_ext = 'html'
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
self.netlist_file = self.expand_filename('', self.netlist_file, 'ibom', 'xml')
|
||||
|
||||
def get_targets(self, parent, out_dir):
|
||||
def get_targets(self, out_dir):
|
||||
if self.output:
|
||||
return [self.expand_filename(out_dir, self.output, 'ibom', 'html')]
|
||||
logger.warning(W_EXTNAME+'{} uses a name generated by the external tool.'.format(parent))
|
||||
logger.warning(W_EXTNAME+'{} uses a name generated by the external tool.'.format(self._parent))
|
||||
logger.warning(W_EXTNAME+'Please use a name generated by KiBot or specify the name explicitly.')
|
||||
return []
|
||||
|
||||
|
|
@ -108,20 +110,23 @@ class IBoMOptions(VariantOptions):
|
|||
files.append(self.netlist_file)
|
||||
return files
|
||||
|
||||
def run(self, output_dir):
|
||||
super().run(output_dir)
|
||||
def run(self, name):
|
||||
super().run(name)
|
||||
tool = search_as_plugin(CMD_IBOM, ['InteractiveHtmlBom', 'InteractiveHtmlBom/InteractiveHtmlBom'])
|
||||
check_script(tool, URL_IBOM)
|
||||
logger.debug('Doing Interactive BoM')
|
||||
# Tell ibom we don't want to use the screen
|
||||
os.environ['INTERACTIVE_HTML_BOM_NO_DISPLAY'] = ''
|
||||
cmd = [tool, GS.pcb_file, '--dest-dir', output_dir, '--no-browser', ]
|
||||
# Solve the output name
|
||||
output = None
|
||||
if self.output:
|
||||
output = self.expand_filename(output_dir, self.output, 'ibom', 'html')
|
||||
output = name
|
||||
self.name_format = 'ibom'
|
||||
output_dir = os.path.dirname(name)
|
||||
cur = os.path.join(output_dir, 'ibom.html')
|
||||
else:
|
||||
output_dir = name
|
||||
cmd = [tool, GS.pcb_file, '--dest-dir', output_dir, '--no-browser', ]
|
||||
# Apply variants/filters
|
||||
to_remove = ','.join(self.get_not_fitted_refs())
|
||||
if self.blacklist and to_remove:
|
||||
|
|
|
|||
|
|
@ -55,8 +55,8 @@ class KiBoMColumns(Optionable):
|
|||
self._field_example = 'Row'
|
||||
self._name_example = 'Line'
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
if not self.field:
|
||||
raise KiPlotConfigurationError("Missing or empty `field` in columns list ({})".format(str(self._tree)))
|
||||
if isinstance(self.join, type):
|
||||
|
|
@ -207,8 +207,8 @@ class KiBoMConfig(Optionable):
|
|||
logger.debug('Output from command:\n'+cmd_output.decode())
|
||||
return columns
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
# digikey_link
|
||||
if isinstance(self.digikey_link, type):
|
||||
self.digikey_link = None
|
||||
|
|
@ -341,9 +341,10 @@ class KiBoMOptions(BaseOptions):
|
|||
self.format = 'HTML'
|
||||
""" [HTML,CSV,XML,XLSX] format for the BoM """
|
||||
super().__init__()
|
||||
self._expand_id = 'bom'
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
if isinstance(self.conf, type):
|
||||
self.conf = 'bom.ini'
|
||||
elif isinstance(self.conf, str):
|
||||
|
|
@ -354,25 +355,28 @@ class KiBoMOptions(BaseOptions):
|
|||
conf = os.path.abspath(os.path.join(GS.out_dir, CONFIG_FILENAME))
|
||||
self.conf.save(conf)
|
||||
self.conf = conf
|
||||
self._expand_ext = self.format.lower()
|
||||
|
||||
def get_targets(self, parent, out_dir):
|
||||
def get_targets(self, out_dir):
|
||||
if self.output:
|
||||
return [self.expand_filename_sch(out_dir, self.output, 'bom', self.format.lower())]
|
||||
logger.warning(W_EXTNAME+'{} uses a name generated by the external tool.'.format(parent))
|
||||
return [self.expand_filename(out_dir, self.output, 'bom', self.format.lower())]
|
||||
logger.warning(W_EXTNAME+'{} uses a name generated by the external tool.'.format(self._parent))
|
||||
logger.warning(W_EXTNAME+'Please use a name generated by KiBot or specify the name explicitly.')
|
||||
return []
|
||||
|
||||
def run(self, output_dir):
|
||||
def run(self, name):
|
||||
check_script(CMD_KIBOM, URL_KIBOM, '1.8.0')
|
||||
format = self.format.lower()
|
||||
prj = GS.sch_no_ext
|
||||
config = os.path.join(GS.sch_dir, self.conf)
|
||||
if self.output:
|
||||
force_output = True
|
||||
output = self.expand_filename_sch(output_dir, self.output, 'bom', format)
|
||||
output = name
|
||||
output_dir = os.path.dirname(name)
|
||||
else:
|
||||
force_output = False
|
||||
output = os.path.basename(prj)+'.'+format
|
||||
output_dir = name
|
||||
logger.debug('Doing BoM, format {} prj: {} config: {} output: {}'.format(format, prj, config, output))
|
||||
cmd = [CMD_KIBOM,
|
||||
'-n', str(self.number),
|
||||
|
|
|
|||
|
|
@ -55,8 +55,8 @@ class PcbDrawStyle(Optionable):
|
|||
if not self._color_re.match(color):
|
||||
raise KiPlotConfigurationError('Invalid color for `{}` use `#rrggbb` with hex digits'.format(name))
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
self.validate_color('board')
|
||||
self.validate_color('copper')
|
||||
self.validate_color('board')
|
||||
|
|
@ -78,7 +78,7 @@ class PcbDrawRemap(Optionable):
|
|||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def config(self):
|
||||
def config(self, parent):
|
||||
pass
|
||||
|
||||
|
||||
|
|
@ -139,8 +139,8 @@ class PcbDrawOptions(VariantOptions):
|
|||
""" Name for the generated file """
|
||||
super().__init__()
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
# Libs
|
||||
if isinstance(self.libs, type):
|
||||
self.libs = None
|
||||
|
|
@ -174,6 +174,8 @@ class PcbDrawOptions(VariantOptions):
|
|||
self.style = None
|
||||
elif isinstance(self.style, PcbDrawStyle):
|
||||
self.style = self.style.to_dict()
|
||||
self._expand_id = 'bottom' if self.bottom else 'top'
|
||||
self._expand_ext = self.format
|
||||
|
||||
def _create_remap(self):
|
||||
with NamedTemporaryFile(mode='w', delete=False) as f:
|
||||
|
|
@ -227,14 +229,12 @@ class PcbDrawOptions(VariantOptions):
|
|||
cmd.append(svg)
|
||||
return svg
|
||||
|
||||
def get_targets(self, parent, out_dir):
|
||||
return [self.expand_filename(out_dir, self.output, 'bottom' if self.bottom else 'top', self.format)]
|
||||
def get_targets(self, out_dir):
|
||||
return [self._parent.expand_filename(out_dir, self.output)]
|
||||
|
||||
def run(self, output_dir):
|
||||
super().run(output_dir)
|
||||
def run(self, name):
|
||||
super().run(name)
|
||||
check_script(PCBDRAW, URL_PCBDRAW, '0.6.0')
|
||||
# Output file name
|
||||
output = self.expand_filename(output_dir, self.output, 'bottom' if self.bottom else 'top', self.format)
|
||||
# Base command with overwrite
|
||||
cmd = [PCBDRAW]
|
||||
# Add user options
|
||||
|
|
@ -278,7 +278,7 @@ class PcbDrawOptions(VariantOptions):
|
|||
tmp_remap = None
|
||||
# The board & output
|
||||
cmd.append(GS.pcb_file)
|
||||
svg = self._append_output(cmd, output)
|
||||
svg = self._append_output(cmd, name)
|
||||
# Execute and inform is successful
|
||||
_run_command(cmd, tmp_remap, tmp_style)
|
||||
if svg is not None:
|
||||
|
|
@ -288,7 +288,7 @@ class PcbDrawOptions(VariantOptions):
|
|||
cmd = [CONVERT, '-trim', png]
|
||||
if self.format == 'jpg':
|
||||
cmd += ['-quality', '85%']
|
||||
cmd.append(output)
|
||||
cmd.append(name)
|
||||
_run_command(cmd, png)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ class PDF_Pcb_PrintOptions(VariantOptions):
|
|||
self.mirror = False
|
||||
""" Print mirrored (X axis inverted). ONLY for KiCad 6 """
|
||||
super().__init__()
|
||||
self._expand_ext = 'pdf'
|
||||
|
||||
@property
|
||||
def drill_marks(self):
|
||||
|
|
@ -53,8 +54,8 @@ class PDF_Pcb_PrintOptions(VariantOptions):
|
|||
raise KiPlotConfigurationError("Unknown drill mark type: {}".format(val))
|
||||
self._drill_marks = val
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
self._drill_marks = PDF_Pcb_PrintOptions._drill_marks_map[self._drill_marks]
|
||||
|
||||
@staticmethod
|
||||
|
|
@ -85,18 +86,13 @@ class PDF_Pcb_PrintOptions(VariantOptions):
|
|||
self.restore_paste_and_glue(board, comps_hash)
|
||||
return fname, fproj
|
||||
|
||||
def get_targets(self, out_dir, layers):
|
||||
layers = Layer.solve(layers)
|
||||
id = '+'.join([la.suffix for la in layers])
|
||||
return [self.expand_filename(out_dir, self.output, id, 'pdf')]
|
||||
def get_targets(self, out_dir):
|
||||
return [self._parent.expand_filename(out_dir, self.output)]
|
||||
|
||||
def run(self, output_dir, layers):
|
||||
super().run(layers)
|
||||
def run(self, output):
|
||||
super().run(self._layers)
|
||||
check_script(CMD_PCBNEW_PRINT_LAYERS, URL_PCBNEW_PRINT_LAYERS, '1.5.2')
|
||||
layers = Layer.solve(layers)
|
||||
# Output file name
|
||||
id = '+'.join([la.suffix for la in layers])
|
||||
output = self.expand_filename(output_dir, self.output, id, 'pdf')
|
||||
cmd = [CMD_PCBNEW_PRINT_LAYERS, 'export', '--output_name', output]
|
||||
if BasePreFlight.get_option('check_zone_fills'):
|
||||
cmd.append('-f')
|
||||
|
|
@ -110,10 +106,10 @@ class PDF_Pcb_PrintOptions(VariantOptions):
|
|||
if self.mirror:
|
||||
cmd.append('--mirror')
|
||||
board_name, proj_name = self.filter_components(GS.board)
|
||||
cmd.extend([board_name, output_dir])
|
||||
cmd.extend([board_name, os.path.dirname(output)])
|
||||
cmd, video_remove = add_extra_options(cmd)
|
||||
# Add the layers
|
||||
cmd.extend([la.layer for la in layers])
|
||||
cmd.extend([la.layer for la in self._layers])
|
||||
# Execute it
|
||||
ret = exec_with_retry(cmd)
|
||||
# Remove the temporal PCB
|
||||
|
|
@ -129,6 +125,11 @@ class PDF_Pcb_PrintOptions(VariantOptions):
|
|||
if os.path.isfile(video_name):
|
||||
os.remove(video_name)
|
||||
|
||||
def set_layers(self, layers):
|
||||
layers = Layer.solve(layers)
|
||||
self._layers = layers
|
||||
self._expand_id = '+'.join([la.suffix for la in layers])
|
||||
|
||||
|
||||
@output_class
|
||||
class PDF_Pcb_Print(BaseOutput): # noqa: F821
|
||||
|
|
@ -145,14 +146,9 @@ class PDF_Pcb_Print(BaseOutput): # noqa: F821
|
|||
""" [list(dict)|list(string)|string] [all,selected,copper,technical,user]
|
||||
List of PCB layers to include in the PDF """
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
# We need layers
|
||||
if isinstance(self.layers, type):
|
||||
raise KiPlotConfigurationError("Missing `layers` list")
|
||||
|
||||
def get_targets(self, out_dir):
|
||||
return self.options.get_targets(out_dir, self.layers)
|
||||
|
||||
def run(self, output_dir):
|
||||
self.options.run(output_dir, self.layers)
|
||||
self.options.set_layers(self.layers)
|
||||
|
|
|
|||
|
|
@ -23,16 +23,17 @@ class PDF_Sch_PrintOptions(VariantOptions):
|
|||
""" Filename for the output PDF (%i=schematic %x=pdf) """
|
||||
super().__init__()
|
||||
self.add_to_doc('variant', "Not fitted components are crossed")
|
||||
self._expand_id = 'schematic'
|
||||
self._expand_ext = 'pdf'
|
||||
|
||||
def get_targets(self, parent, out_dir):
|
||||
id = 'schematic'
|
||||
ext = 'pdf'
|
||||
def get_targets(self, out_dir):
|
||||
if self.output:
|
||||
return [self.expand_filename_sch(out_dir, self.output, id, ext)]
|
||||
return [self.expand_filename_sch(out_dir, '%f.%x', id, ext)]
|
||||
return [self._parent.expand_filename(out_dir, self.output)]
|
||||
return [self._parent.expand_filename(out_dir, '%f.%x')]
|
||||
|
||||
def run(self, output_dir):
|
||||
super().run(output_dir)
|
||||
def run(self, name):
|
||||
super().run(name)
|
||||
output_dir = os.path.dirname(name)
|
||||
check_eeschema_do()
|
||||
if self._comps:
|
||||
# Save it to a temporal dir
|
||||
|
|
@ -53,18 +54,15 @@ class PDF_Sch_PrintOptions(VariantOptions):
|
|||
logger.error(CMD_EESCHEMA_DO+' returned %d', ret)
|
||||
exit(PDF_SCH_PRINT)
|
||||
if self.output:
|
||||
id = 'schematic'
|
||||
ext = 'pdf'
|
||||
cur = self.expand_filename_sch(output_dir, '%f.%x', id, ext)
|
||||
new = self.expand_filename_sch(output_dir, self.output, id, ext)
|
||||
logger.debug('Moving '+cur+' -> '+new)
|
||||
os.rename(cur, new)
|
||||
cur = self._parent.expand_filename(output_dir, '%f.%x')
|
||||
logger.debug('Moving '+cur+' -> '+name)
|
||||
os.rename(cur, name)
|
||||
# Remove the temporal dir if needed
|
||||
if sch_dir:
|
||||
logger.debug('Removing temporal variant dir `{}`'.format(sch_dir))
|
||||
rmtree(sch_dir)
|
||||
if video_remove:
|
||||
video_name = os.path.join(GS.out_dir, 'export_eeschema_screencast.ogv')
|
||||
video_name = os.path.join(output_dir, 'export_eeschema_screencast.ogv')
|
||||
if os.path.isfile(video_name):
|
||||
os.remove(video_name)
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
# License: GPL-3.0
|
||||
# Project: KiBot (formerly KiPlot)
|
||||
# Adapted from: https://github.com/johnbeard/kiplot/pull/10
|
||||
import os
|
||||
from re import compile
|
||||
from datetime import datetime
|
||||
from pcbnew import IU_PER_MM, IU_PER_MILS
|
||||
|
|
@ -44,8 +45,8 @@ class PosColumns(Optionable):
|
|||
self._id_example = 'Ref'
|
||||
self._name_example = 'Reference'
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
if not self.id:
|
||||
raise KiPlotConfigurationError("Missing or empty `id` in columns list ({})".format(str(self._tree)))
|
||||
|
||||
|
|
@ -68,9 +69,10 @@ class PositionOptions(VariantOptions):
|
|||
self.bottom_negative_x = False
|
||||
""" Use negative X coordinates for footprints on bottom layer """
|
||||
super().__init__()
|
||||
self._expand_id = 'position'
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
if isinstance(self.columns, type):
|
||||
# Default list of columns
|
||||
self.columns = OrderedDict([('Ref', 'Ref'), ('Val', 'Val'), ('Package', 'Package'), ('PosX', 'PosX'),
|
||||
|
|
@ -86,6 +88,7 @@ class PositionOptions(VariantOptions):
|
|||
new_name = col.name if col.name else new_col
|
||||
new_columns[new_col] = new_name
|
||||
self.columns = new_columns
|
||||
self._expand_ext = 'pos' if self.format == 'ASCII' else 'csv'
|
||||
|
||||
def _do_position_plot_ascii(self, output_dir, columns, modulesStr, maxSizes):
|
||||
topf = None
|
||||
|
|
@ -200,15 +203,16 @@ class PositionOptions(VariantOptions):
|
|||
return PositionOptions.is_pure_smd_5, PositionOptions.is_not_virtual_5
|
||||
return PositionOptions.is_pure_smd_6, PositionOptions.is_not_virtual_6 # pragma: no cover (Ki6)
|
||||
|
||||
def get_targets(self, parent, out_dir):
|
||||
ext = 'pos' if self.format == 'ASCII' else 'csv'
|
||||
def get_targets(self, out_dir):
|
||||
ext = self._expand_ext
|
||||
if self.separate_files_for_front_and_back:
|
||||
return [self.expand_filename(out_dir, self.output, 'top_pos', ext),
|
||||
self.expand_filename(out_dir, self.output, 'bottom_pos', ext)]
|
||||
return [self.expand_filename(out_dir, self.output, 'both_pos', ext)]
|
||||
|
||||
def run(self, output_dir):
|
||||
super().run(output_dir)
|
||||
def run(self, fname):
|
||||
super().run(fname)
|
||||
output_dir = os.path.dirname(fname)
|
||||
columns = self.columns.values()
|
||||
# Note: the parser already checked the units are milimeters or inches
|
||||
conv = 1.0
|
||||
|
|
@ -223,11 +227,13 @@ class PositionOptions(VariantOptions):
|
|||
quote_char = '"' if self.format == 'CSV' else ''
|
||||
for m in sorted(GS.board.GetModules(), key=lambda c: _ref_key(c.GetReference())):
|
||||
ref = m.GetReference()
|
||||
logger.debug('P&P ref: {}'.format(ref))
|
||||
value = None
|
||||
# Apply any filter or variant data
|
||||
if comps_hash:
|
||||
c = comps_hash.get(ref, None)
|
||||
if c:
|
||||
logger.debug('fit: {} include: {}'.format(c.fitted, c.included))
|
||||
if not c.fitted or not c.included:
|
||||
continue
|
||||
value = c.value
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class Sch_Variant_Options(VariantOptions):
|
|||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def get_targets(self, parent, out_dir):
|
||||
def get_targets(self, out_dir):
|
||||
return GS.sch.file_names_variant(out_dir)
|
||||
|
||||
def run(self, output_dir):
|
||||
|
|
@ -33,3 +33,7 @@ class Sch_Variant(BaseOutput): # noqa: F821
|
|||
self.options = Sch_Variant_Options
|
||||
""" [dict] Options for the `sch_variant` output """
|
||||
self._sch_related = True
|
||||
|
||||
def run(self, output_dir):
|
||||
# No output member, just a dir
|
||||
self.options.run(output_dir)
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ class STEPOptions(VariantOptions):
|
|||
# Temporal dir used to store the downloaded files
|
||||
self._tmp_dir = None
|
||||
super().__init__()
|
||||
self._expand_id = '3D'
|
||||
self._expand_ext = 'step'
|
||||
|
||||
@property
|
||||
def origin(self):
|
||||
|
|
@ -197,13 +199,11 @@ class STEPOptions(VariantOptions):
|
|||
models.push_front(model)
|
||||
return fname
|
||||
|
||||
def get_targets(self, parent, out_dir):
|
||||
return [self.expand_filename(out_dir, self.output, '3D', 'step')]
|
||||
def get_targets(self, out_dir):
|
||||
return [self._parent.expand_filename(out_dir, self.output)]
|
||||
|
||||
def run(self, output_dir):
|
||||
super().run(output_dir)
|
||||
# Output file name
|
||||
output = self.get_targets(None, output_dir)[0]
|
||||
def run(self, output):
|
||||
super().run(output)
|
||||
# Make units explicit
|
||||
if self.metric_units:
|
||||
units = 'mm'
|
||||
|
|
|
|||
|
|
@ -24,16 +24,17 @@ class SVG_Sch_PrintOptions(VariantOptions):
|
|||
""" Filename for the output SVG (%i=schematic %x=svg) """
|
||||
super().__init__()
|
||||
self.add_to_doc('variant', "Not fitted components are crossed")
|
||||
self._expand_id = 'schematic'
|
||||
self._expand_ext = 'svg'
|
||||
|
||||
def get_targets(self, parent, out_dir):
|
||||
id = 'schematic'
|
||||
ext = 'svg'
|
||||
def get_targets(self, out_dir):
|
||||
if self.output:
|
||||
return [self.expand_filename_sch(out_dir, self.output, id, ext)]
|
||||
return [self.expand_filename_sch(out_dir, '%f.%x', id, ext)]
|
||||
return [self._parent.expand_filename(out_dir, self.output)]
|
||||
return [self._parent.expand_filename(out_dir, '%f.%x')]
|
||||
|
||||
def run(self, output_dir):
|
||||
super().run(output_dir)
|
||||
def run(self, name):
|
||||
super().run(name)
|
||||
output_dir = os.path.dirname(name)
|
||||
check_eeschema_do()
|
||||
if self._comps:
|
||||
# Save it to a temporal dir
|
||||
|
|
@ -50,18 +51,15 @@ class SVG_Sch_PrintOptions(VariantOptions):
|
|||
logger.error(CMD_EESCHEMA_DO+' returned %d', ret)
|
||||
exit(SVG_SCH_PRINT)
|
||||
if self.output:
|
||||
id = 'schematic'
|
||||
ext = 'svg'
|
||||
cur = self.expand_filename_sch(output_dir, '%f.%x', id, ext)
|
||||
new = self.expand_filename_sch(output_dir, self.output, id, ext)
|
||||
logger.debug('Moving '+cur+' -> '+new)
|
||||
os.rename(cur, new)
|
||||
cur = self._parent.expand_filename(output_dir, '%f.%x')
|
||||
logger.debug('Moving '+cur+' -> '+name)
|
||||
os.rename(cur, name)
|
||||
# Remove the temporal dir if needed
|
||||
if sch_dir:
|
||||
logger.debug('Removing temporal variant dir `{}`'.format(sch_dir))
|
||||
rmtree(sch_dir)
|
||||
if video_remove:
|
||||
video_name = os.path.join(GS.out_dir, 'export_eeschema_screencast.ogv')
|
||||
video_name = os.path.join(output_dir, 'export_eeschema_screencast.ogv')
|
||||
if os.path.isfile(video_name):
|
||||
os.remove(video_name)
|
||||
|
||||
|
|
|
|||
|
|
@ -104,3 +104,6 @@ class BasePreFlight(Registrable):
|
|||
def get_targets(self):
|
||||
""" Returns a list of targets generated by this preflight """
|
||||
return []
|
||||
|
||||
def _find_variant(self):
|
||||
return ''
|
||||
|
|
|
|||
|
|
@ -26,12 +26,15 @@ class Run_DRC(BasePreFlight): # noqa: F821
|
|||
raise KiPlotConfigurationError('must be boolean')
|
||||
self._enabled = value
|
||||
self._pcb_related = True
|
||||
self._expand_id = 'drc'
|
||||
self._expand_ext = 'txt'
|
||||
|
||||
def get_targets(self):
|
||||
""" Returns a list of targets generated by this preflight """
|
||||
load_board()
|
||||
out_pattern = GS.global_output if GS.global_output is not None else GS.def_global_output
|
||||
return [Optionable.expand_filename(None, GS.out_dir, out_pattern, 'drc', 'txt')]
|
||||
name = Optionable.expand_filename_pcb(self, out_pattern)
|
||||
return [os.path.abspath(os.path.join(GS.out_dir, name))]
|
||||
|
||||
def run(self):
|
||||
check_script(CMD_PCBNEW_RUN_DRC, URL_PCBNEW_RUN_DRC, '1.4.0')
|
||||
|
|
|
|||
|
|
@ -26,12 +26,15 @@ class Run_ERC(BasePreFlight): # noqa: F821
|
|||
raise KiPlotConfigurationError('must be boolean')
|
||||
self._enabled = value
|
||||
self._sch_related = True
|
||||
self._expand_id = 'erc'
|
||||
self._expand_ext = 'txt'
|
||||
|
||||
def get_targets(self):
|
||||
""" Returns a list of targets generated by this preflight """
|
||||
load_sch()
|
||||
out_pattern = GS.global_output if GS.global_output is not None else GS.def_global_output
|
||||
return [Optionable.expand_filename_sch(None, GS.out_dir, out_pattern, 'erc', 'txt')]
|
||||
name = Optionable.expand_filename_sch(self, out_pattern)
|
||||
return [os.path.abspath(os.path.join(GS.out_dir, name))]
|
||||
|
||||
def run(self):
|
||||
check_eeschema_do()
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ class FiltersOptions(Optionable):
|
|||
""" [list(dict)] DRC/ERC errors to be ignored """
|
||||
self._filter_what = 'DRC/ERC errors'
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
parsed = None
|
||||
self.unparsed = None
|
||||
if not isinstance(self.filters, type):
|
||||
|
|
@ -82,7 +82,7 @@ class Filters(BasePreFlight): # noqa: F821
|
|||
def __init__(self, name, value):
|
||||
f = FiltersOptions()
|
||||
f.set_tree({'filters': value})
|
||||
f.config()
|
||||
f.config(self)
|
||||
super().__init__(name, f.filters)
|
||||
|
||||
def get_example():
|
||||
|
|
|
|||
|
|
@ -36,8 +36,8 @@ class BaseVariant(RegVariant):
|
|||
""" [string|list(string)=''] Name of the filter to mark components as 'Do Not Change'.
|
||||
Use '_kibom_dnc' for the default KiBoM behavior """
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
self.pre_transform = BaseFilter.solve_filter(self.pre_transform, 'pre_transform')
|
||||
|
||||
def filter(self, comps):
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ class IBoM(BaseVariant): # noqa: F821
|
|||
val = []
|
||||
return val
|
||||
|
||||
def config(self):
|
||||
super().config()
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
self.exclude_filter = BaseFilter.solve_filter(self.exclude_filter, 'exclude_filter', IFILT_MECHANICAL)
|
||||
self.dnf_filter = BaseFilter.solve_filter(self.dnf_filter, 'dnf_filter')
|
||||
self.dnc_filter = BaseFilter.solve_filter(self.dnc_filter, 'dnc_filter')
|
||||
|
|
|
|||
|
|
@ -39,9 +39,9 @@ class KiBoM(BaseVariant): # noqa: F821
|
|||
self._def_dnf_filter = dnf_filter
|
||||
self._def_dnc_filter = dnc_filter
|
||||
|
||||
def config(self):
|
||||
def config(self, parent):
|
||||
# Now we can let the parent initialize the filters
|
||||
super().config()
|
||||
super().config(parent)
|
||||
# Variants, ensure a list
|
||||
if isinstance(self.variant, type):
|
||||
self.variant = []
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class TestOptions(BaseOptions):
|
|||
self.bar = 'nope'
|
||||
""" nothing """ # pragma: no cover
|
||||
|
||||
def get_targets(self, parent, out_dir):
|
||||
def get_targets(self, out_dir):
|
||||
return ['dummy']
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ def run_compress(ctx, test_import_fail=False):
|
|||
# Create a compress object with the dummy file as source
|
||||
out = RegOutput.get_class_for('compress')()
|
||||
out.set_tree({'options': {'format': 'RAR', 'files': [{'source': ctx.get_out_path('*')}]}})
|
||||
out.config()
|
||||
out.config(None)
|
||||
# Setup the GS output dir, needed for the output path
|
||||
GS.out_dir = '.'
|
||||
# Run the compression and catch the error
|
||||
|
|
@ -168,7 +168,7 @@ def test_ibom_parse_fail(test_dir, caplog, monkeypatch):
|
|||
# Create an ibom object
|
||||
out = RegOutput.get_class_for('ibom')()
|
||||
out.set_tree({})
|
||||
out.config()
|
||||
out.config(None)
|
||||
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
||||
out.run('')
|
||||
assert pytest_wrapped_e.type == SystemExit
|
||||
|
|
@ -224,7 +224,7 @@ def test_pre_xrc_fail(test_dir, caplog, monkeypatch):
|
|||
pre_erc.run()
|
||||
out = RegOutput.get_class_for('pdf_pcb_print')()
|
||||
out.set_tree({'layers': 'all'})
|
||||
out.config()
|
||||
out.config(None)
|
||||
with pytest.raises(SystemExit) as e3:
|
||||
out.run('')
|
||||
assert e1.type == SystemExit
|
||||
|
|
@ -264,7 +264,7 @@ def test_step_fail(test_dir, caplog, monkeypatch):
|
|||
# Create a compress object with the dummy file as source
|
||||
out = RegOutput.get_class_for('step')()
|
||||
out.set_tree({})
|
||||
out.config()
|
||||
out.config(None)
|
||||
with pytest.raises(SystemExit) as e:
|
||||
out.run('')
|
||||
# Check we exited because rar isn't installed
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ def test_pcbdraw_miss_rsvg(caplog, monkeypatch):
|
|||
o.style = ''
|
||||
o.remap = None
|
||||
o.format = 'jpg'
|
||||
o.config()
|
||||
o.config(None)
|
||||
cov.load()
|
||||
cov.start()
|
||||
o.run('')
|
||||
|
|
@ -88,7 +88,7 @@ def test_pcbdraw_miss_convert(caplog, monkeypatch):
|
|||
o.style = ''
|
||||
o.remap = None
|
||||
o.format = 'jpg'
|
||||
o.config()
|
||||
o.config(None)
|
||||
cov.load()
|
||||
cov.start()
|
||||
o.run('')
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ def test_3Rs_position_1(test_dir):
|
|||
def test_3Rs_position_neg_x(test_dir):
|
||||
ctx = context.TestContext(test_dir, '3Rs_position_neg_x', '3Rs', 'simple_position_neg_x', POS_DIR)
|
||||
ctx.run()
|
||||
ctx.sub_dir = os.path.join(ctx.sub_dir, 'position')
|
||||
pos_top = ctx.get_pos_top_filename()
|
||||
pos_bot = ctx.get_pos_bot_filename()
|
||||
ctx.expect_out_file(pos_top)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ outputs:
|
|||
- name: 'position'
|
||||
comment: "Pick and place file"
|
||||
type: position
|
||||
dir: positiondir
|
||||
dir: positiondir/%i
|
||||
options:
|
||||
format: ASCII # CSV or ASCII format
|
||||
units: millimeters # millimeters or inches
|
||||
|
|
|
|||
Loading…
Reference in New Issue