From 1b48e614a7ed157328927c6513f482736062cbf1 Mon Sep 17 00:00:00 2001 From: "Salvador E. Tropea" Date: Fri, 12 Mar 2021 21:14:39 -0300 Subject: [PATCH] Added pattern expansion in the `dir` option for outputs Closes #58 --- CHANGELOG.md | 1 + kibot/config_reader.py | 4 +- kibot/drill_marks.py | 4 +- kibot/fil_base.py | 6 +-- kibot/fil_generic.py | 4 +- kibot/fil_rot_footprint.py | 4 +- kibot/fil_var_rename.py | 4 +- kibot/globals.py | 4 +- kibot/kiplot.py | 5 ++- kibot/layer.py | 4 +- kibot/optionable.py | 40 +++++++++++++----- kibot/out_any_drill.py | 11 +++-- kibot/out_any_layer.py | 8 ++-- kibot/out_base.py | 27 ++++++++---- kibot/out_bom.py | 41 ++++++++++--------- kibot/out_compress.py | 30 +++++++------- kibot/out_ibom.py | 21 ++++++---- kibot/out_kibom.py | 26 +++++++----- kibot/out_pcbdraw.py | 26 ++++++------ kibot/out_pdf_pcb_print.py | 38 ++++++++--------- kibot/out_pdf_sch_print.py | 26 ++++++------ kibot/out_position.py | 22 ++++++---- kibot/out_sch_variant.py | 6 ++- kibot/out_step.py | 12 +++--- kibot/out_svg_sch_print.py | 26 ++++++------ kibot/pre_base.py | 3 ++ kibot/pre_drc.py | 5 ++- kibot/pre_erc.py | 5 ++- kibot/pre_filters.py | 6 +-- kibot/var_base.py | 4 +- kibot/var_ibom.py | 4 +- kibot/var_kibom.py | 4 +- tests/.config/kiplot/plugins/out_test.py | 2 +- tests/test_plot/test_misc_2.py | 8 ++-- tests/test_plot/test_pcbdraw.py | 4 +- tests/test_plot/test_position.py | 1 + .../simple_position_neg_x.kibot.yaml | 2 +- 37 files changed, 253 insertions(+), 195 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a89610cd..1e3ed9c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. diff --git a/kibot/config_reader.py b/kibot/config_reader.py index a932d081..0bdfe5ba 100644 --- a/kibot/config_reader.py +++ b/kibot/config_reader.py @@ -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)) diff --git a/kibot/drill_marks.py b/kibot/drill_marks.py index 1c079a6f..6a2db68d 100644 --- a/kibot/drill_marks.py +++ b/kibot/drill_marks.py @@ -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): diff --git a/kibot/fil_base.py b/kibot/fil_base.py index 6b77d74c..af98be87 100644 --- a/kibot/fil_base.py +++ b/kibot/fil_base.py @@ -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 diff --git a/kibot/fil_generic.py b/kibot/fil_generic.py index 0c1d2cf8..54c9b58a 100644 --- a/kibot/fil_generic.py +++ b/kibot/fil_generic.py @@ -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 diff --git a/kibot/fil_rot_footprint.py b/kibot/fil_rot_footprint.py index e2e1db72..7420adf4 100644 --- a/kibot/fil_rot_footprint.py +++ b/kibot/fil_rot_footprint.py @@ -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: diff --git a/kibot/fil_var_rename.py b/kibot/fil_var_rename.py index 1a7c0021..491d6441 100644 --- a/kibot/fil_var_rename.py +++ b/kibot/fil_var_rename.py @@ -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 = ':' diff --git a/kibot/globals.py b/kibot/globals.py index 2c683a0b..d5e8e4a7 100644 --- a/kibot/globals.py +++ b/kibot/globals.py @@ -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') diff --git a/kibot/kiplot.py b/kibot/kiplot.py index 6067e633..a52df460 100644 --- a/kibot/kiplot.py +++ b/kibot/kiplot.py @@ -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)) diff --git a/kibot/layer.py b/kibot/layer.py index 21ae1983..f5b531d7 100644 --- a/kibot/layer.py +++ b/kibot/layer.py @@ -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: diff --git a/kibot/optionable.py b/kibot/optionable.py index 3bf8e111..a5505b38 100644 --- a/kibot/optionable.py +++ b/kibot/optionable.py @@ -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 diff --git a/kibot/out_any_drill.py b/kibot/out_any_drill.py index c3e136b5..9c955ab1 100644 --- a/kibot/out_any_drill.py +++ b/kibot/out_any_drill.py @@ -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(): diff --git a/kibot/out_any_layer.py b/kibot/out_any_layer.py index 74155b52..4f8e2a01 100644 --- a/kibot/out_any_layer.py +++ b/kibot/out_any_layer.py @@ -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") diff --git a/kibot/out_base.py b/kibot/out_base.py index e851c58d..f85baaa6 100644 --- a/kibot/out_base.py +++ b/kibot/out_base.py @@ -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') diff --git a/kibot/out_bom.py b/kibot/out_bom.py index ca6b5cd7..48b59f1b 100644 --- a/kibot/out_bom.py +++ b/kibot/out_bom.py @@ -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 diff --git a/kibot/out_compress.py b/kibot/out_compress.py index 0d55f4a5..4e1ae6cb 100644 --- a/kibot/out_compress.py +++ b/kibot/out_compress.py @@ -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() diff --git a/kibot/out_ibom.py b/kibot/out_ibom.py index 294b5a62..f26e9ad3 100644 --- a/kibot/out_ibom.py +++ b/kibot/out_ibom.py @@ -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: diff --git a/kibot/out_kibom.py b/kibot/out_kibom.py index f75cccc9..63df7977 100644 --- a/kibot/out_kibom.py +++ b/kibot/out_kibom.py @@ -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), diff --git a/kibot/out_pcbdraw.py b/kibot/out_pcbdraw.py index 1b439c8b..6001cd5a 100644 --- a/kibot/out_pcbdraw.py +++ b/kibot/out_pcbdraw.py @@ -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) diff --git a/kibot/out_pdf_pcb_print.py b/kibot/out_pdf_pcb_print.py index 9c8da3e9..0fc3363c 100644 --- a/kibot/out_pdf_pcb_print.py +++ b/kibot/out_pdf_pcb_print.py @@ -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) diff --git a/kibot/out_pdf_sch_print.py b/kibot/out_pdf_sch_print.py index d09dbba4..d3d1b7be 100644 --- a/kibot/out_pdf_sch_print.py +++ b/kibot/out_pdf_sch_print.py @@ -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) diff --git a/kibot/out_position.py b/kibot/out_position.py index b7238d7b..5c08e136 100644 --- a/kibot/out_position.py +++ b/kibot/out_position.py @@ -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 diff --git a/kibot/out_sch_variant.py b/kibot/out_sch_variant.py index 3ca9e6e1..1ec6cf42 100644 --- a/kibot/out_sch_variant.py +++ b/kibot/out_sch_variant.py @@ -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) diff --git a/kibot/out_step.py b/kibot/out_step.py index 4e101d81..faba05ec 100644 --- a/kibot/out_step.py +++ b/kibot/out_step.py @@ -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' diff --git a/kibot/out_svg_sch_print.py b/kibot/out_svg_sch_print.py index c3e7260e..47800ca4 100644 --- a/kibot/out_svg_sch_print.py +++ b/kibot/out_svg_sch_print.py @@ -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) diff --git a/kibot/pre_base.py b/kibot/pre_base.py index 5aef30dc..27bc40d4 100644 --- a/kibot/pre_base.py +++ b/kibot/pre_base.py @@ -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 '' diff --git a/kibot/pre_drc.py b/kibot/pre_drc.py index cf0ac8c5..4355eadd 100644 --- a/kibot/pre_drc.py +++ b/kibot/pre_drc.py @@ -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') diff --git a/kibot/pre_erc.py b/kibot/pre_erc.py index 9b787d5e..e3c5d291 100644 --- a/kibot/pre_erc.py +++ b/kibot/pre_erc.py @@ -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() diff --git a/kibot/pre_filters.py b/kibot/pre_filters.py index c937698d..daf37adb 100644 --- a/kibot/pre_filters.py +++ b/kibot/pre_filters.py @@ -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(): diff --git a/kibot/var_base.py b/kibot/var_base.py index 8d9ddf50..e659d2f2 100644 --- a/kibot/var_base.py +++ b/kibot/var_base.py @@ -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): diff --git a/kibot/var_ibom.py b/kibot/var_ibom.py index 6e20a7c4..2715f044 100644 --- a/kibot/var_ibom.py +++ b/kibot/var_ibom.py @@ -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') diff --git a/kibot/var_kibom.py b/kibot/var_kibom.py index 36cc5e4a..f254fe63 100644 --- a/kibot/var_kibom.py +++ b/kibot/var_kibom.py @@ -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 = [] diff --git a/tests/.config/kiplot/plugins/out_test.py b/tests/.config/kiplot/plugins/out_test.py index 5d4ff160..2204853c 100644 --- a/tests/.config/kiplot/plugins/out_test.py +++ b/tests/.config/kiplot/plugins/out_test.py @@ -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'] diff --git a/tests/test_plot/test_misc_2.py b/tests/test_plot/test_misc_2.py index 311ef79c..fdcd9e33 100644 --- a/tests/test_plot/test_misc_2.py +++ b/tests/test_plot/test_misc_2.py @@ -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 diff --git a/tests/test_plot/test_pcbdraw.py b/tests/test_plot/test_pcbdraw.py index 540959e5..51c7e9a7 100644 --- a/tests/test_plot/test_pcbdraw.py +++ b/tests/test_plot/test_pcbdraw.py @@ -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('') diff --git a/tests/test_plot/test_position.py b/tests/test_plot/test_position.py index 9e38f3b8..cede7df7 100644 --- a/tests/test_plot/test_position.py +++ b/tests/test_plot/test_position.py @@ -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) diff --git a/tests/yaml_samples/simple_position_neg_x.kibot.yaml b/tests/yaml_samples/simple_position_neg_x.kibot.yaml index bc230db1..4833168b 100644 --- a/tests/yaml_samples/simple_position_neg_x.kibot.yaml +++ b/tests/yaml_samples/simple_position_neg_x.kibot.yaml @@ -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