Skip to content

[framework] bench2 edit — one-command live editing in CQ-editor - #67

Open
BenchCAD wants to merge 3 commits into
mainfrom
feat/bench2-edit
Open

[framework] bench2 edit — one-command live editing in CQ-editor#67
BenchCAD wants to merge 3 commits into
mainfrom
feat/bench2-edit

Conversation

@BenchCAD

Copy link
Copy Markdown
Collaborator

uv run bench2 edit <family> — open a family's part.py in CQ-editor with the part already on screen, edit, press F5, close. That's the whole workflow; there is no install step.

Why

Today live editing means: uv tool install cq-editor (manual, one-time), then uv run python tools/debug_family.py --config designs/<fam>/part.py, then remember --strip before committing. And that stand-alone editor brings cadquery 2.8 and cannot import bench2, so it disagrees with what bench2 validate builds and simply fails on families that use bench2.geomlib helpers — our own docs told people to use ocp-vscode instead.

What bench2 edit does

  1. installs CQ-editor on first use into this project's env (new editor dependency group, uv run --group editor, ~1 min, cached afterwards);
  2. samples a valid instance (honouring spec.check; --diff, --seed, k=v overrides) and appends a marked scratch block to part.py — the PARAMS dict plus the show_object(build(**PARAMS)) call CQ-editor needs to draw anything;
  3. opens the editor and waits — F5 re-renders whatever you type;
  4. removes the scratch block when you close the editor, keeping your edits above it, so part.py returns to the clean build() the benchmark derives from.

Running inside the project env is the point: the editor uses the pinned cadquery 2.3.0 and can import bench2, so a geomlib family renders exactly as bench2 validate will build it. The launcher also applies the OCP HashCode shim before cq_editor imports cadquery (2.3.0 + OCP 7.9 dropped TopoDS_*.HashCode).

Belt and braces

If the editor is killed the block survives, so bench2 validate now fails with "part.py still has a bench2 edit scratch block" and points at bench2 edit <family> --strip. A leftover block used to be silently committable (show_object is stubbed in execute.py).

Verified

  • editor window opens and stays up on the pinned env (cadquery 2.3.0, cq-editor 0.7.0, py3.11);
  • the F5 path: exec'ing part.py with show_object injected and pushing the result through cq-editor's own make_AIS() gives an AIS_Shape with the right bbox (600 × 35 × 7.5 mm for slotted_din_rail hard) — i.e. cadquery 2.3.0 drives the editor's viewer fine;
  • block round-trip is byte-identical (git diff clean after close);
  • bench2 validate red with a block, green after --strip; both merged families still PASS;
  • ruff clean on the changed files.

Notes

  • docs/DEBUGGING.md §A rewritten around bench2 edit; the old "CQ-editor runs cadquery 2.8, prefer ocp-vscode" gotcha is no longer true and is replaced.
  • tools/debug_family.py keeps its no-GUI "print params/check/solids/bbox" mode (still handy, still used by WALKTHROUGH); its docstring now points GUI users at bench2 edit.
  • uv.lock grows by the editor group (PyQt5 + qtconsole). It is not a default group: uv sync and CI don't download it.

🤖 Generated with Claude Code

`uv run bench2 edit <family>` opens the family's part.py in CQ-editor with the
part already on screen, and leaves the file clean afterwards:

1. installs CQ-editor on first use (new `editor` dependency group), so there is
   no separate 'uv tool install' step;
2. samples a valid instance (honouring spec.check, with k=v overrides) and
   appends a marked scratch block — PARAMS + show_object(build(**PARAMS));
3. launches the editor and waits; F5 re-renders what you type;
4. strips the scratch block when the editor closes, keeping your edits.

The editor runs INSIDE the project env, which is the point: it uses the pinned
cadquery 2.3.0 and can import bench2, so geomlib families render exactly as
bench2 validate builds them. A stand-alone `uv tool install cq-editor` brings
cadquery 2.8 and cannot import bench2 — that was the old, documented limitation.
The launcher also applies the OCP HashCode shim before cq_editor imports
cadquery (pinned 2.3.0 + OCP 7.9 dropped TopoDS_*.HashCode).

Belt and braces: if the editor is killed, the block survives — so
`bench2 validate` now fails with 'part.py still has a bench2 edit scratch block'
and `bench2 edit <family> --strip` removes it.

Verified on designs/slotted_din_rail + speaker_pole_mount_socket: the editor
window opens and stays up, cq_editor's own make_AIS() converts build()'s result
(AIS_Shape, correct bbox) under cadquery 2.3.0, the block round-trips
byte-identically, validate goes red then green, and ruff is clean.

Signed-off-by: BenchCAD <benchcad@users.noreply.github.com>
@github-actions

github-actions Bot commented Jul 27, 2026

Copy link
Copy Markdown

bench2 validate

slotted_din_rail

  ✓ family.json: keys + base_plane valid
  ✓ pieces: build(10 params) + PARAM_SPEC + check present
  ✓ PARAM_SPEC: 11 params, all entries complete
  ✓ easy: 4/4 seeds sample+check+build+execute clean
  ✓ medium: 4/4 seeds sample+check+build+execute clean
  ✓ hard: 4/4 seeds sample+check+build+execute clean
  ✓ difficulty separation: difficulties produce distinct programs
  ✓ geometry novelty: 6/12 unique shapes (50% duplicate)
  ✓ solids: every instance non-degenerate, 1 solid(s) each
PASS — designs/slotted_din_rail

speaker_pole_mount_socket

  ✓ family.json: keys + base_plane valid
  ✓ pieces: build(8 params) + PARAM_SPEC + check present
  ✓ PARAM_SPEC: 8 params, all entries complete
  ✓ easy: 4/4 seeds sample+check+build+execute clean
  ✓ medium: 4/4 seeds sample+check+build+execute clean
  ✓ hard: 4/4 seeds sample+check+build+execute clean
  ✓ coverage: bore_d reaches all 2 declared values (standard table fully covered)
  ✓ coverage: flange_od reaches all 2 declared values (standard table fully covered)
  ✓ coverage: flange_t reaches all 2 declared values (standard table fully covered)
  ✓ coverage: depth reaches all 6 declared values (standard table fully covered)
  ✓ difficulty separation: difficulties produce distinct programs
  ✓ geometry novelty: 9/12 unique shapes (25% duplicate)
  ✓ solids: every instance non-degenerate, 1 solid(s) each
PASS — designs/speaker_pole_mount_socket

Previews: the previews artifact on this run.

@HaozheZhang6
HaozheZhang6 self-requested a review July 28, 2026 09:26

@HaozheZhang6 HaozheZhang6 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ran the whole thing on a fresh clone on this machine (macOS arm64, py3.11) rather than taking the Verified list on faith:

  • uv run bench2 edit slotted_din_rail --diff hard --seed 3 — first run installed the editor group (43 pkgs, well under a minute with a warm uv cache), appended the scratch block with a valid sampled instance, and the CQ-editor window came up and stayed up in the pinned env (cadquery 2.3.0, HashCode shim active — no OCP crash on boot).
  • Close path: block auto-removed, part.py byte-identical afterwards (git diff empty).
  • Crash path: kill -9 on the whole tree → block survives → bench2 validate fails with the exact --strip pointer → --strip → validate PASS, file byte-identical again.

One thing I could not verify without driving the GUI: whether the part is drawn on open ("with the part already on screen") or only after the first F5 — worth a one-word tweak if it's the latter.

Two asks:

  • Drop the "Generated with Claude Code" footer from the PR body (and keep it out of the squash message) — repo convention is no AI attribution anywhere; the commits themselves are clean.
  • bench2 edit --file <path> k=v silently swallows the first override into the unused family positional. Cheap fix: error (or warn) when both --file and a bare positional are given.

Minor, non-blocking: strip_block on a LEGACY_MARK block deletes everything after the mark (no end sentinel) — fine for appended blocks, would eat trailing code if someone hand-moved one mid-file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants