fix(task-10): $DIMBLK header carries the canonical arrowhead name; MLeaderStyle is authored on COM through the ACAD_MLEADERSTYLE dictionary
Two review findings, both root causes.
1. `_sync_header_to_dimstyle` copied the DIMSTYLE entry's ezdxf-internal
arrowhead spelling (OBLIQUE) into the DXF-facing $DIMBLK/$DIMBLK1/$DIMBLK2
header, so the saved file named a block it did not hold (the blocks are
_OBLIQUE / _DOT) and `system_get_variable("DIMBLK")` answered "OBLIQUE"
headlessly against "_OBLIQUE" on COM and in the same engine's own
`dimstyle_list` row. The header write now goes through
`reported_arrowhead` — the same read-side rule `_dimstyle_value` applies.
Pinned by header, `system_get_variable`, save/reopen (`ezdxf.readfile`
header equals the block the file holds) and the Restore-to-Standard
empty-string case in `test_builtin_arrowheads_render_save_and_report_one_spelling`.
2. The `mleaderstyle` capability refusal rested on a false engine boundary.
acax25enu.tlb (AutoCAD 2026) exposes IAcadMLeaderStyle with Name,
ArrowSize, LandingGap, TextHeight, TextStyle, ... — exactly what
`Dictionaries.Item("ACAD_MLEADERSTYLE").Item(i)` returns — and
IAcadDictionary.AddObject(keyword, "AcDbMLeaderStyle") creates one.
COM `mleaderstyle_list` now reads the four values off those objects
(`values_available: True`); COM `mleaderstyle_create` validates every value
(`validate_mleaderstyle`, shared with ezdxf), checks the clash and the text
style before AddObject, then writes the four properties. The contract
method is `@abstractmethod` again, the key is gone from both capability
maps, the fake ActiveX surface models the real call shape, and the spec
(§4.2, §8.1, §9) states the ActiveX route.
Live AutoCAD was not running on this machine (GetActiveObject: operation
unavailable; no acad.exe), so the COM route is type-library-verified and
fake-tested, not executed live — scripts/smoke_settings_com.py (Task 24)
owns that.
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
4d246b17b8
commit
e204f227b4
@@ -14,8 +14,6 @@ from __future__ import annotations
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
from backends.capability import capability
|
||||
|
||||
|
||||
class StylesContract(ABC):
|
||||
@abstractmethod
|
||||
@@ -115,29 +113,24 @@ class StylesContract(ABC):
|
||||
async def mleaderstyle_list(self) -> list[dict]:
|
||||
"""``[{name, arrow_size, landing_gap, text_style, text_height, values_available}]``.
|
||||
|
||||
Headless the values are read from the MLEADERSTYLE object (schema
|
||||
defaults for an unset field). ActiveX exposes no MLeaderStyle object,
|
||||
so the live engine reads the *names* from the ``ACAD_MLEADERSTYLE``
|
||||
dictionary and reports the four values ``None`` with
|
||||
``values_available: False``.
|
||||
Both engines report the four values (``values_available: True``).
|
||||
Headless they are read from the MLEADERSTYLE object (schema defaults
|
||||
for an unset field); live from the ``AcadMLeaderStyle`` objects the
|
||||
``ACAD_MLEADERSTYLE`` dictionary holds (``ArrowSize`` / ``LandingGap``
|
||||
/ ``TextHeight`` in drawing units, ``TextStyle`` a name) — ActiveX
|
||||
exposes no *collection* property for them, but the dictionary items
|
||||
are full ``IAcadMLeaderStyle`` objects.
|
||||
"""
|
||||
...
|
||||
|
||||
# B027 (empty method, no @abstractmethod) is what this pattern looks like
|
||||
# from the outside: the decorator replaces the `...` body with the refusing
|
||||
# default, so the source really is empty on purpose.
|
||||
@capability( # noqa: B027
|
||||
"mleaderstyle",
|
||||
reason=(
|
||||
"ActiveX exposes no MLeaderStyle collection; use leader_create_mleader's "
|
||||
"per-leader parameters (arrow size, landing, text height) or the headless "
|
||||
"backend (AUTOCAD_MCP_BACKEND=ezdxf)"
|
||||
),
|
||||
)
|
||||
@abstractmethod
|
||||
async def mleaderstyle_create(self, name: str, values: dict) -> dict:
|
||||
"""Create a multileader style from a resolved ``values`` dict
|
||||
(``engineering.standards.mleaderstyles.resolve_mleaderstyle``).
|
||||
ezdxf only. Returns ``{ok, name, values, textstyle_created}``; the
|
||||
text style follows the ``dimstyle_create`` rule (exists or preset,
|
||||
else refused by name); a clash is refused."""
|
||||
Both engines: ezdxf on ``doc.mleader_styles``; live through
|
||||
``Dictionaries.Item("ACAD_MLEADERSTYLE").AddObject(name,
|
||||
"AcDbMLeaderStyle")`` and the object's property writes. Returns
|
||||
``{ok, name, values, textstyle_created}``; the text style follows the
|
||||
``dimstyle_create`` rule (exists or preset, else refused by name); a
|
||||
clash is refused — before anything is written."""
|
||||
...
|
||||
|
||||
Reference in New Issue
Block a user