Add options to leave junctions and contact blocks out of the parts list (#1178)

Since #849 the parts list has a row for every contact block (slave) and
terminal-type element. Users who draw the dots and bends where wires
branch as terminal-type symbols (114_connections) get one empty row per
junction: 109 of 151 rows on one reported cabinet.

Two options, both off by default so existing exports are unchanged:
- leave out the contact blocks: --no-slaves, "no_slaves" in qet_export,
  or uncheck the new "Contacts esclaves" element type in the dialog;
- leave out the junctions: terminal-type elements with no label,
  designation, manufacturer or manufacturer reference. --no-junctions,
  "no_junctions", or "Laisser de côté les jonctions" in the dialog.
  A terminal block with a label or a part number stays.

The element type filter had no box for slaves, so every query it built
left them out: the export dialog never listed contact blocks, although
the command line has since #849. The dialog now checks the new box by
default and gives the same rows as --export-bom. The box is unchecked by
default elsewhere, so nomenclature tables keep their rows.

docs/smart-device-bom.md still said slaves and terminals were excluded;
corrected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ispyisail
2026-10-05 22:08:44 +13:00
parent 32f7b94594
commit 8434b88eb8
17 changed files with 273 additions and 39 deletions
+6
View File
@@ -678,6 +678,12 @@ Python, plus the hang guard on `addConductor` and the database refresh in
`source_date_epoch` if given, else the server's own `SOURCE_DATE_EPOCH`,
else 0 (1 January 1970). The result's `"reproducible"` is false, with a
hint, when the QElectroTech build is too old to honour it.
- **`"no_slaves"` and `"no_junctions"` shorten a `bom` export.** The first
leaves out the contact blocks, which otherwise get a row of their own; the
second leaves out terminal-type elements with no label, designation,
manufacturer or manufacturer reference, such as the junction dots of
`114_connections`. They pass `--no-slaves` and `--no-junctions`; an older
QElectroTech ignores both and exports every row, so check the row count.
- **`qet_export` isolates its launch.** SingleApplication keys its socket
on `applicationFilePath()`, so a second launch of the same binary path
forwards its request to an already-running instance and returns *that*
+22 -4
View File
@@ -1059,10 +1059,13 @@ def _source_date_epoch(value) -> int:
def tool_export(binary: str, project: str, format: str, output: str,
timeout: int = 180, reproducible: bool = False,
source_date_epoch: int | None = None) -> dict:
source_date_epoch: int | None = None,
no_slaves: bool = False, no_junctions: bool = False) -> dict:
if format not in EXPORT_FORMATS:
raise ValueError(f"unknown format {format!r}; "
f"expected one of {', '.join(sorted(EXPORT_FORMATS))}")
if (no_slaves or no_junctions) and format != "bom":
raise ValueError("no_slaves and no_junctions only apply to format \"bom\"")
proj = Path(project).expanduser()
if not proj.is_file():
raise ValueError(f"no such project: {proj}")
@@ -1080,8 +1083,12 @@ def tool_export(binary: str, project: str, format: str, output: str,
if reproducible or source_date_epoch is not None:
epoch = _source_date_epoch(source_date_epoch)
extra_env = {"SOURCE_DATE_EPOCH": str(epoch)}
result = _run_qet(binary, [flag, str(proj), output], timeout,
extra_env=extra_env)
args = [flag, str(proj), output]
if no_slaves:
args.append("--no-slaves")
if no_junctions:
args.append("--no-junctions")
result = _run_qet(binary, args, timeout, extra_env=extra_env)
out = Path(output).expanduser()
result["output"] = str(out)
result["output_exists"] = out.exists()
@@ -4783,13 +4790,24 @@ TOOLS = [
"carries, in seconds since 1970 UTC. "
"Default: this server's own "
"SOURCE_DATE_EPOCH, else 0"},
"no_slaves": {"type": "boolean", "default": False,
"description": "bom: leave out the contact blocks (slave "
"elements), which otherwise get a row of "
"their own with their master's label"},
"no_junctions": {"type": "boolean", "default": False,
"description": "bom: leave out the junctions: "
"terminal-type elements with no label, "
"designation, manufacturer or "
"manufacturer reference"},
},
"required": ["project", "format", "output"],
},
"handler": lambda a: tool_export(a["binary"], a["project"], a["format"],
a["output"], a.get("timeout", 180),
a.get("reproducible", False),
a.get("source_date_epoch")),
a.get("source_date_epoch"),
a.get("no_slaves", False),
a.get("no_junctions", False)),
},
{
"name": "qet_edit",
+30
View File
@@ -4025,6 +4025,36 @@ class ProjectNewValidation(unittest.TestCase):
self.assertFalse(Path(new).exists())
class BomExportOptions(unittest.TestCase):
"""qet_export's no_slaves and no_junctions become --export-bom flags (#1178)."""
def run_export(self, format="bom", **kw):
seen = []
def fake(binary, args, timeout=180, **rest):
seen.extend(args)
return {"ok": True}
with tempfile.TemporaryDirectory() as tmp:
proj = Path(tmp) / "a.qet"
proj.write_text("<project/>")
with unittest.mock.patch.object(m, "_run_qet", fake):
m.tool_export("qet", str(proj), format, str(Path(tmp) / "o.csv"), **kw)
return seen
def test_off_by_default(self):
args = self.run_export()
self.assertNotIn("--no-slaves", args)
self.assertNotIn("--no-junctions", args)
def test_flags_after_the_output(self):
args = self.run_export(no_slaves=True, no_junctions=True)
self.assertEqual(args[0], "--export-bom")
self.assertEqual(args[3:], ["--no-slaves", "--no-junctions"])
def test_refused_for_other_formats(self):
with self.assertRaises(ValueError):
self.run_export(format="wiring", no_junctions=True)
class ReproducibleExport(unittest.TestCase):
"""qet_export's "reproducible" sets SOURCE_DATE_EPOCH for the run."""