Fixed problems when using page layout files with relative paths.

Fixes #174
This commit is contained in:
Salvador E. Tropea 2022-04-04 18:02:31 -03:00
parent 4b0f7a29de
commit 9e1f645c31
45 changed files with 2240 additions and 1856 deletions

View File

@ -120,6 +120,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
not specifying the SCH and more than one SCH was found. (#138)
- 3D: problems to download 3D models for native KiCad 6 files. (#171)
(not imported from KiCad 5)
- Problems when using page layout files with relative paths. (#174)
## [0.11.0] - 2021-04-25

View File

@ -64,13 +64,14 @@ test1:
#@cat output/*/error.txt
test_docker_local_1:
rm -rf output
rm -f tests/.local
-rm -rf output
-rm -f tests/.local
$(PY_COV) erase
# Run in the same directory to make the __pycache__ valid
# Also change the owner of the files to the current user (we run as root like in GitHub)
#docker run --rm -it -v $(CWD):$(CWD) --workdir="$(CWD)" setsoft/kicad_auto_test:latest '/bin/bash'
docker run --rm -v $(CWD):$(CWD) --workdir="$(CWD)" setsoft/kicad_auto_test:latest \
/bin/bash -c "flake8 . --count --statistics ; python3-coverage run -a src/kibot --help-outputs > /dev/null; pytest-3 --log-cli-level debug -k 'test_step_2' --test_dir output ; $(PY_COV) html; chown -R $(USER_ID):$(GROUP_ID) output/ tests/board_samples/ tests/.config/kiplot/plugins/__pycache__/ tests/test_plot/fake_pcbnew/__pycache__/ tests/.config/kibot/plugins/__pycache__/ .coverage htmlcov/"
/bin/bash -c "flake8 . --count --statistics ; python3-coverage run -a src/kibot --help-outputs > /dev/null; pytest-3 --log-cli-level debug -k 'test_print_sch_variant_ni_1' --test_dir output ; $(PY_COV) html; chown -R $(USER_ID):$(GROUP_ID) output/ tests/board_samples/ tests/.config/kiplot/plugins/__pycache__/ tests/test_plot/fake_pcbnew/__pycache__/ tests/.config/kibot/plugins/__pycache__/ .coverage htmlcov/"
#$(PY_COV) report
#x-www-browser htmlcov/index.html
rm .coverage

View File

@ -1698,7 +1698,7 @@ Next time you need this list just use an alias, like this:
A short-cut to use for simple cases where a variant is an overkill.
- `frame`: [boolean=true] Include the frame and title block.
- `monochrome`: [boolean=false] Generate a monochromatic PDF.
- `output`: [string='%f-%i%I%v.%x'] Filename for the output PDF (%i=schematic %x=pdf). Affected by global options.
- `output`: [string='%f-%i%I%v.%x'] Filename for the output PDF (%i=schematic, %x=pdf). Affected by global options.
- `variant`: [string=''] Board variant to apply.
Not fitted components are crossed.
- `output_id`: [string=''] Text to use for the %I expansion content. To differentiate variations of this output.
@ -2098,7 +2098,9 @@ Next time you need this list just use an alias, like this:
* Valid keys:
- `dnf_filter`: [string|list(string)='_none'] Name of the filter to mark components as not fitted.
A short-cut to use for simple cases where a variant is an overkill.
- `output`: [string='%f-%i%I%v.%x'] Filename for the output SVG (%i=schematic %x=svg). Affected by global options.
- `frame`: [boolean=true] Include the frame and title block.
- `monochrome`: [boolean=false] Generate a monochromatic PDF.
- `output`: [string='%f-%i%I%v.%x'] Filename for the output SVG (%i=schematic, %x=svg). Affected by global options.
- `variant`: [string=''] Board variant to apply.
Not fitted components are crossed.
- `output_id`: [string=''] Text to use for the %I expansion content. To differentiate variations of this output.

View File

@ -1123,7 +1123,7 @@ outputs:
frame: true
# [boolean=false] Generate a monochromatic PDF
monochrome: false
# [string='%f-%i%I%v.%x'] Filename for the output PDF (%i=schematic %x=pdf). Affected by global options
# [string='%f-%i%I%v.%x'] Filename for the output PDF (%i=schematic, %x=pdf). Affected by global options
output: '%f-%i%I%v.%x'
# [string=''] Board variant to apply.
# Not fitted components are crossed
@ -1534,7 +1534,11 @@ outputs:
# [string|list(string)='_none'] Name of the filter to mark components as not fitted.
# A short-cut to use for simple cases where a variant is an overkill
dnf_filter: '_none'
# [string='%f-%i%I%v.%x'] Filename for the output SVG (%i=schematic %x=svg). Affected by global options
# [boolean=true] Include the frame and title block
frame: true
# [boolean=false] Generate a monochromatic PDF
monochrome: false
# [string='%f-%i%I%v.%x'] Filename for the output SVG (%i=schematic, %x=svg). Affected by global options
output: '%f-%i%I%v.%x'
# [string=''] Board variant to apply.
# Not fitted components are crossed

View File

@ -328,11 +328,11 @@ class GS(object):
exit(EXIT_BAD_ARGS)
@staticmethod
def copy_project(pcb_name):
def copy_project(new_pcb_name):
pro_name = GS.pro_file
if pro_name is None or not os.path.isfile(pro_name):
return None
pro_copy = pcb_name.replace('.kicad_pcb', GS.pro_ext)
pro_copy = new_pcb_name.replace('.kicad_pcb', GS.pro_ext)
logger.debug('Copying project `{}` to `{}`'.format(pro_name, pro_copy))
copy2(pro_name, pro_copy)
return pro_copy

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020 Salvador E. Tropea
# Copyright (c) 2020 Instituto Nacional de Tecnología Industrial
# Copyright (c) 2020-2022 Salvador E. Tropea
# Copyright (c) 2020-2022 Instituto Nacional de Tecnología Industrial
# License: GPL-3.0
# Project: KiBot (formerly KiPlot)
"""
@ -20,11 +20,12 @@ import sys
import json
from io import StringIO
from glob import glob
from shutil import copy2
import platform
import sysconfig
from ..gs import GS
from .. import log
from ..misc import W_NOCONFIG, W_NOKIENV, W_NOLIBS, W_NODEFSYMLIB
from ..misc import W_NOCONFIG, W_NOKIENV, W_NOLIBS, W_NODEFSYMLIB, MISSING_WKS
# Check python version to determine which version of ConfirParser to import
if sys.version_info.major >= 3:
@ -67,6 +68,8 @@ def expand_env(val, env, extra_env, used_extra=None):
val = val.replace('${'+var+'}', extra_env[var])
used_extra[0] = True
else:
logger.error(env)
logger.error(extra_env)
logger.error('Unable to expand `{}` in `{}`'.format(var, val))
return val
@ -381,6 +384,62 @@ class KiConf(object):
# Load the project's table
KiConf.load_lib_aliases(os.path.join(KiConf.dirname, SYM_LIB_TABLE))
def fix_page_layout_k6_key(key, data, dest_dir):
if key in data:
section = data[key]
pl = section.get('page_layout_descr_file', None)
if pl:
fname = KiConf.expand_env(pl)
if os.path.isfile(fname):
dest = os.path.join(dest_dir, key+'.kicad_wks')
logger.debug('Copying {} -> {}'.format(fname, dest))
copy2(fname, dest)
data[key]['page_layout_descr_file'] = dest
else:
logger.error('Missing page layout file: '+fname)
exit(MISSING_WKS)
def fix_page_layout_k6(project):
# Get the current definitions
dest_dir = os.path.dirname(project)
with open(project, 'rt') as f:
pro_text = f.read()
data = json.loads(pro_text)
KiConf.fix_page_layout_k6_key('pcbnew', data, dest_dir)
KiConf.fix_page_layout_k6_key('schematic', data, dest_dir)
with open(project, 'wt') as f:
f.write(json.dumps(data, sort_keys=True, indent=2))
def fix_page_layout_k5(project):
order = 1
dest_dir = os.path.dirname(project)
with open(project, 'rt') as f:
lns = f.readlines()
for c, line in enumerate(lns):
if line.startswith('PageLayoutDescrFile='):
fname = line[20:].strip()
logger.error(fname)
fname = KiConf.expand_env(fname)
logger.error(fname)
if os.path.isfile(fname):
dest = os.path.join(dest_dir, str(order)+'.kicad_wks')
copy2(fname, dest)
else:
logger.error('Missing page layout file: '+fname)
exit(MISSING_WKS)
lns[c] = 'PageLayoutDescrFile='+dest+'\n'
with open(project, 'wt') as f:
lns = f.writelines(lns)
def fix_page_layout(project):
if not project:
return
KiConf.init(GS.pcb_file)
if GS.ki5():
KiConf.fix_page_layout_k5(project)
else:
KiConf.fix_page_layout_k6(project)
def expand_env(name, used_extra=None):
if used_extra is None:
used_extra = [False]

View File

@ -37,6 +37,7 @@ WRONG_INSTALL = 23
RENDER_3D_ERR = 24
FAILED_EXECUTE = 25
KICOST_ERROR = 26
MISSING_WKS = 27
error_level_to_name = ['NONE',
'INTERNAL_ERROR',
'WRONG_ARGUMENTS',
@ -64,6 +65,7 @@ error_level_to_name = ['NONE',
'RENDER_3D_ERR',
'FAILED_EXECUTE',
'KICOST_ERROR',
'MISSING_WKS',
]
CMD_EESCHEMA_DO = 'eeschema_do'
URL_EESCHEMA_DO = 'https://github.com/INTI-CMNB/KiAuto'

View File

@ -5,7 +5,6 @@
# Project: KiBot (formerly KiPlot)
import os
from shutil import rmtree
from tempfile import mkdtemp
from .pre_base import BasePreFlight
from .error import KiPlotConfigurationError
from .gs import GS
@ -77,12 +76,7 @@ class Any_PCB_PrintOptions(VariantOptions):
if self.hide_excluded:
self.remove_fab(board, comps_hash)
# Save the PCB to a temporal dir
pcb_dir = mkdtemp(prefix='tmp-kibot-pdf_pcb_print-')
fname = os.path.join(pcb_dir, GS.pcb_basename+'.kicad_pcb')
logger.debug('Storing filtered PCB to `{}`'.format(fname))
GS.board.Save(fname)
# Copy the project: avoids warnings, could carry some options
GS.copy_project(fname)
fname, pcb_dir = self.save_tmp_dir_board('pdf_pcb_print')
self.uncross_modules(board, comps_hash)
self.restore_paste_and_glue(board, comps_hash)
if self.hide_excluded:

View File

@ -0,0 +1,85 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020-2022 Salvador E. Tropea
# Copyright (c) 2020-2022 Instituto Nacional de Tecnología Industrial
# License: GPL-3.0
# Project: KiBot (formerly KiPlot)
import os
from tempfile import mkdtemp
from shutil import rmtree, copy2
from .gs import GS
from .kiplot import check_eeschema_do, exec_with_retry, add_extra_options
from .misc import CMD_EESCHEMA_DO
from .out_base import VariantOptions
from .kicad.config import KiConf
from .macros import macros, document, output_class # noqa: F401
from . import log
logger = log.get_logger()
def copy_project(sch_dir):
""" Copy the project file to the temporal dir """
ext = GS.pro_ext
source = GS.pro_file
prj_file = os.path.join(sch_dir, GS.sch_basename+ext)
if source is not None and os.path.isfile(source):
copy2(source, prj_file)
KiConf.fix_page_layout(prj_file)
else:
# Create a dummy project file to avoid warnings
f = open(prj_file, 'wt')
f.close()
class Any_SCH_PrintOptions(VariantOptions):
def __init__(self):
with document:
self.monochrome = False
""" Generate a monochromatic PDF """
self.frame = True
""" Include the frame and title block """
super().__init__()
self.add_to_doc('variant', "Not fitted components are crossed")
self._expand_id = 'schematic'
def get_targets(self, out_dir):
if self.output:
return [self._parent.expand_filename(out_dir, self.output)]
return [self._parent.expand_filename(out_dir, '%f.%x')]
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
sch_dir = mkdtemp(prefix='tmp-kibot-'+self._expand_ext+'_sch_print-')
copy_project(sch_dir)
fname = GS.sch.save_variant(sch_dir)
sch_file = os.path.join(sch_dir, fname)
else:
sch_dir = None
sch_file = GS.sch_file
cmd = [CMD_EESCHEMA_DO, 'export', '--all_pages', '--file_format', self._expand_ext]
if self.monochrome:
cmd.append('--monochrome')
if not self.frame:
cmd.append('--no_frame')
cmd.extend([sch_file, output_dir])
cmd, video_remove = add_extra_options(cmd)
ret = exec_with_retry(cmd)
if ret:
logger.error(CMD_EESCHEMA_DO+' returned %d', ret)
exit(self._exit_error)
if self.output:
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(output_dir, 'export_eeschema_screencast.ogv')
if os.path.isfile(video_name):
os.remove(video_name)

View File

@ -1,10 +1,12 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020-2021 Salvador E. Tropea
# Copyright (c) 2020-2021 Instituto Nacional de Tecnología Industrial
# Copyright (c) 2020-2022 Salvador E. Tropea
# Copyright (c) 2020-2022 Instituto Nacional de Tecnología Industrial
# License: GPL-3.0
# Project: KiBot (formerly KiPlot)
import os
from copy import deepcopy
from tempfile import NamedTemporaryFile, mkdtemp
from glob import glob
from .gs import GS
from .kiplot import load_sch, get_board_comps_data
from .misc import Rect, W_WRONGPASTE
@ -20,6 +22,7 @@ else:
from .registrable import RegOutput
from .optionable import Optionable, BaseOptions
from .fil_base import BaseFilter, apply_fitted_filter, reset_filters
from .kicad.config import KiConf
from .macros import macros, document # noqa: F401
from .error import KiPlotConfigurationError
from . import log
@ -386,6 +389,38 @@ class VariantOptions(BaseOptions):
if self.old_title is not None:
GS.board.GetTitleBlock().SetTitle(self.old_title)
def save_tmp_board(self, dir=None):
""" Save the PCB to a temporal file.
Advantage: all relative paths inside the file remains valid
Disadvantage: the name of the file gets altered """
if dir is None:
dir = GS.pcb_dir
with NamedTemporaryFile(mode='w', suffix='.kicad_pcb', delete=False, dir=dir) as f:
fname = f.name
logger.debug('Storing modified PCB to `{}`'.format(fname))
GS.board.Save(fname)
GS.copy_project(fname)
return fname
def save_tmp_dir_board(self, id):
""" Save the PCB to a temporal dir.
Disadvantage: all relative paths inside the file becomes useless
Aadvantage: the name of the file remains the same """
pcb_dir = mkdtemp(prefix='tmp-kibot-'+id+'-')
fname = os.path.join(pcb_dir, GS.pcb_basename+'.kicad_pcb')
logger.debug('Storing modified PCB to `{}`'.format(fname))
GS.board.Save(fname)
pro_name = GS.copy_project(fname)
KiConf.fix_page_layout(pro_name)
return fname, pcb_dir
def remove_tmp_board(self, board_name):
# Remove the temporal PCB
if board_name != GS.pcb_file:
# KiCad likes to create project files ...
for f in glob(board_name.replace('.kicad_pcb', '.*')):
os.remove(f)
def run(self, output_dir):
""" Makes the list of components available """
if not self.dnf_filter and not self.variant:

View File

@ -1,13 +1,12 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020-2021 Salvador E. Tropea
# Copyright (c) 2020-2021 Instituto Nacional de Tecnología Industrial
# Copyright (c) 2020-2022 Salvador E. Tropea
# Copyright (c) 2020-2022 Instituto Nacional de Tecnología Industrial
# License: GPL-3.0
# Project: KiBot (formerly KiPlot)
import os
import re
import requests
import tempfile
from tempfile import NamedTemporaryFile
from .error import KiPlotConfigurationError
from .misc import W_MISS3D, W_FAILDL
from .gs import (GS)
@ -181,15 +180,6 @@ class Base3DOptions(VariantOptions):
models.add(full_name)
return list(models)
def save_board(self, dir):
""" Save the PCB to a temporal file """
with NamedTemporaryFile(mode='w', suffix='.kicad_pcb', delete=False, dir=dir) as f:
fname = f.name
logger.debug('Storing modified PCB to `{}`'.format(fname))
GS.board.Save(fname)
GS.copy_project(fname)
return fname
def apply_variant_aspect(self, enable=False):
""" Disable/Enable the 3D models that aren't for this variant.
This mechanism uses the MTEXT attributes. """
@ -233,14 +223,14 @@ class Base3DOptions(VariantOptions):
# Push it back to the module
models.push_back(m3d)
def filter_components(self, dir):
def filter_components(self):
self.undo_3d_models_rep = {}
if not self._comps:
# No variant/filter to apply
if self.download_models():
# Some missing components found and we downloaded them
# Save the fixed board
ret = self.save_board(dir)
ret = self.save_tmp_board()
# Undo the changes
self.undo_3d_models_rename()
return ret
@ -269,7 +259,7 @@ class Base3DOptions(VariantOptions):
# We will change the 3D model
self.replace_models(models, new_model, c)
self.download_models()
fname = self.save_board(dir)
fname = self.save_tmp_board()
self.undo_3d_models_rename()
# Undo the removing
for m in GS.get_modules():

View File

@ -3,91 +3,27 @@
# Copyright (c) 2020-2022 Instituto Nacional de Tecnología Industrial
# License: GPL-3.0
# Project: KiBot (formerly KiPlot)
import os
from tempfile import mkdtemp
from shutil import rmtree, copy2
from .gs import (GS)
from .kiplot import check_eeschema_do, exec_with_retry, add_extra_options
from .misc import (CMD_EESCHEMA_DO, PDF_SCH_PRINT)
from .out_base import VariantOptions
from .gs import GS
from .out_any_sch_print import Any_SCH_PrintOptions
from .misc import PDF_SCH_PRINT
from .macros import macros, document, output_class # noqa: F401
from . import log
logger = log.get_logger()
def copy_project(sch_dir):
""" Copy the project file to the temporal dir """
ext = GS.pro_ext
source = GS.pro_file
prj_file = os.path.join(sch_dir, GS.sch_basename+ext)
if source is not None and os.path.isfile(source):
copy2(source, prj_file)
else:
# Create a dummy project file to avoid warnings
f = open(prj_file, 'wt')
f.close()
class PDF_Sch_PrintOptions(VariantOptions):
class PDF_SCH_PrintOptions(Any_SCH_PrintOptions):
def __init__(self):
with document:
self.output = GS.def_global_output
""" Filename for the output PDF (%i=schematic %x=pdf) """
self.monochrome = False
""" Generate a monochromatic PDF """
self.frame = True
""" Include the frame and title block """
""" 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, out_dir):
if self.output:
return [self._parent.expand_filename(out_dir, self.output)]
return [self._parent.expand_filename(out_dir, '%f.%x')]
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
sch_dir = mkdtemp(prefix='tmp-kibot-pdf_sch_print-')
copy_project(sch_dir)
fname = GS.sch.save_variant(sch_dir)
sch_file = os.path.join(sch_dir, fname)
else:
sch_dir = None
sch_file = GS.sch_file
cmd = [CMD_EESCHEMA_DO, 'export', '--all_pages', '--file_format', 'pdf']
if self.monochrome:
cmd.append('--monochrome')
if not self.frame:
cmd.append('--no_frame')
cmd.extend([sch_file, output_dir])
cmd, video_remove = add_extra_options(cmd)
ret = exec_with_retry(cmd)
if ret:
logger.error(CMD_EESCHEMA_DO+' returned %d', ret)
exit(PDF_SCH_PRINT)
if self.output:
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(output_dir, 'export_eeschema_screencast.ogv')
if os.path.isfile(video_name):
os.remove(video_name)
self._exit_error = PDF_SCH_PRINT
@output_class
class PDF_Sch_Print(BaseOutput): # noqa: F821
class PDF_SCH_Print(BaseOutput): # noqa: F821
""" PDF Schematic Print (Portable Document Format)
Exports the PCB to the most common exchange format. Suitable for printing.
This is the main format to document your schematic.
@ -95,6 +31,6 @@ class PDF_Sch_Print(BaseOutput): # noqa: F821
def __init__(self):
super().__init__()
with document:
self.options = PDF_Sch_PrintOptions
self.options = PDF_SCH_PrintOptions
""" [dict] Options for the `pdf_sch_print` output """
self._sch_related = True

View File

@ -5,7 +5,6 @@
# Project: KiBot (formerly KiPlot)
# KiCad 6 bug: https://gitlab.com/kicad/code/kicad/-/issues/9890
import os
from glob import glob
from shutil import rmtree
from .misc import (CMD_PCBNEW_3D, URL_PCBNEW_3D, RENDER_3D_ERR, PCB_MAT_COLORS, PCB_FINISH_COLORS, SOLDER_COLORS, SILK_COLORS,
KICAD_VERSION_6_0_2, MISSING_TOOL)
@ -170,16 +169,13 @@ class Render3DOptions(Base3DOptions):
if self.view != 'z':
cmd.extend(['--view', self.view])
# The board
board_name = self.filter_components(GS.pcb_dir)
board_name = self.filter_components()
cmd.extend([board_name, os.path.dirname(output)])
cmd, video_remove = add_extra_options(cmd)
# Execute it
ret = exec_with_retry(cmd)
# Remove the temporal PCB
if board_name != GS.pcb_file:
# KiCad likes to create project files ...
for f in glob(board_name.replace('.kicad_pcb', '.*')):
os.remove(f)
self.remove_tmp_board(board_name)
# Remove the downloaded 3D models
if self._tmp_dir:
rmtree(self._tmp_dir)

View File

@ -1,12 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020-2021 Salvador E. Tropea
# Copyright (c) 2020-2021 Instituto Nacional de Tecnología Industrial
# Copyright (c) 2020-2022 Salvador E. Tropea
# Copyright (c) 2020-2022 Instituto Nacional de Tecnología Industrial
# License: GPL-3.0
# Project: KiBot (formerly KiPlot)
# KiCad 6 bug: https://gitlab.com/kicad/code/kicad/-/issues/10075
import re
import os
from glob import glob
from subprocess import (check_output, STDOUT, CalledProcessError)
from shutil import rmtree
from .error import KiPlotConfigurationError
@ -78,7 +76,7 @@ class STEPOptions(Base3DOptions):
else:
cmd.extend(['--user-origin', "{}{}".format(self.origin.replace(',', 'x'), units)])
# The board
board_name = self.filter_components(GS.pcb_dir)
board_name = self.filter_components()
cmd.append(board_name)
# Execute and inform is successful
logger.debug('Executing: '+str(cmd))
@ -90,11 +88,7 @@ class STEPOptions(Base3DOptions):
logger.debug('Output from command: '+e.output.decode())
exit(KICAD2STEP_ERR)
finally:
# Remove the temporal PCB
if board_name != GS.pcb_file:
# KiCad likes to create project files ...
for f in glob(board_name.replace('.kicad_pcb', '.*')):
os.remove(f)
self.remove_tmp_board(board_name)
# Remove the downloaded 3D models
if self._tmp_dir:
rmtree(self._tmp_dir)

View File

@ -1,77 +1,36 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020-2021 Salvador E. Tropea
# Copyright (c) 2020-2021 Instituto Nacional de Tecnología Industrial
# Copyright (c) 2020-2022 Salvador E. Tropea
# Copyright (c) 2020-2022 Instituto Nacional de Tecnología Industrial
# Copyright (c) 2020 @nerdyscout
# License: GPL-3.0
# Project: KiBot (formerly KiPlot)
import os
from tempfile import mkdtemp
from shutil import rmtree
from .gs import (GS)
from .kiplot import check_eeschema_do, exec_with_retry, add_extra_options
from .misc import (CMD_EESCHEMA_DO, SVG_SCH_PRINT)
from .out_base import VariantOptions
from .gs import GS
from .out_any_sch_print import Any_SCH_PrintOptions
from .misc import SVG_SCH_PRINT
from .macros import macros, document, output_class # noqa: F401
from . import log
logger = log.get_logger()
class SVG_Sch_PrintOptions(VariantOptions):
class SVG_SCH_PrintOptions(Any_SCH_PrintOptions):
def __init__(self):
with document:
self.output = GS.def_global_output
""" Filename for the output SVG (%i=schematic %x=svg) """
""" 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, out_dir):
if self.output:
return [self._parent.expand_filename(out_dir, self.output)]
return [self._parent.expand_filename(out_dir, '%f.%x')]
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
sch_dir = mkdtemp(prefix='tmp-kibot-svg_sch_print-')
fname = GS.sch.save_variant(sch_dir)
sch_file = os.path.join(sch_dir, fname)
else:
sch_dir = None
sch_file = GS.sch_file
cmd = [CMD_EESCHEMA_DO, 'export', '--all_pages', '--file_format', 'svg', sch_file, output_dir]
cmd, video_remove = add_extra_options(cmd)
ret = exec_with_retry(cmd)
if ret:
logger.error(CMD_EESCHEMA_DO+' returned %d', ret)
exit(SVG_SCH_PRINT)
if self.output:
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(output_dir, 'export_eeschema_screencast.ogv')
if os.path.isfile(video_name):
os.remove(video_name)
self._exit_error = SVG_SCH_PRINT
@output_class
class SVG_Sch_Print(BaseOutput): # noqa: F821
class SVG_SCH_Print(BaseOutput): # noqa: F821
""" SVG Schematic Print
Exports the PCB. Suitable for printing.
This is a format to document your schematic. """
def __init__(self):
super().__init__()
with document:
self.options = SVG_Sch_PrintOptions
self.options = SVG_SCH_PrintOptions
""" [dict] Options for the `svg_sch_print` output """
self._sch_related = True

View File

@ -8,6 +8,7 @@ BoardNm=
[pcbnew]
version=1
LastNetListRead=
PageLayoutDescrFile=${KIPRJMOD}/../../data/rotulo_k5.kicad_wks
UseCmpFile=1
PadDrill=0.600000000000
PadDrillOvalY=0.600000000000
@ -31,3 +32,13 @@ NetIExt=net
version=1
LibDir=
[eeschema/libraries]
[schematic_editor]
version=1
PageLayoutDescrFile=${KIPRJMOD}/../../data/rotulo_sch_k5.kicad_wks
PlotDirectoryName=
SubpartIdSeparator=0
SubpartFirstId=65
NetFmtName=
SpiceAjustPassiveValues=0
LabSize=50
ERC_TestSimilarLabels=1

View File

@ -0,0 +1 @@
kibom-variant_3.kicad_pcb

View File

@ -0,0 +1 @@
kibom-variant_3.pro

View File

@ -0,0 +1 @@
kibom-variant_3.sch

View File

@ -0,0 +1 @@
test_v5.kicad_pcb

View File

@ -0,0 +1 @@
test_v5.sch

View File

@ -229,7 +229,7 @@
(property "Config" "T1" (id 4) (at 63.5 43.18 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "default:_3D_model" "${KICAD6_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_2010_5025Metric.wrl" (id 4) (at 63.5 43.18 0)
(property "default:_3D_model" "${KICAD6_3DMODEL_DIR}/Resistor_SMD.3dshapes/R_2010_5025Metric.wrl" (id 5) (at 63.5 43.18 0)
(effects (font (size 1.27 1.27)) hide)
)
(pin "1" (uuid c70d9ef3-bfeb-47e0-a1e1-9aeba3da7864))

View File

@ -121,6 +121,211 @@
"cvpcb": {
"equivalence_files": []
},
"erc": {
"erc_exclusions": [],
"meta": {
"version": 0
},
"pin_map": [
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
1,
0,
1,
2
],
[
0,
1,
0,
0,
0,
0,
1,
1,
2,
1,
1,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
2
],
[
1,
1,
1,
1,
1,
0,
1,
1,
1,
1,
1,
2
],
[
0,
0,
0,
1,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
1,
2,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
0,
2,
1,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2
]
],
"rule_severities": {
"bus_definition_conflict": "error",
"bus_entry_needed": "error",
"bus_label_syntax": "error",
"bus_to_bus_conflict": "error",
"bus_to_net_conflict": "error",
"different_unit_footprint": "error",
"different_unit_net": "error",
"duplicate_reference": "error",
"duplicate_sheet_names": "error",
"extra_units": "error",
"global_label_dangling": "warning",
"hier_label_mismatch": "error",
"label_dangling": "error",
"lib_symbol_issues": "warning",
"multiple_net_names": "warning",
"net_not_bus_member": "warning",
"no_connect_connected": "warning",
"no_connect_dangling": "warning",
"pin_not_connected": "error",
"pin_not_driven": "error",
"pin_to_pin": "warning",
"power_pin_not_driven": "error",
"similar_labels": "warning",
"unannotated": "error",
"unit_value_mismatch": "error",
"unresolved_variable": "error",
"wire_dangling": "error"
}
},
"libraries": {
"pinned_footprint_libs": [],
"pinned_symbol_libs": []
@ -163,14 +368,53 @@
"step": "",
"vrml": ""
},
"page_layout_descr_file": ""
"page_layout_descr_file": "${KIPRJMOD}/../../data/rotulo_k6.kicad_wks"
},
"schematic": {
"annotate_start_num": 0,
"drawing": {
"default_line_thickness": 6.0,
"default_text_size": 50.0,
"field_names": [],
"intersheets_ref_own_page": false,
"intersheets_ref_prefix": "",
"intersheets_ref_short": false,
"intersheets_ref_show": false,
"intersheets_ref_suffix": "",
"junction_size_choice": 3,
"label_size_ratio": 0.375,
"pin_symbol_size": 25.0,
"text_offset_ratio": 0.15
},
"legacy_lib_dir": "",
"legacy_lib_list": []
"legacy_lib_list": [],
"meta": {
"version": 1
},
"net_format_name": "",
"ngspice": {
"fix_include_paths": true,
"fix_passive_vals": false,
"meta": {
"version": 0
},
"model_mode": 0,
"workbook_filename": ""
},
"page_layout_descr_file": "${KIPRJMOD}/../../data/rotulo_sch_k6.kicad_wks",
"plot_directory": "",
"spice_adjust_passive_values": false,
"spice_external_command": "spice \"%I\"",
"subpart_first_id": 65,
"subpart_id_separator": 0
},
"sheets": [],
"sheets": [
[
"e6521bef-4109-48f7-8b88-4121b0468927",
""
]
],
"text_variables": {
"text": "Test"
}
}
}

View File

@ -0,0 +1 @@
test_v5.kicad_pcb

View File

@ -0,0 +1 @@
kibom-variant_3_txt.kicad_pro

View File

@ -0,0 +1 @@
test_v5.kicad_sch

View File

@ -0,0 +1,32 @@
(page_layout
(setup (textsize 1.5 1.5)(linewidth 0.15)(textlinewidth 0.15)
(left_margin 10)(right_margin 10)(top_margin 10)(bottom_margin 10))
(rect (name rect1:Rect) (start 110 34) (end 2 2))
(rect (name rect2:Rect) (start 0 0 ltcorner) (end 0 0) (repeat 2) (incrx 2) (incry 2))
(line (name segm1:Line) (start 50 2 ltcorner) (end 50 0 ltcorner) (repeat 30) (incrx 50))
(tbtext 1 (name text1:Text) (pos 25 1 ltcorner) (font (size 1.3 1.3)) (repeat 100) (incrx 50))
(line (name segm2:Line) (start 50 2 lbcorner) (end 50 0 lbcorner) (repeat 30) (incrx 50))
(tbtext 1 (name text2:Text) (pos 25 1 lbcorner) (font (size 1.3 1.3)) (repeat 100) (incrx 50))
(line (name segm3:Line) (start 0 50 ltcorner) (end 2 50 ltcorner) (repeat 30) (incry 50))
(tbtext A (name text3:Text) (pos 1 25 ltcorner) (font (size 1.3 1.3)) (justify center) (repeat 100) (incry 50))
(line (name segm4:Line) (start 0 50 rtcorner) (end 2 50 rtcorner) (repeat 30) (incry 50))
(tbtext A (name text4:Text) (pos 1 25 rtcorner) (font (size 1.3 1.3)) (justify center) (repeat 100) (incry 50))
(tbtext "Date: %D" (name text5:Text) (pos 87 6.9))
(line (name segm5:Line) (start 110 5.5) (end 2 5.5))
(line (name segm6:Line) (start 110 8.5) (end 2 8.5))
(tbtext "Rev: %R" (name text6:Text) (pos 87.00020000000001 3.900199999999984) (font bold))
(tbtext "Size: %Z" (name text7:Text) (pos 109 6.9))
(tbtext "Id: %S/%N" (name text8:Text) (pos 109.0002 4.100199999999973))
(line (name segm7:Line) (start 110 12.5) (end 2 12.5))
(tbtext "Title: %T" (name text9:Text) (pos 109 10.7) (font (size 2 2) bold italic))
(tbtext "File: %F" (name text10:Text) (pos 109 14.3))
(line (name segm8:Line) (start 110 18.5) (end 2 18.5))
(tbtext "Sheet: %P" (name text11:Text) (pos 109 17))
(tbtext %Y (name text12:Text) (pos 109 20) (font bold))
(tbtext %C0 (name text13:Text) (pos 109 23))
(tbtext %C1 (name text14:Text) (pos 109 26))
(tbtext %C2 (name text15:Text) (pos 109 29))
(tbtext %C3 (name text16:Text) (pos 109 32))
(line (name segm9:Line) (start 90 8.5) (end 90 5.5))
(line (name segm10:Line) (start 90.00020000000001 8.500199999999978) (end 90.00020000000001 2.000199999999978))
)

View File

@ -0,0 +1,40 @@
(kicad_wks (version 20210606) (generator pl_editor)
(setup (textsize 1.5 1.5)(linewidth 0.15)(textlinewidth 0.15)
(left_margin 10)(right_margin 10)(top_margin 10)(bottom_margin 10))
(rect (name "") (start 110 34) (end 2 2) (comment "rect around the title block")
)
(rect (name "") (start 0 0 ltcorner) (end 0 0) (repeat 2) (incrx 2) (incry 2))
(line (name "") (start 50 2 ltcorner) (end 50 0 ltcorner) (repeat 30) (incrx 50))
(tbtext "1" (name "") (pos 25 1 ltcorner) (font (size 1.3 1.3)) (repeat 100) (incrx 50))
(line (name "") (start 50 2 lbcorner) (end 50 0 lbcorner) (repeat 30) (incrx 50))
(tbtext "1" (name "") (pos 25 1 lbcorner) (font (size 1.3 1.3)) (repeat 100) (incrx 50))
(line (name "") (start 0 50 ltcorner) (end 2 50 ltcorner) (repeat 30) (incry 50))
(tbtext "A" (name "") (pos 1 25 ltcorner) (font (size 1.3 1.3)) (justify center) (repeat 100) (incry 50))
(line (name "") (start 0 50 rtcorner) (end 2 50 rtcorner) (repeat 30) (incry 50))
(tbtext "A" (name "") (pos 1 25 rtcorner) (font (size 1.3 1.3)) (justify center) (repeat 100) (incry 50))
(tbtext "Date: ${ISSUE_DATE}" (name "") (pos 87 6.9))
(line (name "") (start 110 5.5) (end 2 5.5))
(line (name "") (start 110 8.5) (end 2 8.5))
(tbtext "Rev: ${REVISION}" (name "") (pos 53 6.9002) (font bold))
(tbtext "Size: ${PAPER}" (name "") (pos 109 6.9) (comment "Paper format name")
)
(tbtext "Id: ${#}/${##}" (name "") (pos 109 3.6002) (comment "Sheet id")
)
(line (name "") (start 110 12.5) (end 2 12.5))
(tbtext "Title: ${TITLE}" (name "") (pos 109 10.7) (font (size 2 2) bold italic))
(tbtext "File: ${FILENAME}" (name "") (pos 109 14.3))
(line (name "") (start 110 18.5) (end 2 18.5))
(tbtext "Sheet: ${SHEETNAME}" (name "") (pos 109 17))
(tbtext "${COMPANY}" (name "") (pos 109 20) (font bold) (comment "Company name")
)
(tbtext "${COMMENT1}" (name "") (pos 109 23) (comment "Comment 0")
)
(tbtext "${COMMENT2}" (name "") (pos 109 26) (comment "Comment 1")
)
(tbtext "${COMMENT3}" (name "") (pos 109 29) (comment "Comment 2")
)
(tbtext "${COMMENT4}" (name "") (pos 109 32) (comment "Comment 3")
)
(line (name "") (start 90 8.5) (end 90 5.5))
(line (name "") (start 53 8.5002) (end 53 2.0002))
)

View File

@ -0,0 +1,32 @@
(page_layout
(setup (textsize 1.5 1.5)(linewidth 0.15)(textlinewidth 0.15)
(left_margin 10)(right_margin 10)(top_margin 10)(bottom_margin 10))
(rect (name rect1:Rect) (start 110 34) (end 2 2))
(rect (name rect2:Rect) (start 0 0 ltcorner) (end 0 0) (repeat 2) (incrx 2) (incry 2))
(line (name segm1:Line) (start 50 2 ltcorner) (end 50 0 ltcorner) (repeat 30) (incrx 50))
(tbtext 1 (name text1:Text) (pos 25 1 ltcorner) (font (size 1.3 1.3)) (repeat 100) (incrx 50))
(line (name segm2:Line) (start 50 2 lbcorner) (end 50 0 lbcorner) (repeat 30) (incrx 50))
(tbtext 1 (name text2:Text) (pos 25 1 lbcorner) (font (size 1.3 1.3)) (repeat 100) (incrx 50))
(line (name segm3:Line) (start 0 50 ltcorner) (end 2 50 ltcorner) (repeat 30) (incry 50))
(tbtext A (name text3:Text) (pos 1 25 ltcorner) (font (size 1.3 1.3)) (justify center) (repeat 100) (incry 50))
(line (name segm4:Line) (start 0 50 rtcorner) (end 2 50 rtcorner) (repeat 30) (incry 50))
(tbtext A (name text4:Text) (pos 1 25 rtcorner) (font (size 1.3 1.3)) (justify center) (repeat 100) (incry 50))
(tbtext "Date: %D" (name text5:Text) (pos 87 6.9))
(line (name segm5:Line) (start 110 5.5) (end 2 5.5))
(line (name segm6:Line) (start 110 8.5) (end 2 8.5))
(tbtext "Rev: %R" (name text6:Text) (pos 87.00020000000001 3.900199999999984) (font bold))
(tbtext "Size: %Z" (name text7:Text) (pos 109 6.9))
(tbtext "Id: %S/%N" (name text8:Text) (pos 109.0002 4.100199999999973))
(line (name segm7:Line) (start 110 12.5) (end 2 12.5))
(tbtext "Title: %T" (name text9:Text) (pos 109 10.7) (font (size 2 2) bold italic))
(tbtext "Schematic: %F" (name text10:Text) (pos 109 14.3))
(line (name segm8:Line) (start 110 18.5) (end 2 18.5))
(tbtext "Sheet: %P" (name text11:Text) (pos 109 17))
(tbtext %Y (name text12:Text) (pos 109 20) (font bold))
(tbtext %C0 (name text13:Text) (pos 109 23))
(tbtext %C1 (name text14:Text) (pos 109 26))
(tbtext %C2 (name text15:Text) (pos 109 29))
(tbtext %C3 (name text16:Text) (pos 109 32))
(line (name segm9:Line) (start 90 8.5) (end 90 5.5))
(line (name segm10:Line) (start 90.00020000000001 8.500199999999978) (end 90.00020000000001 2.000199999999978))
)

View File

@ -0,0 +1,40 @@
(kicad_wks (version 20210606) (generator pl_editor)
(setup (textsize 1.5 1.5)(linewidth 0.15)(textlinewidth 0.15)
(left_margin 10)(right_margin 10)(top_margin 10)(bottom_margin 10))
(rect (name "") (start 110 34) (end 2 2) (comment "rect around the title block")
)
(rect (name "") (start 0 0 ltcorner) (end 0 0) (repeat 2) (incrx 2) (incry 2))
(line (name "") (start 50 2 ltcorner) (end 50 0 ltcorner) (repeat 30) (incrx 50))
(tbtext "1" (name "") (pos 25 1 ltcorner) (font (size 1.3 1.3)) (repeat 100) (incrx 50))
(line (name "") (start 50 2 lbcorner) (end 50 0 lbcorner) (repeat 30) (incrx 50))
(tbtext "1" (name "") (pos 25 1 lbcorner) (font (size 1.3 1.3)) (repeat 100) (incrx 50))
(line (name "") (start 0 50 ltcorner) (end 2 50 ltcorner) (repeat 30) (incry 50))
(tbtext "A" (name "") (pos 1 25 ltcorner) (font (size 1.3 1.3)) (justify center) (repeat 100) (incry 50))
(line (name "") (start 0 50 rtcorner) (end 2 50 rtcorner) (repeat 30) (incry 50))
(tbtext "A" (name "") (pos 1 25 rtcorner) (font (size 1.3 1.3)) (justify center) (repeat 100) (incry 50))
(tbtext "Date: ${ISSUE_DATE}" (name "") (pos 87 6.9))
(line (name "") (start 110 5.5) (end 2 5.5))
(line (name "") (start 110 8.5) (end 2 8.5))
(tbtext "Rev: ${REVISION}" (name "") (pos 53 6.9002) (font bold))
(tbtext "Size: ${PAPER}" (name "") (pos 109 6.9) (comment "Paper format name")
)
(tbtext "Id: ${#}/${##}" (name "") (pos 109 3.6002) (comment "Sheet id")
)
(line (name "") (start 110 12.5) (end 2 12.5))
(tbtext "Title: ${TITLE}" (name "") (pos 109 10.7) (font (size 2 2) bold italic))
(tbtext "Schematic: ${FILENAME}" (name "") (pos 109 14.3))
(line (name "") (start 110 18.5) (end 2 18.5))
(tbtext "Sheet: ${SHEETNAME}" (name "") (pos 109 17))
(tbtext "${COMPANY}" (name "") (pos 109 20) (font bold) (comment "Company name")
)
(tbtext "${COMMENT1}" (name "") (pos 109 23) (comment "Comment 0")
)
(tbtext "${COMMENT2}" (name "") (pos 109 26) (comment "Comment 1")
)
(tbtext "${COMMENT3}" (name "") (pos 109 29) (comment "Comment 2")
)
(tbtext "${COMMENT4}" (name "") (pos 109 32) (comment "Comment 3")
)
(line (name "") (start 90 8.5) (end 90 5.5))
(line (name "") (start 53 8.5002) (end 53 2.0002))
)

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1 @@
../5_1_6/kibom-variant_3_txt-F_Fab.pdf

View File

@ -0,0 +1 @@
../5_1_6/test_v5_wks-schematic_(no_L).pdf

Binary file not shown.

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 180 KiB

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

View File

@ -55,14 +55,14 @@ def test_print_pcb_refill_2(test_dir):
def test_print_variant_1(test_dir):
prj = 'kibom-variant_3'
prj = 'kibom-variant_3_txt'
ctx = context.TestContext(test_dir, 'print_variant_1', prj, 'print_pcb_variant_1', '')
ctx.run()
# Check all outputs are there
fname = prj+'-F_Fab.pdf'
ctx.search_err(r'KiCad project file not found', True)
ctx.expect_out_file(fname)
ctx.compare_pdf(fname)
ctx.compare_pdf(fname, height='100%')
ctx.clean_up(keep_project=True)

View File

@ -58,7 +58,7 @@ def test_print_sch_svg_ok(test_dir):
def test_print_sch_svg_fail(test_dir):
prj = '3Rs'
prj = 'print_err'
ctx = context.TestContext(test_dir, 'PrSCHFail_SVG', prj, 'print_sch_svg', PDF_DIR)
ctx.run(SVG_SCH_PRINT, no_board_file=True, extra=['-e', os.path.join(ctx.get_board_dir(),
'print_err'+context.KICAD_SCH_EXT)])
@ -105,14 +105,14 @@ def test_sch_variant_ni_2(test_dir):
def test_print_sch_variant_ni_1(test_dir):
""" Using a variant """
prj = 'test_v5' # Is the most complete, contains every KiCad object I know
prj = 'test_v5_wks' # Is the most complete, contains every KiCad object I know
ctx = context.TestContextSCH(test_dir, 'test_print_sch_variant_ni_1', prj, 'print_pdf_no_inductors_1', PDF_DIR)
ctx.run()
r_name = 'test_v5-schematic_(no_L).pdf'
r_name = 'test_v5_wks-schematic_(no_L).pdf'
o_name = os.path.join(NI_DIR, r_name)
ctx.expect_out_file(o_name)
ctx.compare_pdf(o_name, r_name)
ctx.clean_up()
ctx.compare_pdf(o_name, r_name, height='100%')
ctx.clean_up(keep_project=True)
def test_print_sch_svg_variant_ni_1(test_dir):

View File

@ -433,7 +433,7 @@ class TestContext(object):
logging.debug(msg+' OK')
# logging.debug(' '+m.group(0))
def compare_image(self, image, reference=None, diff='diff.png', ref_out_dir=False, fuzz='5%', tol=0):
def compare_image(self, image, reference=None, diff='diff.png', ref_out_dir=False, fuzz='5%', tol=0, height='87%'):
""" For images and single page PDFs """
if reference is None:
reference = image
@ -460,7 +460,7 @@ class TestContext(object):
image,
reference,
# Avoid the part where KiCad version is printed
'-crop', '100%x87%+0+0', '+repage',
'-crop', '100%x'+height+'+0+0', '+repage',
'-colorspace', 'RGB',
self.get_out_path(diff)]
logging.debug('Comparing images with: '+usable_cmd(cmd))
@ -476,7 +476,7 @@ class TestContext(object):
os.remove(png_image)
assert ae <= tol
def compare_pdf(self, gen, reference=None, diff='diff-{}.png'):
def compare_pdf(self, gen, reference=None, diff='diff-{}.png', height='87%'):
""" For multi-page PDFs """
if reference is None:
reference = gen
@ -500,7 +500,8 @@ class TestContext(object):
assert len(ref_pages) == len(gen_pages)
# Compare each page
for page in range(len(ref_pages)):
self.compare_image('gen-'+str(page)+'.png', 'ref-'+str(page)+'.png', diff.format(page), ref_out_dir=True)
self.compare_image('gen-'+str(page)+'.png', 'ref-'+str(page)+'.png', diff.format(page), ref_out_dir=True,
height=height)
def compare_txt(self, text, reference=None, diff='diff.txt'):
if reference is None: