From 02dbb133b52f7d4e33f8c8204bfe61b9b674aa34 Mon Sep 17 00:00:00 2001 From: Umut CAN Date: Tue, 22 Sep 2026 13:07:31 +0300 Subject: [PATCH] feat(settings): live COM smoke on AutoCAD 2026 builds the five .dwt twins and records the run scripts/smoke_settings_com.py --build-dwt exited 0 on AutoCAD 2026 (25.1s), 2026-09-22: five templates/*.dwt written through drawing_template_save (SaveAs code 66, each file opens with AC1032), page setup plotted and the PDF's own /MediaBox read back as 420.158 x 297.039 mm, iso_a3_mech.dwt reopened as source "bundled" with ISO-25 current, layer state / named view / UCS / preferences / SummaryInfo / prompt line all through the COM engine. The record is in CHANGELOG.md under Unreleased. The smoke keeps a ledger of the documents it opens and closes them on the way out, so a failed run never leaves scratch documents on the operator's seat. Two of its expectations were corrected to the merged tree: mleaderstyle_create is implemented on COM (spec: no `mleaderstyle` key), and plot_style_list marks catalogue rows with `installed`. --interactive was not run unattended on the shared seat (an unanswered GetPoint holds the command line); Task 23 measured the pick live. *.dwt / *.dwg are binary in .gitattributes; AutoCAD's plot.log is ignored. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd --- .gitattributes | 2 + .gitignore | 4 + CHANGELOG.md | 454 ++++++++++++++++++++++++++++++++++ scripts/smoke_settings_com.py | 388 +++++++++++++++++++++++++++++ templates/README.md | 8 +- templates/ansi_b_mech.dwt | Bin 0 -> 17250 bytes templates/ansi_d_arch.dwt | Bin 0 -> 17278 bytes templates/iso_a1_arch.dwt | Bin 0 -> 17281 bytes templates/iso_a3_mech.dwt | Bin 0 -> 18240 bytes templates/iso_a3_pid.dwt | Bin 0 -> 18528 bytes 10 files changed, 855 insertions(+), 1 deletion(-) create mode 100644 scripts/smoke_settings_com.py create mode 100644 templates/ansi_b_mech.dwt create mode 100644 templates/ansi_d_arch.dwt create mode 100644 templates/iso_a1_arch.dwt create mode 100644 templates/iso_a3_mech.dwt create mode 100644 templates/iso_a3_pid.dwt diff --git a/.gitattributes b/.gitattributes index ada0244..bb81e50 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,3 +2,5 @@ * text=auto templates/*.dxf text eol=crlf templates/*.dwt binary +*.dwt binary +*.dwg binary diff --git a/.gitignore b/.gitignore index 13517c3..9b07d1a 100644 --- a/.gitignore +++ b/.gitignore @@ -60,3 +60,7 @@ benchmarks/.competitors/ # committed one was stale and unvetted — but CI now installs from it with # `uv sync --locked`, so ignoring it would silently disarm every locked lane. # Regenerate with `uv lock` whenever pyproject.toml dependencies change. + +# AutoCAD writes its plot-and-publish log into the cwd of the plotting process +# (scripts/smoke_settings_com.py plots from the repo root). +plot.log diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f45963..e44aba1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -174,6 +174,460 @@ AutoCAD type library (a package directory holding only a `__pycache__`) — an environment fault, not a backend one; deleting `%TEMP%\gen_py\3.11` cleared it and no backend change was needed. +### Live COM smoke — settings (track E) + +`scripts/smoke_settings_com.py --build-dwt`, AutoCAD 2026 (`25.1s (LMS Tech)`), +Windows 11, 2026-09-22, in a new document (`Drawing27.dwg`) — styles → +page setup → `batch_plot` (the PDF's own `/MediaBox`) → the five `.dwt` twins +built and `iso_a3_mech.dwt` reopened → layer state round trip → named view → +UCS → preferences (one reversible set) → SummaryInfo → prompt line, all +through the COM engine, exit 0: + +```json +{ + "autocad": "25.1s (LMS Tech)", + "system_launch": { + "launched": false, + "attached": true, + "version": "25.1s (LMS Tech)", + "document": "Drawing9.dwg", + "visible": true, + "progid": "AutoCAD.Application", + "backend": "com" + }, + "dwt_built": [ + { + "name": "iso_a3_mech", + "path": "templates\\iso_a3_mech.dwt", + "bytes": 18240, + "magic": "AC1032", + "is_dwg_container": true, + "format": "dwt" + }, + { + "name": "iso_a1_arch", + "path": "templates\\iso_a1_arch.dwt", + "bytes": 17281, + "magic": "AC1032", + "is_dwg_container": true, + "format": "dwt" + }, + { + "name": "iso_a3_pid", + "path": "templates\\iso_a3_pid.dwt", + "bytes": 18528, + "magic": "AC1032", + "is_dwg_container": true, + "format": "dwt" + }, + { + "name": "ansi_b_mech", + "path": "templates\\ansi_b_mech.dwt", + "bytes": 17250, + "magic": "AC1032", + "is_dwg_container": true, + "format": "dwt" + }, + { + "name": "ansi_d_arch", + "path": "templates\\ansi_d_arch.dwt", + "bytes": 17278, + "magic": "AC1032", + "is_dwg_container": true, + "format": "dwt" + } + ], + "document": "Drawing27.dwg", + "styles": { + "dimstyle": { + "ok": true, + "name": "ISO-25-SMOKE", + "values": { + "DIMTXT": 2.5, + "DIMASZ": 2.5, + "DIMEXE": 1.25, + "DIMEXO": 0.625, + "DIMGAP": 0.625, + "DIMTAD": 1, + "DIMTIH": 0, + "DIMTOH": 0, + "DIMDEC": 2, + "DIMDSEP": ",", + "DIMLUNIT": 2, + "DIMZIN": 8, + "DIMBLK": "", + "DIMTXSTY": "ISOCP", + "DIMLWD": -2, + "DIMLWE": -2, + "DIMSCALE": 1.0 + }, + "written": [ + "DIMASZ", + "DIMBLK", + "DIMDEC", + "DIMDSEP", + "DIMEXE", + "DIMEXO", + "DIMGAP", + "DIMLUNIT", + "DIMLWD", + "DIMLWE", + "DIMSCALE", + "DIMTAD", + "DIMTIH", + "DIMTOH", + "DIMTXSTY", + "DIMTXT", + "DIMZIN" + ], + "current": true, + "textstyle_created": true + }, + "textstyle": { + "ok": true, + "name": "ISOCP-SMOKE", + "font": "isocp.shx", + "font_resolved": true, + "current": false + }, + "mleaderstyle": { + "ok": true, + "name": "SMOKE", + "values": { + "arrow_size": 2.5, + "landing_gap": 1.0, + "text_style": "ISOCP", + "text_height": 2.5 + }, + "textstyle_created": false + }, + "mleaderstyles_on_seat": [ + "SMOKE", + "Standard" + ] + }, + "page_setup": { + "applied": { + "paper": "ISO_A3", + "orientation": "landscape", + "size_mm": [ + 420.0, + 297.0 + ], + "canonical_media_name": "ISO_A3_(420.00_x_297.00_MM)", + "plot_style": "monochrome.ctb", + "plot_style_known": true, + "scale": "1:1", + "scale_factor": 1.0, + "scale_ratio": [ + 1.0, + 1.0 + ], + "dxf_standard_scale_type": 16, + "activex_standard_scale": 16, + "plot_area": "layout", + "plot_type": 5, + "device": "DWG To PDF.pc3", + "margins_mm": null, + "center": null, + "paper_units": "mm" + }, + "changed": { + "paper": [ + "", + "ISO_A3" + ], + "canonical_media_name": [ + "", + "ISO_A3_(420.00_x_297.00_MM)" + ], + "size_mm": [ + [ + 0.0, + 0.0 + ], + [ + 420.0, + 297.0 + ] + ], + "plot_style": [ + "", + "monochrome.ctb" + ], + "device": [ + "Microsoft Print to PDF", + "DWG To PDF.pc3" + ], + "margins_mm": [ + [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + [ + 17.0, + 17.0, + 5.0, + 5.0 + ] + ], + "paper_units": [ + "inches", + "mm" + ] + }, + "pdf": { + "layout": "Layout1", + "ok": true, + "path": "C:\\Users\\VECTOR\\AppData\\Local\\Temp\\acadmcp_settings_smoke_sapms54v\\Drawing27-Layout1.pdf", + "bytes": 2774, + "mediabox_mm": [ + 420.158, + 297.039 + ], + "paper": "ISO_A3" + }, + "installed_plot_styles": [ + "Autodesk-Color.stb", + "Autodesk-MONO.stb", + "DWF Virtual Pens.ctb", + "Fill Patterns.ctb", + "Grayscale.ctb", + "Screening 100%.ctb", + "Screening 25%.ctb", + "Screening 50%.ctb", + "Screening 75%.ctb", + "acad.ctb", + "acad.stb", + "monochrome.ctb", + "monochrome.stb" + ] + }, + "template": { + "path": "C:\\Users\\VECTOR\\Documents\\GitHub\\Autocad-MCP\\templates\\iso_a3_mech.dwt", + "source": "bundled", + "document": "Drawing28.dwg", + "dimstyle_current": [ + "ISO-25" + ], + "papers": [ + "ISO_A3" + ] + }, + "documents": [ + { + "name": "Drawing9.dwg", + "path": null, + "active": false, + "saved": false, + "entity_count": 0 + }, + { + "name": "Drawing27.dwg", + "path": null, + "active": true, + "saved": false, + "entity_count": 0 + } + ], + "layer_state": { + "saved": { + "ok": true, + "name": "SMOKE", + "layer_count": 3, + "replaced": false, + "chunks": 2, + "backend": "com" + }, + "restored": { + "ok": true, + "name": "SMOKE", + "applied": { + "layers": 3, + "properties": [ + "on", + "frozen", + "locked", + "color", + "linetype", + "lineweight", + "plot", + "current" + ], + "current_layer": "0" + }, + "missing_layers": [], + "new_layers": [], + "backend": "com" + }, + "deleted": { + "ok": true, + "deleted": "SMOKE", + "backend": "com" + } + }, + "view": { + "saved": { + "ok": true, + "name": "SMOKE_VIEW", + "center": [ + 100.0, + 50.0 + ], + "height": 80.0, + "width": 160.9964412811388, + "replaced": false, + "backend": "com" + }, + "restored": { + "ok": true, + "name": "SMOKE_VIEW", + "center": [ + 100.0, + 50.0 + ], + "height": 80.0, + "width": 160.9964412811388, + "applied": "zoom_window", + "backend": "com", + "viewctr": [ + 100.0, + 50.0 + ], + "viewsize": 80.0 + } + }, + "ucs": { + "set": { + "ok": true, + "name": "SMOKE_UCS", + "origin": [ + 10.0, + 20.0, + 0.0 + ], + "x_axis": [ + 1.0, + 0.0, + 0.0 + ], + "y_axis": [ + 0.0, + 1.0, + 0.0 + ], + "replaced": false, + "current": true, + "backend": "com" + }, + "world": { + "ok": true, + "name": "world", + "current": true, + "backend": "com" + } + }, + "preferences": { + "cursor_size": 5, + "read_only": [ + "Files.SupportPath", + "Files.TemplateDwgPath", + "Files.PrinterStyleSheetPath", + "Files.PrinterConfigPath" + ], + "template_dwg_path": "C:\\Users\\VECTOR\\AppData\\Local\\Autodesk\\AutoCAD 2026\\R25.1\\enu\\Template" + }, + "properties": { + "set": { + "ok": true, + "summary_written": [ + "author", + "title" + ], + "custom_written": [ + "ACADMCP_SMOKE" + ], + "custom_deleted": [], + "backend": "com" + }, + "get": { + "summary": { + "title": "ACADMCP settings smoke", + "subject": "", + "author": "smoke_settings_com.py", + "keywords": "", + "comments": "" + }, + "summary_available": true, + "custom": { + "ACADMCP_SMOKE": "1" + }, + "backend": "com" + } + }, + "prompt_message": { + "ok": true, + "text": "ACADMCP settings smoke: done", + "backend": "com" + }, + "failures": [] +} +``` + +The headless engine reports the identical `mediabox_mm` (to 1e-9: matplotlib +writes an exact 420 × 297; AutoCAD's PDF driver writes 420.158 × 297.039, +inside spec §9's ±0.5 mm), `layer_state.restored` and `properties.get.custom` +on the same steps; `summary_available` is `false` headlessly and the five +summary fields are `null` (capability `dwgprops`). + +What the run refused before the green one, each fixed in the backend and +pinned by a fake-ActiveX test: + +- Three runs died with `RPC_E_CALL_REJECTED` (-2147418111) on the read that + follows a document switch — `Documents.Count` straight after + `Documents.Open`, after `Close(False)` inside `document_close`, and in + `_ensure_document_state` — AutoCAD's own message filter refusing the call + while it still switches documents. pywin32 has no + `CoRegisterMessageFilter`, so the backend now waits that window out itself + (`_wait_out_rejected_call`, read-only callables only, 0.25 s → 1 s pauses + inside a 20 s budget) at those sites; any other error is not retried. +- `layer_list` on the reopened template raised `AttributeError: 'IAcadLayer' + object has no attribute 'Color'. Did you mean: 'color'?`. The type library + spells `IAcadEntity` / `IAcadLayer` `color` and `Lineweight`; late-bound + dispatch resolved `.Color` / `.LineWeight` case-insensitively, but once a + makepy cache exists (this machine's was regenerated on 2026-09-17) every + object a method returns is a generated wrapper and the lookup is exact. The + backend now spells both members as the type library does (works on both + wrappers) and the fakes model the measured names. +- `layer_state_restore` raised `'IAcadObject' object has no attribute + 'Count'`: `Dictionaries.Item` and `IAcadDictionary.Item` are declared + `IAcadObject*` (the narrowing `_com_unnarrow` already handled for MLEADER + styles); the save before it went through the typed `Dictionaries.Add`, so + only the reopen paths failed. Both now un-narrow. +- A state saved with layer `0` current came back with two warnings and `0` + unapplied: the `Freeze` put on layer `0` raises 'Invalid layer' whatever + the value, even `False` while thawed (measured on a scratch document; + `color` / `Linetype` / `Lineweight` / `Plottable` / `LayerOn` / `Lock` / + `ActiveLayer` all fine on it). `Freeze` is now written only when it would + change the layer. +- Two of the smoke's own expectations predated the merged tree and were + corrected to it: `mleaderstyle_create` is implemented on COM through the + `ACAD_MLEADERSTYLE` dictionary (spec §4: no `mleaderstyle` key exists), so + the smoke now asserts the created style is listed with `arrow_size` 2.5; + and `plot_style_list` marks catalogue rows with `installed: true` (the + `source: "installed"` rows are files the catalogue does not know), so the + `monochrome.ctb` check reads that flag. + +`--interactive` (`user_pick_point`) was not run in this session: the seat is +shared with other agents and nobody was confirmed at the keyboard, and an +unanswered `Utility.GetPoint` holds AutoCAD's command line — every COM client +gets `RPC_E_CALL_REJECTED` — until someone presses Esc, past the 60 s timeout. +The pick path was executed live earlier in the track (Task 23's measurement: +`GetPoint` answers in WCS while `GetEntity` answers in the current UCS). Each +plot also dropped AutoCAD's `plot.log` into the repo root; it is ignored now. + ## [1.5.1] — 2026-08-06 A patch for three defects found *after* 1.5.0 went to PyPI, two of them by the diff --git a/scripts/smoke_settings_com.py b/scripts/smoke_settings_com.py new file mode 100644 index 0000000..c604491 --- /dev/null +++ b/scripts/smoke_settings_com.py @@ -0,0 +1,388 @@ +# scripts/smoke_settings_com.py +"""Exercise the settings track once against the live AutoCAD on this machine. + +Creates a NEW document (never touches the operator's open drawing) and runs +every SECTION 18-20 path that needs a live seat, through the same backend +methods the tools call: + + system_launch (attach) -> {attached, launched, version} + dimstyle_create ISO-25 / textstyle_create ISOCP + / mleaderstyle_create iso -> listed with arrow_size 2.5 + page_setup_apply ISO_A3 -> batch_plot -> the PDF's own /MediaBox (420 x 297) + plot_style_list (installed .ctb files) + drawing_new(template=iso_a3_mech .dwt) -> mech layers, ISO-25 current, ISO_A3 + document_list / document_activate + layer_state_save -> change -> layer_state_restore -> layer_state_delete + view_named_save / view_named_list / view_named_restore + ucs_set / ucs_list / ucs_restore("world") + a non-orthogonal refusal + preferences_get + ONE reversible preferences_set (Display.CursorSize) + + a read-only key refused + drawing_properties_set / get (SummaryInfo + a custom property) + system_prompt_message + --interactive: user_pick_point (needs the operator at the keyboard) + --build-dwt: open each templates/.dxf and save the .dwt twin + through drawing_template_save, before anything else + +Prints one JSON report. Exit codes: + + 0 every assertion held (``failures`` is empty) + 1 the seat answered but at least one assertion failed (listed) + 2 no live CAD application reachable (pywin32 missing, or the ProgID + cannot be created) -- the COM paths then remain fake-tested only + +Reachability is read from ``system_status()`` because ``connect()`` is lazy. +The ``Dispatch`` fallback *launches* the ProgID when nothing is running and a +cold start can exceed ``COM_CALL_TIMEOUT`` (60 s): open AutoCAD first. + + AUTOCAD_MCP_BACKEND=com uv run --frozen python scripts/smoke_settings_com.py + uv run --frozen python scripts/smoke_settings_com.py --build-dwt + uv run --frozen python scripts/smoke_settings_com.py --interactive --keep +""" + +from __future__ import annotations + +import argparse +import asyncio +import json +import sys +import tempfile +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +sys.path.insert(0, str(ROOT)) + +#: The five bundled templates (spec §6). Pinned here rather than read from +#: the catalogue so the smoke also notices a catalogue that lost a row. +TEMPLATE_NAMES = ("iso_a3_mech", "iso_a1_arch", "iso_a3_pid", "ansi_b_mech", "ansi_d_arch") + +#: Every DWG/DWT since R13 opens with "AC10xx" (AC1032 for the 2018 format). +DWG_MAGIC = b"AC10" + +#: What the ISO A3 landscape sheet must read back as, from the PDF itself. +A3_LANDSCAPE_MM = (420.0, 297.0) +MEDIABOX_TOLERANCE_MM = 0.5 + + +def _check(failures: list[str], label: str, ok: bool) -> None: + if not ok: + failures.append(label) + + +#: Names of the documents this run opened and has not closed yet. A run that +#: dies half-way closes them in ``main``'s ``finally`` (unless ``--keep``), so +#: a failed smoke never leaves its scratch documents on the operator's seat. +_OPENED: list[str] = [] + + +async def _opened_now(backend) -> str: + """Record the document a ``drawing_new`` / ``drawing_open`` just made active.""" + name = (await backend.system_status()).get("active_document") + if name and name not in _OPENED: + _OPENED.append(name) + return name + + +async def _close_ours(backend, name: str) -> None: + await backend.document_close(name, discard=True) + if name in _OPENED: + _OPENED.remove(name) + + +async def _close_leftovers(backend) -> None: + open_names = {row["name"] for row in await backend.document_list()} + for name in list(_OPENED): + if name in open_names: + try: + await backend.document_close(name, discard=True) + except Exception as exc: # best effort on the way out + print(f"could not close {name}: {exc}", file=sys.stderr) + _OPENED.remove(name) + + +async def build_dwt(backend) -> list[dict]: + """Open each bundled DXF over COM and save its .dwt twin next to it.""" + from engineering.standards.templates import TEMPLATE_CATALOG, TEMPLATES_DIR + + rows: list[dict] = [] + if len(TEMPLATE_CATALOG) != len(TEMPLATE_NAMES): + raise SystemExit( + f"TEMPLATE_CATALOG has {len(TEMPLATE_CATALOG)} rows, the smoke pins " + f"{len(TEMPLATE_NAMES)}: update TEMPLATE_NAMES deliberately" + ) + for name in TEMPLATE_NAMES: + dxf = Path(TEMPLATES_DIR).resolve() / f"{name}.dxf" + dwt = Path(TEMPLATES_DIR).resolve() / f"{name}.dwt" + if not dxf.exists(): + raise SystemExit(f"{dxf} is missing: run scripts/build_templates.py first") + await backend.drawing_open(str(dxf)) + opened_as = await _opened_now(backend) + saved = await backend.drawing_template_save( + str(dwt), name=name, description=f"AutoCAD MCP Pro bundled template {name}" + ) + # SaveAs rebinds the document to the .dwt name (``document_rebound``). + if opened_as in _OPENED: + _OPENED.remove(opened_as) + await _close_ours(backend, await _opened_now(backend)) + head = dwt.read_bytes()[:6] + rows.append( + { + "name": name, + "path": str(dwt.relative_to(ROOT)), + "bytes": dwt.stat().st_size, + "magic": head.decode("ascii", "replace"), + "is_dwg_container": head.startswith(DWG_MAGIC), + "format": saved["format"], + } + ) + return rows + + +async def main(args: argparse.Namespace) -> int: + try: + from backends.com_backend import ComBackend + except ImportError as exc: + print(f"pywin32 not available: {exc}") + return 2 + backend = ComBackend() + try: + await backend.connect() + except Exception as exc: + print(f"no live AutoCAD reachable: {exc}") + return 2 + + failures: list[str] = [] + report: dict = {} + try: + status = await backend.system_status() + if not status.get("connected"): + print(f"no live AutoCAD reachable: {status.get('error', status)}") + return 2 + report["autocad"] = status.get("autocad_version") or status.get("cad_progid") + report["system_launch"] = await backend.system_launch(visible=True) + _check(failures, "system_launch attached", report["system_launch"]["attached"] is True) + + if args.build_dwt: + report["dwt_built"] = await build_dwt(backend) + _check( + failures, + "every .dwt is a DWG container", + all(row["is_dwg_container"] for row in report["dwt_built"]), + ) + + await backend.drawing_new() + smoke_document = await _opened_now(backend) + report["document"] = smoke_document + + # ── styles ──────────────────────────────────────────────────────── + from engineering.standards.dimstyles import resolve_dimstyle + from engineering.standards.mleaderstyles import resolve_mleaderstyle + + created = await backend.dimstyle_create( + "ISO-25-SMOKE", resolve_dimstyle("iso-25", None), set_current=True + ) + dimstyles = {row["name"]: row for row in await backend.dimstyle_list()} + smoke_style = dimstyles["ISO-25-SMOKE"] + _check(failures, "dimstyle DIMTXT 2.5", abs(smoke_style["values"]["DIMTXT"] - 2.5) < 1e-6) + _check(failures, "dimstyle DIMDSEP ','", smoke_style["values"]["DIMDSEP"] == ",") + _check(failures, "dimstyle current", smoke_style["current"] is True) + textstyle = await backend.textstyle_create("ISOCP-SMOKE", "isocp.shx") + _check(failures, "isocp.shx resolved on the seat", textstyle["font_resolved"] is True) + # Both engines create MLEADER styles (spec: COM through the + # ACAD_MLEADERSTYLE dictionary's AddObject; no `mleaderstyle` key). + mleader_created = await backend.mleaderstyle_create( + "SMOKE", resolve_mleaderstyle("iso", None) + ) + mleader_styles = {row["name"]: row for row in await backend.mleaderstyle_list()} + _check(failures, "mleaderstyle created on COM", mleader_created["ok"] is True) + _check(failures, "mleaderstyle listed", "SMOKE" in mleader_styles) + _check( + failures, + "mleaderstyle ISO arrow 2.5", + abs(float(mleader_styles.get("SMOKE", {}).get("arrow_size", 0.0)) - 2.5) < 1e-6, + ) + report["styles"] = { + "dimstyle": created, + "textstyle": textstyle, + "mleaderstyle": mleader_created, + "mleaderstyles_on_seat": sorted(mleader_styles), + } + + # ── page setup + the PDF's own mediabox ─────────────────────────── + from engineering.standards.papers import resolve_page_setup + from engineering.standards.plot import batch_plot + + applied = await backend.page_setup_apply( + "Layout1", resolve_page_setup("ISO_A3", orientation="landscape", scale="1:1") + ) + listed = (await backend.page_setup_list("Layout1"))[0] + _check( + failures, + "page_setup_list says 420 x 297", + tuple(float(v) for v in listed["size_mm"]) == A3_LANDSCAPE_MM, + ) + out_dir = Path(tempfile.mkdtemp(prefix="acadmcp_settings_smoke_")) + plotted = await batch_plot(backend, ["Layout1"], str(out_dir), "{drawing}-{layout}.pdf") + pdf_row = plotted["sheets"][0] + width_mm, height_mm = (float(v) for v in pdf_row["mediabox_mm"]) + _check( + failures, + "PDF /MediaBox is 420 x 297 (+-0.5 mm)", + abs(width_mm - A3_LANDSCAPE_MM[0]) < MEDIABOX_TOLERANCE_MM + and abs(height_mm - A3_LANDSCAPE_MM[1]) < MEDIABOX_TOLERANCE_MM, + ) + # Catalogue rows carry ``installed`` (True/False, None when the + # Preferences object is unreachable); ``source: "installed"`` marks + # files the catalogue does not know. + installed = sorted( + row["name"] for row in await backend.plot_style_list() if row.get("installed") is True + ) + _check(failures, "monochrome.ctb installed on the seat", "monochrome.ctb" in installed) + report["page_setup"] = { + "applied": applied["applied"], + "changed": applied["changed"], + "pdf": pdf_row, + "installed_plot_styles": installed, + } + + # ── bundled template over COM ───────────────────────────────────── + from engineering.standards.templates import resolve_template + + template_path, template_source = resolve_template("iso_a3_mech", "com") + opened = await backend.drawing_new(template=template_path) + await _opened_now(backend) + template_layers = {layer.name for layer in await backend.layer_list()} + current_dimstyles = [row["name"] for row in await backend.dimstyle_list() if row["current"]] + template_papers = [row["paper"] for row in await backend.page_setup_list()] + _check( + failures, + "template carries the mech layers", + {"GEOMETRY", "DIM", "CENTER", "HIDDEN", "TITLEBLOCK"} <= template_layers, + ) + _check(failures, "template has ISO-25 current", current_dimstyles == ["ISO-25"]) + _check(failures, "template has an ISO_A3 page setup", "ISO_A3" in template_papers) + report["template"] = { + "path": str(template_path), + "source": template_source, + "document": opened["name"], + "dimstyle_current": current_dimstyles, + "papers": template_papers, + } + await _close_ours(backend, opened["name"]) + activated = await backend.document_activate(smoke_document) + _check(failures, "smoke document re-activated", activated["active"] == smoke_document) + report["documents"] = await backend.document_list() + + # ── layer state round trip ──────────────────────────────────────── + await backend.layer_create("SMOKE_A", color=1) + await backend.layer_create("SMOKE_B", color=2) + saved = await backend.layer_state_save("SMOKE", description="settings smoke") + await backend.layer_modify("SMOKE_A", color=5) + await backend.layer_freeze("SMOKE_B") + restored = await backend.layer_state_restore("SMOKE") + after = {layer.name: layer for layer in await backend.layer_list()} + _check(failures, "layer state restored the colour", after["SMOKE_A"].color == 1) + _check(failures, "layer state thawed SMOKE_B", after["SMOKE_B"].is_frozen is False) + _check(failures, "restore reports nothing missing", restored["missing_layers"] == []) + _check( + failures, + "restore applied every layer", + restored["applied"]["layers"] == saved["layer_count"], + ) + _check(failures, "restore raised no warnings", "warnings" not in restored) + states = await backend.layer_state_list() + _check(failures, "layer state listed", any(row["name"] == "SMOKE" for row in states)) + deleted = await backend.layer_state_delete("SMOKE") + report["layer_state"] = {"saved": saved, "restored": restored, "deleted": deleted} + + # ── named view ──────────────────────────────────────────────────── + view = await backend.view_named_save("SMOKE_VIEW", center=[100.0, 50.0], height=80.0) + views = await backend.view_named_list() + _check(failures, "named view listed", any(row["name"] == "SMOKE_VIEW" for row in views)) + report["view"] = {"saved": view, "restored": await backend.view_named_restore("SMOKE_VIEW")} + + # ── UCS ─────────────────────────────────────────────────────────── + ucs = await backend.ucs_set( + "SMOKE_UCS", [10.0, 20.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0] + ) + ucs_rows = await backend.ucs_list() + _check( + failures, + "ucs current", + any(row["name"] == "SMOKE_UCS" and row["current"] for row in ucs_rows), + ) + try: + await backend.ucs_set("SMOKE_BAD", [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0]) + _check(failures, "non-orthogonal UCS refused", False) + except ValueError as exc: + _check(failures, "non-orthogonal UCS refusal names the angle", "45" in str(exc)) + report["ucs"] = {"set": ucs, "world": await backend.ucs_restore("world")} + + # ── preferences: get, one reversible set, a read-only refusal ───── + prefs = await backend.preferences_get() + cursor = int(prefs["values"]["Display.CursorSize"]) + probe = cursor + 1 if cursor < 100 else cursor - 1 + bumped = await backend.preferences_set("Display.CursorSize", probe) + reverted = await backend.preferences_set("Display.CursorSize", cursor) + _check(failures, "preference set reports old", bumped["old"] == cursor) + _check(failures, "preference set reports new", bumped["new"] == probe) + _check(failures, "preference reverted", reverted["new"] == cursor) + _check(failures, "read-only keys listed", "Files.SupportPath" in prefs["read_only"]) + try: + await backend.preferences_set("Files.SupportPath", "C:/nope") + _check(failures, "read-only preference refused", False) + except ValueError: + _check(failures, "read-only preference refused", True) + report["preferences"] = { + "cursor_size": cursor, + "read_only": prefs["read_only"], + "template_dwg_path": prefs["values"].get("Files.TemplateDwgPath"), + } + + # ── SummaryInfo ─────────────────────────────────────────────────── + written = await backend.drawing_properties_set( + summary={"title": "ACADMCP settings smoke", "author": "smoke_settings_com.py"}, + custom={"ACADMCP_SMOKE": "1"}, + ) + props = await backend.drawing_properties_get() + _check(failures, "summary available on COM", props["summary_available"] is True) + _check(failures, "title round trip", props["summary"]["title"] == "ACADMCP settings smoke") + _check(failures, "custom property round trip", props["custom"].get("ACADMCP_SMOKE") == "1") + report["properties"] = {"set": written, "get": props} + + # ── operator prompt line ────────────────────────────────────────── + report["prompt_message"] = await backend.system_prompt_message( + "ACADMCP settings smoke: done" + ) + + if args.interactive: + picked = await backend.user_pick_point("ACADMCP smoke: pick any point (Esc cancels)") + report["user_pick_point"] = picked + _check( + failures, + "pick returns a point, cancelled or timed_out", + bool(picked.get("cancelled")) + or bool(picked.get("timed_out")) + or ("x" in picked and "y" in picked), + ) + + report["failures"] = failures + print(json.dumps(report, indent=2, default=str)) + if not args.keep: + await _close_ours(backend, smoke_document) + return 0 if not failures else 1 + finally: + if not args.keep: + await _close_leftovers(backend) + await backend.disconnect() + + +def _parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(description=__doc__.split("\n\n")[0]) + parser.add_argument("--build-dwt", action="store_true", help="build templates/*.dwt first") + parser.add_argument("--interactive", action="store_true", help="also run user_pick_point") + parser.add_argument("--keep", action="store_true", help="leave the smoke document open") + return parser + + +if __name__ == "__main__": + raise SystemExit(asyncio.run(main(_parser().parse_args()))) diff --git a/templates/README.md b/templates/README.md index 9528d5a..1a5825d 100644 --- a/templates/README.md +++ b/templates/README.md @@ -26,7 +26,7 @@ listed by `drawing_template_list`. Start from one with - `.dwt` — the live twin, used by `drawing_new(template=…)` on the COM backend. AutoCAD's DWT is a DWG container, which no headless library writes, so these are produced **on the live machine** by - `uv run --frozen python scripts/smoke_settings_com.py --build-dwt` (Task 24's + `uv run --frozen python scripts/smoke_settings_com.py --build-dwt` (Task 25's smoke): it opens each DXF over COM and calls `drawing_template_save(…dwt)` (`SaveAs(path, ac2018_Template)`), then the files are committed once. While a `.dwt` is missing, `resolve_template` falls back to the DXF and reports @@ -43,3 +43,9 @@ to CRLF so a checkout on any platform equals a fresh build. Rebuild after changing anything the build depends on (layer sets, the title block, the dimension presets, the settings facade) and commit the result together with the change — the reproducibility test is the gate. + +The `.dwt` twins were built on 2026-09-22 on AutoCAD 2026 by +`scripts/smoke_settings_com.py --build-dwt` — each DXF opened over COM and +saved as a template (`AcSaveAsType` 66, `ac2018_Template`). Rebuild them the +same way after changing a DXF; `scripts/build_templates.py --check` gates the +DXF side only. diff --git a/templates/ansi_b_mech.dwt b/templates/ansi_b_mech.dwt new file mode 100644 index 0000000000000000000000000000000000000000..001b9ea80cec7cf89b8beca8828d4c9d2d3788e8 GIT binary patch literal 17250 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 NC><)#zw*CM{15b%AFcoZ literal 0 HcmV?d00001 diff --git a/templates/ansi_d_arch.dwt b/templates/ansi_d_arch.dwt new file mode 100644 index 0000000000000000000000000000000000000000..54ce5dd4fc9d3d1c64b7791f2b13e009374c4f07 GIT binary patch literal 17278 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 literal 0 HcmV?d00001 diff --git a/templates/iso_a1_arch.dwt b/templates/iso_a1_arch.dwt new file mode 100644 index 0000000000000000000000000000000000000000..dcf15bacf6e9379cdb4f2c55503aba1ce67f3c83 GIT binary patch literal 17281 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