feat(refs): xrefs, raster underlays, data extract and real DWG output
SECTION 24 completes at eleven tools with xref_attach, xref_manage,
image_attach, data_extract and drawing_export_dwg, on the four contract members
that genuinely differ per engine -- backends/contracts/refs.py. Everything else
in the sheet track composes the generic members and is written once.
The ActiveX members were read off the AutoCAD 2026 seat's own type library
(C:\Program Files\Common Files\Autodesk Shared\acax25enu.tlb, "AutoCAD 2025
Type Library" 1.0, the library the running 25.x seat registers) before a line of
the COM path was written, and the measurement is in the code beside the calls:
IAcadModelSpace.AttachExternalReference(PathName, Name, InsertionPoint,
Xscale, Yscale, Zscale, Rotation, bOverlay, Password)
IAcadModelSpace.AddRaster(imageFileName, InsertionPoint, ScaleFactor,
RotationAngle)
IAcadBlock: IsXRef (get), Path (get AND put -- so the repath is an assignment,
not a method), Reload(), Unload(), Bind(bPrefixName), Detach(),
XRefDatabase (get)
IAcadDocument.SaveAs(FullFileName, SaveAsType, vSecurityParams)
AcSaveAsType: ac2000_dwg=12 ac2004_dwg=24 ac2007_dwg=36 ac2010_dwg=48
ac2013_dwg=60 ac2018_dwg=64 (=acNative)
The running seat itself was not answering COM while this landed (its window was
Not Responding and GetActiveObject never returned), so the type library -- which
is the same seat's declared surface and reads without a call into the process --
is what the members are measured from; no document of the operator's was opened
or touched. This repository has been bitten four times by a fake that invented a
member, so the COM fakes in the tests model those names and nothing else.
ActiveX angles are radians, so the degree-to-radian conversion happens at that
boundary and nowhere else.
Headlessly, ezdxf.xref.attach carries the attachment (measured on ezdxf 1.4.4:
block flags 20 for an attachment and 24 for an overlay, so "is this an xref" is
flags & (BLK_XREF | BLK_XREF_OVERLAY) -- masking BLK_XREF alone misses every
overlay), add_image_def + add_image the raster, with Pillow reading the pixel
size so the placed image keeps the file's aspect.
Three capability keys, declared in both maps:
dwg_write -- measured absent here (odafc.is_installed() is False), so the
ezdxf entry is a runtime re-evaluation like viewport_render's
matplotlib check rather than a hardcoded False: installing the
ODA File Converter starts the call working with no edit to the
map. The refusal names the install route and drawing_export_dxf.
xref_live -- reload and bind need a live seat's xref manager and are refused
headlessly; list, detach and path are headless and are not
behind the key.
xlsx_write -- openpyxl is optional and absent here; CSV is always available,
so the refusal never blocks the deliverable and says so.
Two numbers the plan predicted wrongly are corrected to what the registry
actually does. `block` outranks `drawing` in _GROUP_TAG_PRIORITY, so the two
xref tools file under `blocks` (9 -> 11) beside block_insert -- which is where
an xref belongs, being a block definition that lives in another file -- and
`drawing` moves 11 -> 12, not 11 -> 14. And `data_extract` must not say "parts
list" in its own text: that is the golden discovery query for
entity_create_table, and a file writer outranking the tool that draws the thing
is a regression the tuning bar catches. It is described by its destination --
a file -- instead.
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
de8dc8f813
commit
3ef316d520
@@ -495,7 +495,7 @@ async def test_tool_groups_is_byte_identical_to_the_source_declared_grouping():
|
||||
|
||||
|
||||
async def test_tool_group_sizes_are_unchanged():
|
||||
"""Frozen snapshot of the surface (210 tools, 23 groups).
|
||||
"""Frozen snapshot of the surface (215 tools, 23 groups).
|
||||
|
||||
Taken before @cad_tool landed at 131 tools; `batch` moved 2 -> 3 when
|
||||
v1.5.0's `cad_batch` joined `entity_batch_create`/`entity_batch_modify`, and
|
||||
@@ -537,6 +537,15 @@ async def test_tool_group_sizes_are_unchanged():
|
||||
It moved 12 -> 16 when `revision_add`, `bom_extract`, `bom_table` and
|
||||
`balloon_add` joined the same section; `bom_extract` also carries `query`,
|
||||
but `engineering` outranks it in `_GROUP_TAG_PRIORITY`.
|
||||
The section's last five tools file elsewhere on purpose: they are
|
||||
whole-drawing and entity operations, not sheet furniture, and
|
||||
`_GROUP_TAG_PRIORITY` files them where a caller would look.
|
||||
`xref_attach` and `xref_manage` carry `drawing` *and* `block`, and `block`
|
||||
outranks `drawing`, so they file under `blocks` (9 -> 11) beside
|
||||
`block_insert` -- which is where an xref belongs: it is a block definition
|
||||
that lives in another file. `image_attach` carries `create`
|
||||
(entity_creation 18 -> 19), `data_extract` carries `engineering`
|
||||
(16 -> 17) and `drawing_export_dwg` carries `drawing` alone (11 -> 12).
|
||||
Every other number here has been unchanged
|
||||
since the snapshot was taken.
|
||||
"""
|
||||
@@ -544,12 +553,12 @@ async def test_tool_group_sizes_are_unchanged():
|
||||
assert sizes == {
|
||||
"analysis": 12,
|
||||
"batch": 3,
|
||||
"blocks": 9,
|
||||
"blocks": 11,
|
||||
"corner_ops": 4,
|
||||
"dimensions": 5,
|
||||
"drawing": 11,
|
||||
"engineering": 16,
|
||||
"entity_creation": 18,
|
||||
"drawing": 12,
|
||||
"engineering": 17,
|
||||
"entity_creation": 19,
|
||||
"entity_modification": 16,
|
||||
"entity_query": 9,
|
||||
"environment": 22,
|
||||
@@ -566,4 +575,4 @@ async def test_tool_group_sizes_are_unchanged():
|
||||
"validation": 1,
|
||||
"view": 4,
|
||||
}
|
||||
assert sum(sizes.values()) == 210
|
||||
assert sum(sizes.values()) == 215
|
||||
|
||||
Reference in New Issue
Block a user