83f192ac2ff4bed642a8d20fbe4ff68c43aab8a0
2
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
301610620c |
fix(task-14): detach an xref out of every space, and stop the live engine inventing facts
Three blocking findings on the refs group, all of them the same shape: a number or a refusal the caller was entitled to read as measured. 1. ezdxf xref_manage: the victim scan and the `inserts` count both walked `doc.modelspace()` only, then dropped the definition with `delete_block(safe=False)` -- the flag that suppresses the in-use check. An xref shown on a paper-space sheet was reported as 1 insert where the drawing held 2, and detaching it left that sheet INSERT with no BLOCK behind it: `ezdxf.recover` reports `FIX 103 UNDEFINED_BLOCK: Deleted entity INSERT(#34) without required BLOCK definition` and the repo's own drawing_audit silently deletes the sheet geometry. The scan now walks `doc.blocks`, which is every entity space (model space, each paper-space tab, every block definition) and is exactly what ezdxf's own safe check searches with `doc.query('INSERT[name==...]i')` -- hence the case-insensitive name match. `delete_block` is now `safe=True`, as the plan's Interfaces block pins it, so a future miss raises instead of writing a corrupt file. 2. COM xref_manage(action='list') reported `kind: "attach"` for every row, a literal constant. Re-measured on this seat's registered type library (C:\Program Files\Common Files\Autodesk Shared\acax25*.tlb, "AutoCAD 2025 Type Library", installed with AutoCAD 2026): IAcadBlock's xref members are exactly IsXRef, Path, Name, Reload, Unload, Bind, Detach, XRefDatabase -- no overlay indicator exists on the interface, so an overlay was reported to the client as an attachment. The row now says `kind: None`, the same honesty the adjacent `inserts` field already had, and the contract plus the tool docstring say so. 3. COM xref_attach had no duplicate-block-name guard, although contracts/refs.py and the tool docstring both promise the refusal and ezdxf implements it. Two different part.dwg files, or a re-attach after a repath, silently re-pointed or half-wrote the definition while the payload claimed the new path. Added `_block_names(doc)` (Blocks.Count / Blocks.Item(index) / block.Name -- the members xref_manage already walks) and the refusal fires before AttachExternalReference is dispatched, with the same message the headless engine gives. Lower-cased, because AutoCAD symbol-table names are case-insensitive. Tests: five new ones, each failing against the unfixed backends -- an xref shown on Layout1 is counted and detached with the drawing, the detached file audits clean through ezdxf.recover, delete_block's in-use check is pinned, the live listing reports kind None (against a fake that models only the measured members, so it cannot enshrine an invented one), and the live attach refuses a held name (xref and plain block, either case) without dispatching. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd |
||
|
|
3ef316d520 |
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
|