feat(templates): drawing_template_save on both engines — dwt_write is a declared capability
Live AutoCAD writes a real .dwt through SaveAs(path, ac2018_Template = 66) and puts the description into the summary Comments; headlessly a .dxf template is written through drawing_save_as and a .dwt request is refused with capability dwt_write, naming the DXF route and the COM route. drawing_save_as's "dwt" entry was 5 (acR13_dxf): a DWT request wrote an R13 DXF under a .dwt name. Probed live on AutoCAD 2026 (typelib: ac2018_Template = 66, acR13_dxf = 5, acTemplateDwg absent; the saved file starts AC1032, the document is rebound, Comments takes). SECTION 19 is now 6 tools; SAVEAS joins SHARED_ACAD_COMMANDS; templates/README.md documents the two files per template. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd
This commit is contained in:
co-authored by
Claude Opus 5
parent
17f7228fd6
commit
b458923e19
@@ -123,6 +123,18 @@ _DWG_WRITE_REFUSAL = (
|
||||
)
|
||||
|
||||
|
||||
# A DWT is a DWG container with a template flag. ezdxf cannot write it, and a
|
||||
# DXF under a .dwt name is exactly the mislabelled file the DWG refusal exists
|
||||
# to prevent. The DXF route works headlessly end to end: drawing_new(template=)
|
||||
# opens a .dxf template.
|
||||
_DWT_WRITE_REFUSAL = (
|
||||
"drawing_template_save: the headless ezdxf backend cannot write DWT — a .dwt is a DWG "
|
||||
"container, and ezdxf has no DWG writer. Save the template as .dxf instead "
|
||||
"(drawing_new(template='{stem}.dxf') opens it headlessly), or switch to the live COM "
|
||||
"backend (AUTOCAD_MCP_BACKEND=com, needs Windows + AutoCAD) for a real .dwt."
|
||||
)
|
||||
|
||||
|
||||
def _is_dwg_path(path: str) -> bool:
|
||||
"""True when `path` names a DWG file. The extension is authoritative (N2)."""
|
||||
return Path(path).suffix.lower() == ".dwg"
|
||||
@@ -2687,10 +2699,39 @@ class EzdxfBackend(AutoCADBackend):
|
||||
return [{"name": name, "source": "catalog", "installed": None} for name in CTB_CATALOG]
|
||||
|
||||
async def drawing_template_save(self, path, name=None, description=None) -> dict:
|
||||
# Completed in Task 20; declared here so the ABC instantiates.
|
||||
raise UnsupportedCapabilityError(
|
||||
"dwt_write", "drawing_template_save: not implemented yet (Task 20)"
|
||||
)
|
||||
"""Save the current drawing as a template — DXF only, headlessly.
|
||||
|
||||
``.dwt`` is refused with capability ``dwt_write`` before anything is
|
||||
written; ``.dxf`` goes through ``drawing_save_as`` (the document is
|
||||
rebound to the new path, as AutoCAD's SAVEAS does). A description has
|
||||
no home in a DXF header — it is a DWG/DWT summary property — so it is
|
||||
reported ``description_written: False`` rather than dropped silently.
|
||||
"""
|
||||
suffix = Path(path).suffix.lower()
|
||||
if suffix == ".dwt":
|
||||
raise UnsupportedCapabilityError(
|
||||
"dwt_write", _DWT_WRITE_REFUSAL.format(stem=Path(path).stem)
|
||||
)
|
||||
if suffix != ".dxf":
|
||||
raise ValueError(
|
||||
f"drawing_template_save: path must end in .dxf (headless) or .dwt (live "
|
||||
f"AutoCAD), got {path!r}"
|
||||
)
|
||||
saved = await self.drawing_save_as(path, "dxf")
|
||||
result = {
|
||||
"ok": True,
|
||||
"path": saved["path"],
|
||||
"format": "dxf",
|
||||
"backend": "ezdxf",
|
||||
"name": name or Path(path).stem,
|
||||
"description_written": False,
|
||||
}
|
||||
if description is not None:
|
||||
result["description_note"] = (
|
||||
"DXF has no template description field; it is a DWG/DWT summary property "
|
||||
"(capability 'dwgprops')"
|
||||
)
|
||||
return result
|
||||
|
||||
# ── 3D solids (unsupported headlessly — honest capability boundary) ─────
|
||||
|
||||
|
||||
Reference in New Issue
Block a user