Better debug info, fixed errors and no .kicad_pcb dependency
- When a BoM operation fails now we show the output of the child process. (Only enabled when using debug verbosity) - The error levels 1 and 2 were overlapped with internal Python codes. - Now we delay the PCB load until we really need it. Which could be never.
This commit is contained in:
parent
aef19e31c7
commit
61f1ebbab2
|
|
@ -6,6 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- Better debug information when a BoM fails to be generated.
|
||||
### Changed
|
||||
- Allowed operations that doesn't involve a PCB now can run if the PCB file is
|
||||
missing or corrupted.
|
||||
### Fixed
|
||||
- Error codes that overlapped.
|
||||
|
||||
## [0.2.5] - 2020-06-11
|
||||
### Added
|
||||
|
|
|
|||
151
kiplot/kiplot.py
151
kiplot/kiplot.py
|
|
@ -42,6 +42,11 @@ def plot_error(msg):
|
|||
exit(misc.PLOT_ERROR)
|
||||
|
||||
|
||||
def level_debug():
|
||||
""" Determine if we are in debug mode """
|
||||
return logger.getEffectiveLevel() <= logging.DEBUG
|
||||
|
||||
|
||||
def check_version(command, version):
|
||||
cmd = [command, '--version']
|
||||
logger.debug('Running: '+str(cmd))
|
||||
|
|
@ -87,11 +92,6 @@ class Plotter(object):
|
|||
def plot(self, brd_file, target, invert, skip_pre):
|
||||
|
||||
logger.debug("Starting plot of board {}".format(brd_file))
|
||||
|
||||
board = pcbnew.LoadBoard(brd_file)
|
||||
assert board is not None
|
||||
logger.debug("Board loaded")
|
||||
|
||||
self._preflight_checks(brd_file, skip_pre)
|
||||
|
||||
n = len(target)
|
||||
|
|
@ -100,29 +100,29 @@ class Plotter(object):
|
|||
logger.debug('Skipping all outputs')
|
||||
return
|
||||
|
||||
board = None
|
||||
for op in self.cfg.outputs:
|
||||
|
||||
if (n == 0) or ((op.name in target) ^ invert):
|
||||
logger.info('- %s (%s) [%s]' % (op.description, op.name, op.options.type))
|
||||
|
||||
# fresh plot controller
|
||||
pc = pcbnew.PLOT_CONTROLLER(board)
|
||||
|
||||
self._configure_output_dir(pc, op)
|
||||
output_dir = self._get_output_dir(op)
|
||||
if (not self._output_is_schematic(op)) and (board is None):
|
||||
board = self._load_board(brd_file)
|
||||
|
||||
try:
|
||||
if self._output_is_layer(op):
|
||||
self._do_layer_plot(board, pc, op, brd_file)
|
||||
self._do_layer_plot(board, output_dir, op, brd_file)
|
||||
elif self._output_is_drill(op):
|
||||
self._do_drill_plot(board, pc, op)
|
||||
self._do_drill_plot(board, output_dir, op)
|
||||
elif self._output_is_position(op):
|
||||
self._do_position_plot(board, pc, op)
|
||||
self._do_position_plot(board, output_dir, op)
|
||||
elif self._output_is_bom(op):
|
||||
self._do_bom(board, pc, op, brd_file)
|
||||
self._do_bom(output_dir, op, brd_file)
|
||||
elif self._output_is_sch_print(op):
|
||||
self._do_sch_print(board, pc, op, brd_file)
|
||||
self._do_sch_print(output_dir, op, brd_file)
|
||||
elif self._output_is_pcb_print(op):
|
||||
self._do_pcb_print(board, pc, op, brd_file)
|
||||
self._do_pcb_print(board, output_dir, op, brd_file)
|
||||
else: # pragma no cover
|
||||
# We shouldn't get here, means the above if is incomplete
|
||||
plot_error("Don't know how to plot type "+op.options.type)
|
||||
|
|
@ -131,6 +131,17 @@ class Plotter(object):
|
|||
else:
|
||||
logger.debug('Skipping %s output', op.name)
|
||||
|
||||
def _load_board(self, brd_file):
|
||||
try:
|
||||
board = pcbnew.LoadBoard(brd_file)
|
||||
except OSError as e:
|
||||
logger.error('Error loading PCB file. Currupted?')
|
||||
logger.error(e)
|
||||
exit(misc.CORRUPTED_PCB)
|
||||
assert board is not None
|
||||
logger.debug("Board loaded")
|
||||
return board
|
||||
|
||||
def _preflight_checks(self, brd_file, skip_pre):
|
||||
logger.debug("Preflight checks")
|
||||
|
||||
|
|
@ -178,7 +189,7 @@ class Plotter(object):
|
|||
cmd.extend(['-f', filter_file])
|
||||
cmd.extend([sch_file, self.cfg.outdir])
|
||||
# If we are in verbose mode enable debug in the child
|
||||
if logger.getEffectiveLevel() <= logging.DEBUG:
|
||||
if level_debug():
|
||||
cmd.insert(1, '-vv')
|
||||
cmd.insert(1, '-r')
|
||||
logger.info('- Running the ERC')
|
||||
|
|
@ -195,7 +206,7 @@ class Plotter(object):
|
|||
sch_file = check_eeschema_do(brd_file)
|
||||
cmd = [misc.CMD_EESCHEMA_DO, 'bom_xml', sch_file, self.cfg.outdir]
|
||||
# If we are in verbose mode enable debug in the child
|
||||
if logger.getEffectiveLevel() <= logging.DEBUG:
|
||||
if level_debug():
|
||||
cmd.insert(1, '-vv')
|
||||
cmd.insert(1, '-r')
|
||||
logger.info('- Updating BoM in XML format')
|
||||
|
|
@ -212,7 +223,7 @@ class Plotter(object):
|
|||
cmd.extend(['-f', filter_file])
|
||||
cmd.extend([brd_file, self.cfg.outdir])
|
||||
# If we are in verbose mode enable debug in the child
|
||||
if logger.getEffectiveLevel() <= logging.DEBUG:
|
||||
if level_debug():
|
||||
cmd.insert(1, '-vv')
|
||||
cmd.insert(1, '-r')
|
||||
if ignore_unconnected:
|
||||
|
|
@ -230,7 +241,7 @@ class Plotter(object):
|
|||
exit(misc.DRC_ERROR)
|
||||
|
||||
def _output_is_layer(self, output):
|
||||
|
||||
""" All the formats for 'PCB|Plot' """
|
||||
return output.options.type in [
|
||||
PCfg.OutputOptions.GERBER,
|
||||
PCfg.OutputOptions.POSTSCRIPT,
|
||||
|
|
@ -241,7 +252,7 @@ class Plotter(object):
|
|||
]
|
||||
|
||||
def _output_is_drill(self, output):
|
||||
|
||||
""" All the drill formats' """
|
||||
return output.options.type in [
|
||||
PCfg.OutputOptions.EXCELLON,
|
||||
PCfg.OutputOptions.GERB_DRILL,
|
||||
|
|
@ -262,6 +273,10 @@ class Plotter(object):
|
|||
PCfg.OutputOptions.IBOM,
|
||||
]
|
||||
|
||||
def _output_is_schematic(self, output):
|
||||
""" All the outputs involving the SCH and not the PCB """
|
||||
return self._output_is_bom(output) or self._output_is_sch_print(output)
|
||||
|
||||
def _get_layer_plot_format(self, output):
|
||||
"""
|
||||
Gets the Pcbnew plot format for a given KiPlot output type
|
||||
|
|
@ -284,10 +299,12 @@ class Plotter(object):
|
|||
raise ValueError("Don't know how to translate plot type: {}"
|
||||
.format(output.options.type))
|
||||
|
||||
def _do_layer_plot(self, board, plot_ctrl, output, file_name):
|
||||
def _do_layer_plot(self, board, output_dir, output, file_name):
|
||||
|
||||
# fresh plot controller
|
||||
plot_ctrl = pcbnew.PLOT_CONTROLLER(board)
|
||||
# set up plot options for the whole output
|
||||
self._configure_plot_ctrl(plot_ctrl, output)
|
||||
self._configure_plot_ctrl(plot_ctrl, output, output_dir)
|
||||
|
||||
po = plot_ctrl.GetPlotOptions()
|
||||
layer_cnt = board.GetCopperLayerCount()
|
||||
|
|
@ -373,12 +390,10 @@ class Plotter(object):
|
|||
|
||||
return drill_writer
|
||||
|
||||
def _do_drill_plot(self, board, plot_ctrl, output):
|
||||
def _do_drill_plot(self, board, output_dir, output):
|
||||
|
||||
to = output.options.type_options
|
||||
|
||||
outdir = plot_ctrl.GetPlotOptions().GetOutputDirectory()
|
||||
|
||||
# dialog_gendrill.cpp:357
|
||||
if to.use_aux_axis_as_origin:
|
||||
offset = board.GetAuxOrigin()
|
||||
|
|
@ -399,37 +414,36 @@ class Plotter(object):
|
|||
gen_report = to.generate_report
|
||||
|
||||
if gen_drill:
|
||||
logger.debug("Generating drill files in "+outdir)
|
||||
logger.debug("Generating drill files in "+output_dir)
|
||||
|
||||
if gen_map:
|
||||
drill_writer.SetMapFileFormat(to.map_options.type)
|
||||
logger.debug("Generating drill map type {} in {}"
|
||||
.format(to.map_options.type, outdir))
|
||||
.format(to.map_options.type, output_dir))
|
||||
|
||||
drill_writer.CreateDrillandMapFilesSet(outdir, gen_drill, gen_map)
|
||||
drill_writer.CreateDrillandMapFilesSet(output_dir, gen_drill, gen_map)
|
||||
|
||||
if gen_report:
|
||||
drill_report_file = os.path.join(outdir,
|
||||
drill_report_file = os.path.join(output_dir,
|
||||
to.report_options.filename)
|
||||
logger.debug("Generating drill report: "+drill_report_file)
|
||||
|
||||
drill_writer.GenDrillReportFile(drill_report_file)
|
||||
|
||||
def _do_position_plot_ascii(self, board, plot_ctrl, output, columns,
|
||||
def _do_position_plot_ascii(self, board, output_dir, output, columns,
|
||||
modulesStr, maxSizes):
|
||||
to = output.options.type_options
|
||||
outdir = plot_ctrl.GetPlotOptions().GetOutputDirectory()
|
||||
name = os.path.splitext(os.path.basename(board.GetFileName()))[0]
|
||||
|
||||
topf = None
|
||||
botf = None
|
||||
bothf = None
|
||||
if to.separate_files_for_front_and_back:
|
||||
topf = open(os.path.join(outdir, "{}-top.pos".format(name)), 'w')
|
||||
botf = open(os.path.join(outdir, "{}-bottom.pos".format(name)),
|
||||
topf = open(os.path.join(output_dir, "{}-top.pos".format(name)), 'w')
|
||||
botf = open(os.path.join(output_dir, "{}-bottom.pos".format(name)),
|
||||
'w')
|
||||
else:
|
||||
bothf = open(os.path.join(outdir, "{}-both.pos").format(name), 'w')
|
||||
bothf = open(os.path.join(output_dir, "{}-both.pos").format(name), 'w')
|
||||
|
||||
files = [f for f in [topf, botf, bothf] if f is not None]
|
||||
for f in files:
|
||||
|
|
@ -482,22 +496,21 @@ class Plotter(object):
|
|||
if bothf is not None:
|
||||
bothf.close()
|
||||
|
||||
def _do_position_plot_csv(self, board, plot_ctrl, output, columns,
|
||||
def _do_position_plot_csv(self, board, output_dir, output, columns,
|
||||
modulesStr):
|
||||
to = output.options.type_options
|
||||
outdir = plot_ctrl.GetPlotOptions().GetOutputDirectory()
|
||||
name = os.path.splitext(os.path.basename(board.GetFileName()))[0]
|
||||
|
||||
topf = None
|
||||
botf = None
|
||||
bothf = None
|
||||
if to.separate_files_for_front_and_back:
|
||||
topf = open(os.path.join(outdir, "{}-top-pos.csv".format(name)),
|
||||
topf = open(os.path.join(output_dir, "{}-top-pos.csv".format(name)),
|
||||
'w')
|
||||
botf = open(os.path.join(outdir, "{}-bottom-pos.csv".format(name)),
|
||||
botf = open(os.path.join(output_dir, "{}-bottom-pos.csv".format(name)),
|
||||
'w')
|
||||
else:
|
||||
bothf = open(os.path.join(outdir, "{}-both-pos.csv").format(name),
|
||||
bothf = open(os.path.join(output_dir, "{}-both-pos.csv").format(name),
|
||||
'w')
|
||||
|
||||
files = [f for f in [topf, botf, bothf] if f is not None]
|
||||
|
|
@ -523,7 +536,7 @@ class Plotter(object):
|
|||
if bothf is not None:
|
||||
bothf.close()
|
||||
|
||||
def _do_position_plot(self, board, plot_ctrl, output):
|
||||
def _do_position_plot(self, board, output_dir, output):
|
||||
to = output.options.type_options
|
||||
|
||||
columns = ["Ref", "Val", "Package", "PosX", "PosY", "Rot", "Side"]
|
||||
|
|
@ -562,18 +575,17 @@ class Plotter(object):
|
|||
|
||||
# Note: the parser already checked the format is ASCII or CSV
|
||||
if to.format.lower() == 'ascii':
|
||||
self._do_position_plot_ascii(board, plot_ctrl, output, columns,
|
||||
self._do_position_plot_ascii(board, output_dir, output, columns,
|
||||
modules, maxlengths)
|
||||
else: # if to.format.lower() == 'csv':
|
||||
self._do_position_plot_csv(board, plot_ctrl, output, columns,
|
||||
self._do_position_plot_csv(board, output_dir, output, columns,
|
||||
modules)
|
||||
|
||||
def _do_sch_print(self, board, plot_ctrl, output, brd_file):
|
||||
def _do_sch_print(self, output_dir, output, brd_file):
|
||||
sch_file = check_eeschema_do(brd_file)
|
||||
outdir = plot_ctrl.GetPlotOptions().GetOutputDirectory()
|
||||
cmd = [misc.CMD_EESCHEMA_DO, 'export', '--all_pages',
|
||||
'--file_format', 'pdf', sch_file, outdir]
|
||||
if logger.getEffectiveLevel() <= logging.DEBUG:
|
||||
'--file_format', 'pdf', sch_file, output_dir]
|
||||
if level_debug():
|
||||
cmd.insert(1, '-vv')
|
||||
cmd.insert(1, '-r')
|
||||
logger.debug('Executing: '+str(cmd))
|
||||
|
|
@ -583,12 +595,12 @@ class Plotter(object):
|
|||
exit(misc.PDF_SCH_PRINT)
|
||||
to = output.options.type_options
|
||||
if to.output:
|
||||
cur = os.path.abspath(os.path.join(outdir, os.path.splitext(os.path.basename(brd_file))[0]) + '.pdf')
|
||||
new = os.path.abspath(os.path.join(outdir, to.output))
|
||||
cur = os.path.abspath(os.path.join(output_dir, os.path.splitext(os.path.basename(brd_file))[0]) + '.pdf')
|
||||
new = os.path.abspath(os.path.join(output_dir, to.output))
|
||||
logger.debug('Moving '+cur+' -> '+new)
|
||||
os.rename(cur, new)
|
||||
|
||||
def _do_pcb_print(self, board, plot_ctrl, output, brd_file):
|
||||
def _do_pcb_print(self, board, output_dir, output, brd_file):
|
||||
check_script(misc.CMD_PCBNEW_PRINT_LAYERS,
|
||||
misc.URL_PCBNEW_PRINT_LAYERS, '1.3.1')
|
||||
to = output.options.type_options
|
||||
|
|
@ -602,11 +614,10 @@ class Plotter(object):
|
|||
raise PlotError(
|
||||
"Inner layer {} is not valid for this board"
|
||||
.format(layer.layer))
|
||||
outdir = plot_ctrl.GetPlotOptions().GetOutputDirectory()
|
||||
cmd = [misc.CMD_PCBNEW_PRINT_LAYERS, 'export',
|
||||
'--output_name', to.output_name,
|
||||
brd_file, outdir]
|
||||
if logger.getEffectiveLevel() <= logging.DEBUG:
|
||||
brd_file, output_dir]
|
||||
if level_debug():
|
||||
cmd.insert(1, '-vv')
|
||||
cmd.insert(1, '-r')
|
||||
# Add the layers
|
||||
|
|
@ -618,37 +629,38 @@ class Plotter(object):
|
|||
logger.error(misc.CMD_PCBNEW_PRINT_LAYERS+' returned %d', ret)
|
||||
exit(misc.PDF_PCB_PRINT)
|
||||
|
||||
def _do_bom(self, board, plot_ctrl, output, brd_file):
|
||||
def _do_bom(self, output_dir, output, brd_file):
|
||||
if output.options.type == 'kibom':
|
||||
self._do_kibom(board, plot_ctrl, output, brd_file)
|
||||
self._do_kibom(output_dir, output, brd_file)
|
||||
else:
|
||||
self._do_ibom(board, plot_ctrl, output, brd_file)
|
||||
self._do_ibom(output_dir, output, brd_file)
|
||||
|
||||
def _do_kibom(self, board, plot_ctrl, output, brd_file):
|
||||
def _do_kibom(self, output_dir, output, brd_file):
|
||||
check_script(misc.CMD_KIBOM, misc.URL_KIBOM)
|
||||
to = output.options.type_options
|
||||
format = to.format.lower()
|
||||
outdir = plot_ctrl.GetPlotOptions().GetOutputDirectory()
|
||||
prj = os.path.splitext(os.path.relpath(brd_file))[0]
|
||||
logger.debug('Doing BoM, format '+format+' prj: '+prj)
|
||||
cmd = [misc.CMD_KIBOM, prj+'.xml',
|
||||
os.path.join(outdir, os.path.basename(prj))+'.'+format]
|
||||
os.path.join(output_dir, os.path.basename(prj))+'.'+format]
|
||||
logger.debug('Running: '+str(cmd))
|
||||
try:
|
||||
check_output(cmd, stderr=STDOUT)
|
||||
cmd_output = check_output(cmd, stderr=STDOUT)
|
||||
except CalledProcessError as e:
|
||||
logger.error('Failed to create BoM, error %d', e.returncode)
|
||||
if e.output:
|
||||
logger.debug('Output from command: '+e.output.decode())
|
||||
exit(misc.BOM_ERROR)
|
||||
for f in glob(os.path.join(outdir, prj)+'*.tmp'):
|
||||
for f in glob(os.path.join(output_dir, prj)+'*.tmp'):
|
||||
os.remove(f)
|
||||
logger.debug('Output from command:\n'+cmd_output.decode())
|
||||
|
||||
def _do_ibom(self, board, plot_ctrl, output, brd_file):
|
||||
def _do_ibom(self, output_dir, output, brd_file):
|
||||
check_script(misc.CMD_IBOM, misc.URL_IBOM)
|
||||
outdir = plot_ctrl.GetPlotOptions().GetOutputDirectory()
|
||||
prj = os.path.splitext(os.path.relpath(brd_file))[0]
|
||||
logger.debug('Doing Interactive BoM, prj: '+prj)
|
||||
cmd = [misc.CMD_IBOM, brd_file,
|
||||
'--dest-dir', outdir,
|
||||
'--dest-dir', output_dir,
|
||||
'--no-browser', ]
|
||||
to = output.options.type_options
|
||||
if to.blacklist:
|
||||
|
|
@ -659,10 +671,13 @@ class Plotter(object):
|
|||
cmd.append(to.name_format)
|
||||
logger.debug('Running: '+str(cmd))
|
||||
try:
|
||||
check_output(cmd, stderr=STDOUT)
|
||||
cmd_output = check_output(cmd, stderr=STDOUT)
|
||||
except CalledProcessError as e:
|
||||
logger.error('Failed to create BoM, error %d', e.returncode)
|
||||
if e.output:
|
||||
logger.debug('Output from command: '+e.output.decode())
|
||||
exit(misc.BOM_ERROR)
|
||||
logger.debug('Output from command:\n'+cmd_output.decode()+'\n')
|
||||
|
||||
def _configure_gerber_opts(self, po, output):
|
||||
|
||||
|
|
@ -704,7 +719,7 @@ class Plotter(object):
|
|||
|
||||
po.SetDXFPlotPolygonMode(dxf_opts.polygon_mode)
|
||||
|
||||
def _configure_output_dir(self, plot_ctrl, output):
|
||||
def _get_output_dir(self, output):
|
||||
|
||||
# outdir is a combination of the config and output
|
||||
outdir = os.path.join(self.cfg.outdir, output.outdir)
|
||||
|
|
@ -713,14 +728,14 @@ class Plotter(object):
|
|||
if not os.path.exists(outdir):
|
||||
os.makedirs(outdir)
|
||||
|
||||
po = plot_ctrl.GetPlotOptions()
|
||||
po.SetOutputDirectory(outdir)
|
||||
return outdir
|
||||
|
||||
def _configure_plot_ctrl(self, plot_ctrl, output):
|
||||
def _configure_plot_ctrl(self, plot_ctrl, output, output_dir):
|
||||
|
||||
logger.debug("Configuring plot controller for output")
|
||||
|
||||
po = plot_ctrl.GetPlotOptions()
|
||||
po.SetOutputDirectory(output_dir)
|
||||
|
||||
opts = output.options.type_options
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
"""
|
||||
|
||||
# Error levels
|
||||
NO_YAML_MODULE = 1
|
||||
NO_PCBNEW_MODULE = 2
|
||||
INTERNAL_ERROR = 1 # Unhandled exceptions
|
||||
WRONG_ARGUMENTS = 2 # This is what argsparse uses
|
||||
USUPPORTED_OPTION = 3
|
||||
MISSING_TOOL = 4
|
||||
DRC_ERROR = 5
|
||||
|
|
@ -16,6 +16,9 @@ BOM_ERROR = 11
|
|||
PDF_SCH_PRINT = 12
|
||||
PDF_PCB_PRINT = 13
|
||||
PLOT_ERROR = 14
|
||||
NO_YAML_MODULE = 15
|
||||
NO_PCBNEW_MODULE = 16
|
||||
CORRUPTED_PCB = 17
|
||||
|
||||
CMD_EESCHEMA_DO = 'eeschema_do'
|
||||
URL_EESCHEMA_DO = 'https://github.com/INTI-CMNB/kicad-automation-scripts'
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
bogus
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
EESchema Schematic File Version 4
|
||||
EELAYER 30 0
|
||||
EELAYER END
|
||||
$Descr A4 11693 8268
|
||||
encoding utf-8
|
||||
Sheet 1 1
|
||||
Title ""
|
||||
Date ""
|
||||
Rev ""
|
||||
Comp ""
|
||||
Comment1 ""
|
||||
Comment2 ""
|
||||
Comment3 ""
|
||||
Comment4 ""
|
||||
$EndDescr
|
||||
$Comp
|
||||
L Device:R R1
|
||||
U 1 1 5EBE8A2E
|
||||
P 3500 2200
|
||||
F 0 "R1" H 3570 2246 50 0000 L CNN
|
||||
F 1 "100" H 3570 2155 50 0000 L CNN
|
||||
F 2 "Resistor_SMD:R_0805_2012Metric" V 3430 2200 50 0001 C CNN
|
||||
F 3 "~" H 3500 2200 50 0001 C CNN
|
||||
1 3500 2200
|
||||
1 0 0 -1
|
||||
$EndComp
|
||||
$Comp
|
||||
L Device:R R2
|
||||
U 1 1 5EBE8E9E
|
||||
P 3500 2750
|
||||
F 0 "R2" H 3570 2796 50 0000 L CNN
|
||||
F 1 "200" H 3570 2705 50 0000 L CNN
|
||||
F 2 "Resistor_SMD:R_0805_2012Metric" V 3430 2750 50 0001 C CNN
|
||||
F 3 "~" H 3500 2750 50 0001 C CNN
|
||||
1 3500 2750
|
||||
1 0 0 -1
|
||||
$EndComp
|
||||
$Comp
|
||||
L Device:C C1
|
||||
U 1 1 5EBE91AC
|
||||
P 3900 2750
|
||||
F 0 "C1" H 4015 2796 50 0000 L CNN
|
||||
F 1 "1uF" H 4015 2705 50 0000 L CNN
|
||||
F 2 "Capacitor_SMD:C_0805_2012Metric" H 3938 2600 50 0001 C CNN
|
||||
F 3 "~" H 3900 2750 50 0001 C CNN
|
||||
1 3900 2750
|
||||
1 0 0 -1
|
||||
$EndComp
|
||||
Wire Wire Line
|
||||
3500 2350 3500 2450
|
||||
Wire Wire Line
|
||||
3900 2600 3900 2450
|
||||
Wire Wire Line
|
||||
3900 2450 3500 2450
|
||||
Connection ~ 3500 2450
|
||||
Wire Wire Line
|
||||
3500 2450 3500 2600
|
||||
$Comp
|
||||
L power:GND #PWR03
|
||||
U 1 1 5EBE965A
|
||||
P 3900 3000
|
||||
F 0 "#PWR03" H 3900 2750 50 0001 C CNN
|
||||
F 1 "GND" H 3905 2827 50 0000 C CNN
|
||||
F 2 "" H 3900 3000 50 0001 C CNN
|
||||
F 3 "" H 3900 3000 50 0001 C CNN
|
||||
1 3900 3000
|
||||
1 0 0 -1
|
||||
$EndComp
|
||||
$Comp
|
||||
L power:GND #PWR02
|
||||
U 1 1 5EBE9830
|
||||
P 3500 3000
|
||||
F 0 "#PWR02" H 3500 2750 50 0001 C CNN
|
||||
F 1 "GND" H 3505 2827 50 0000 C CNN
|
||||
F 2 "" H 3500 3000 50 0001 C CNN
|
||||
F 3 "" H 3500 3000 50 0001 C CNN
|
||||
1 3500 3000
|
||||
1 0 0 -1
|
||||
$EndComp
|
||||
$Comp
|
||||
L power:VCC #PWR01
|
||||
U 1 1 5EBE99A0
|
||||
P 3500 1950
|
||||
F 0 "#PWR01" H 3500 1800 50 0001 C CNN
|
||||
F 1 "VCC" H 3517 2123 50 0000 C CNN
|
||||
F 2 "" H 3500 1950 50 0001 C CNN
|
||||
F 3 "" H 3500 1950 50 0001 C CNN
|
||||
1 3500 1950
|
||||
1 0 0 -1
|
||||
$EndComp
|
||||
Wire Wire Line
|
||||
3500 2050 3500 2000
|
||||
Wire Wire Line
|
||||
3500 3000 3500 2900
|
||||
Wire Wire Line
|
||||
3900 3000 3900 2900
|
||||
$Comp
|
||||
L power:GND #PWR0101
|
||||
U 1 1 5EC534BF
|
||||
P 4500 3050
|
||||
F 0 "#PWR0101" H 4500 2800 50 0001 C CNN
|
||||
F 1 "GND" H 4505 2877 50 0000 C CNN
|
||||
F 2 "" H 4500 3050 50 0001 C CNN
|
||||
F 3 "" H 4500 3050 50 0001 C CNN
|
||||
1 4500 3050
|
||||
1 0 0 -1
|
||||
$EndComp
|
||||
$Comp
|
||||
L power:PWR_FLAG #FLG0101
|
||||
U 1 1 5EC53A6E
|
||||
P 4500 2950
|
||||
F 0 "#FLG0101" H 4500 3025 50 0001 C CNN
|
||||
F 1 "PWR_FLAG" H 4500 3123 50 0000 C CNN
|
||||
F 2 "" H 4500 2950 50 0001 C CNN
|
||||
F 3 "~" H 4500 2950 50 0001 C CNN
|
||||
1 4500 2950
|
||||
1 0 0 -1
|
||||
$EndComp
|
||||
$Comp
|
||||
L power:PWR_FLAG #FLG0102
|
||||
U 1 1 5EC53E1A
|
||||
P 3200 1950
|
||||
F 0 "#FLG0102" H 3200 2025 50 0001 C CNN
|
||||
F 1 "PWR_FLAG" H 3200 2123 50 0000 C CNN
|
||||
F 2 "" H 3200 1950 50 0001 C CNN
|
||||
F 3 "~" H 3200 1950 50 0001 C CNN
|
||||
1 3200 1950
|
||||
1 0 0 -1
|
||||
$EndComp
|
||||
Wire Wire Line
|
||||
3200 1950 3200 2000
|
||||
Wire Wire Line
|
||||
3200 2000 3500 2000
|
||||
Connection ~ 3500 2000
|
||||
Wire Wire Line
|
||||
3500 2000 3500 1950
|
||||
Wire Wire Line
|
||||
4500 2950 4500 3050
|
||||
$EndSCHEMATC
|
||||
|
|
@ -13,10 +13,12 @@ pytest-3 --log-cli-level debug
|
|||
import os
|
||||
import sys
|
||||
# Look for the 'utils' module from where the script is running
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, os.path.dirname(script_dir))
|
||||
prev_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, os.path.dirname(prev_dir))
|
||||
# Utils import
|
||||
from utils import context
|
||||
sys.path.insert(0, os.path.dirname(prev_dir))
|
||||
from kiplot.misc import (BOM_ERROR)
|
||||
|
||||
BOM_DIR = 'BoM'
|
||||
|
||||
|
|
@ -35,3 +37,9 @@ def test_bom():
|
|||
ctx.search_in_file(csv, ['R,R1,100', 'R,R2,200', 'C,C1,1uF'])
|
||||
os.remove(os.path.join(ctx.get_board_dir(), 'bom.ini'))
|
||||
ctx.clean_up()
|
||||
|
||||
|
||||
def test_bom_fail():
|
||||
ctx = context.TestContext('BoM_fail', 'bom_no_xml', 'bom', BOM_DIR)
|
||||
ctx.run(BOM_ERROR)
|
||||
ctx.clean_up()
|
||||
|
|
|
|||
|
|
@ -13,10 +13,12 @@ pytest-3 --log-cli-level debug
|
|||
import os
|
||||
import sys
|
||||
# Look for the 'utils' module from where the script is running
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, os.path.dirname(script_dir))
|
||||
prev_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, os.path.dirname(prev_dir))
|
||||
# Utils import
|
||||
from utils import context
|
||||
sys.path.insert(0, os.path.dirname(prev_dir))
|
||||
from kiplot.misc import (BOM_ERROR)
|
||||
|
||||
BOM_DIR = 'BoM'
|
||||
|
||||
|
|
@ -39,3 +41,9 @@ def test_ibom_no_ops():
|
|||
ctx.run()
|
||||
ctx.expect_out_file(os.path.join(BOM_DIR, 'ibom.html'))
|
||||
ctx.clean_up()
|
||||
|
||||
|
||||
def test_ibom_fail():
|
||||
ctx = context.TestContext('BoM_interactiveFail', 'bom_no_xml', 'ibom', BOM_DIR)
|
||||
ctx.run(BOM_ERROR)
|
||||
ctx.clean_up()
|
||||
|
|
|
|||
Loading…
Reference in New Issue