fix(task-10): user dimstyles survive DXF round trips, purge keeps style references, Restore writes every DIM* variable
Three headless defects in the styles block, each measured before the fix:
* `_normalise_dimstyle_rounding` cleaned `Standard` only, while ezdxf's
exporter writes DIMRND 0.0 for every DIMSTYLE. A user style (ISO-25 / ANSI)
came back from save/open, transaction_rollback and drawing_undo rounding
every dimension to a whole unit ("33" for 33.333, "R6" for R6.35) with
dimstyle_list still reporting DIMDEC 2. It now walks the whole table.
* `drawing_purge` followed only entity `.dxf.style`, so it deleted the text
style a DIMSTYLE (DIMTXSTY), an MLEADERSTYLE (text_style_handle) or the
header ($TEXTSTYLE / $DIMTXSTY) referenced; the next dimension silently
rendered in Standard and drawing_save_as raised DXFTableEntryError after
leaving a truncated file. `_style_table_references` now counts those, plus
the arrowhead blocks a DIMSTYLE / MLEADERSTYLE / MULTILEADER references,
compared case-insensitively.
* `_sync_header_to_dimstyle` wrote only the attributes the target style
stores, leaving the previous style's $DIM* in the header — folded onto the
next dimension by `_with_header_dimvars` (ISO-25 DIMZIN 0 / DIMSCALE 2.0
then Restore Standard rendered 5.0 mm "33.30") and written to the file as
current-style overrides; $DIMRND 0.5 outlived the style's own discard. It
now writes the schema default for every whitelist variable the style omits
(`Standard` for DIMTXSTY), which reproduces a fresh header exactly.
tests/test_styles.py: the reopen test now renders a dimension after the
reopen, plus one test per defect; all four fail on the previous backend.
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
cc3bd4876b
commit
2ee18727cd
+115
-15
@@ -387,15 +387,26 @@ def _normalise_dimstyle_rounding(doc) -> None:
|
|||||||
itself — silently rounded every dimension to a whole unit *before* DIMDEC
|
itself — silently rounded every dimension to a whole unit *before* DIMDEC
|
||||||
got to format it: a 12.75 mm feature dimensioned as 13, R6.35 as R6.
|
got to format it: a 12.75 mm feature dimensioned as 13, R6.35 as R6.
|
||||||
|
|
||||||
|
Every style in the table, not `Standard` alone: ezdxf's exporter writes
|
||||||
|
group 45 = 0.0 for *each* DIMSTYLE entry, so a user style (the ISO-25 /
|
||||||
|
ANSI presets `dimstyle_create` makes) came back poisoned from every DXF
|
||||||
|
round trip — save/open, `transaction_rollback`, `drawing_undo` — and a
|
||||||
|
33.333 mm feature dimensioned with it rendered "33" while `dimstyle_list`
|
||||||
|
still reported DIMDEC 2. Measured before this ran on the whole table.
|
||||||
|
|
||||||
Only the 0.0 sentinel is removed. A drafter who genuinely asked for 0.5 mm
|
Only the 0.0 sentinel is removed. A drafter who genuinely asked for 0.5 mm
|
||||||
rounding keeps it.
|
rounding keeps it.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
style = doc.dimstyles.get("Standard")
|
styles = list(doc.dimstyles)
|
||||||
except Exception:
|
except Exception:
|
||||||
return
|
return
|
||||||
if style.dxf.hasattr("dimrnd") and float(style.dxf.dimrnd) == 0.0:
|
for style in styles:
|
||||||
style.dxf.discard("dimrnd")
|
try:
|
||||||
|
if style.dxf.hasattr("dimrnd") and float(style.dxf.dimrnd) == 0.0:
|
||||||
|
style.dxf.discard("dimrnd")
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
continue
|
||||||
|
|
||||||
|
|
||||||
def _apply_iso_dimstyle(doc) -> None:
|
def _apply_iso_dimstyle(doc) -> None:
|
||||||
@@ -801,17 +812,42 @@ def _write_dimstyle_values(style, values: dict[str, Any]) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def _sync_header_to_dimstyle(doc, style) -> None:
|
def _sync_header_to_dimstyle(doc, style) -> None:
|
||||||
"""Load the style's stored variables into ``$DIM*`` — a live seat's Restore."""
|
"""Load the style into ``$DIM*`` — every whitelist variable, a live seat's Restore.
|
||||||
|
|
||||||
|
``-DIMSTYLE Restore`` replaces *all* the DIM* system variables with the
|
||||||
|
style's settings; a DIMSTYLE entry that omits a code means its schema
|
||||||
|
default. Writing only the attributes the style *stores* left every other
|
||||||
|
``$DIM*`` at the previous style's value — measured, ISO-25 with DIMZIN 0 /
|
||||||
|
DIMSCALE 2.0 made current and then ``dimstyle_set_current("Standard")``
|
||||||
|
rendered the next dimension at 5.0 mm as "33.30": `_with_header_dimvars`
|
||||||
|
folded the stale header onto it, and the saved file carried the same
|
||||||
|
values next to ``$DIMSTYLE Standard``, which AutoCAD reads as overrides.
|
||||||
|
The same gap kept ``$DIMRND 0.5`` in the header after `dimstyle_modify`
|
||||||
|
discarded the style's own attribute.
|
||||||
|
|
||||||
|
Measured on ezdxf 1.4.4: a fresh header equals the schema default for
|
||||||
|
every whitelist variable a fresh `Standard` does not store, so restoring
|
||||||
|
`Standard` reproduces the header `drawing_new` made. `DIMTXSTY` has no
|
||||||
|
schema default; AutoCAD reads ``Standard`` for it, as `_dimstyle_value`
|
||||||
|
reports.
|
||||||
|
"""
|
||||||
from engineering.standards.dimstyles import DIM_VARIABLE_WHITELIST
|
from engineering.standards.dimstyles import DIM_VARIABLE_WHITELIST
|
||||||
|
|
||||||
for var in sorted(DIM_VARIABLE_WHITELIST):
|
for var in sorted(DIM_VARIABLE_WHITELIST):
|
||||||
attr = var.lower()
|
attr = var.lower()
|
||||||
if not style.dxf.hasattr(attr):
|
value = style.dxf.get(attr) if style.dxf.hasattr(attr) else None
|
||||||
|
if value is None:
|
||||||
|
value = _dimstyle_schema_default(var)
|
||||||
|
if value is None and var == "DIMTXSTY":
|
||||||
|
value = "Standard"
|
||||||
|
key = f"${var}"
|
||||||
|
if value is None:
|
||||||
|
try:
|
||||||
|
del doc.header[key]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
continue
|
continue
|
||||||
raw = style.dxf.get(attr)
|
doc.header[key] = value
|
||||||
if raw is None:
|
|
||||||
continue
|
|
||||||
doc.header[f"${var}"] = raw
|
|
||||||
|
|
||||||
|
|
||||||
def _font_available(font_file: str) -> bool:
|
def _font_available(font_file: str) -> bool:
|
||||||
@@ -859,6 +895,57 @@ def _dimensions_using(doc, style_name: str) -> list[str]:
|
|||||||
return handles
|
return handles
|
||||||
|
|
||||||
|
|
||||||
|
def _style_table_references(doc) -> tuple[set[str], set[str]]:
|
||||||
|
"""``(block names, text-style names)`` the style tables and header reference.
|
||||||
|
|
||||||
|
Lower-cased, for `drawing_purge`. A DIMSTYLE names its text style and up
|
||||||
|
to four arrowhead blocks (stored in ezdxf's spelling, ``OBLIQUE``, while
|
||||||
|
the block is ``_OBLIQUE`` — both spellings are counted); an MLEADERSTYLE
|
||||||
|
references its text style and arrowhead by handle; the header names the
|
||||||
|
current text style and dimension text style. ``Standard`` is never purged.
|
||||||
|
"""
|
||||||
|
blocks: set[str] = set()
|
||||||
|
styles: set[str] = {"standard"}
|
||||||
|
|
||||||
|
def _add_block(name) -> None:
|
||||||
|
if isinstance(name, str) and name:
|
||||||
|
lowered = name.lower()
|
||||||
|
blocks.add(lowered)
|
||||||
|
blocks.add(lowered if lowered.startswith("_") else f"_{lowered}")
|
||||||
|
|
||||||
|
def _add_style(name) -> None:
|
||||||
|
if isinstance(name, str) and name:
|
||||||
|
styles.add(name.lower())
|
||||||
|
|
||||||
|
def _add_by_handle(handle, into) -> None:
|
||||||
|
entity = doc.entitydb.get(handle) if handle else None
|
||||||
|
if entity is not None:
|
||||||
|
into(entity.dxf.get("name"))
|
||||||
|
|
||||||
|
try:
|
||||||
|
for var in ("$TEXTSTYLE", "$DIMTXSTY"):
|
||||||
|
_add_style(doc.header.get(var, None))
|
||||||
|
for var in ("$DIMBLK", "$DIMBLK1", "$DIMBLK2", "$DIMLDRBLK"):
|
||||||
|
_add_block(doc.header.get(var, None))
|
||||||
|
except Exception: # an opened document may not have a readable header
|
||||||
|
pass
|
||||||
|
for style in doc.dimstyles:
|
||||||
|
_add_style(style.dxf.get("dimtxsty"))
|
||||||
|
for attr in ("dimblk", "dimblk1", "dimblk2", "dimldrblk"):
|
||||||
|
_add_block(style.dxf.get(attr))
|
||||||
|
for _name, style in doc.mleader_styles:
|
||||||
|
_add_by_handle(style.dxf.get("text_style_handle"), _add_style)
|
||||||
|
_add_by_handle(style.dxf.get("arrow_head_handle"), _add_block)
|
||||||
|
for entity in doc.entitydb.values():
|
||||||
|
if entity.dxftype() != "MULTILEADER":
|
||||||
|
continue
|
||||||
|
context = getattr(entity, "context", None)
|
||||||
|
_add_by_handle(getattr(context, "text_style_handle", None), _add_style)
|
||||||
|
for arrow in getattr(entity, "arrow_heads", None) or ():
|
||||||
|
_add_by_handle(getattr(arrow, "handle", None), _add_block)
|
||||||
|
return blocks, styles
|
||||||
|
|
||||||
|
|
||||||
def _round_measure(result: dict) -> dict:
|
def _round_measure(result: dict) -> dict:
|
||||||
"""Six decimal places, matching analysis_measure_distance."""
|
"""Six decimal places, matching analysis_measure_distance."""
|
||||||
result["area"] = round(float(result["area"]), 6)
|
result["area"] = round(float(result["area"]), 6)
|
||||||
@@ -2538,17 +2625,31 @@ class EzdxfBackend(AutoCADBackend):
|
|||||||
raise self._solid_unsupported("solid_boolean")
|
raise self._solid_unsupported("solid_boolean")
|
||||||
|
|
||||||
async def drawing_purge(self) -> dict:
|
async def drawing_purge(self) -> dict:
|
||||||
|
"""Delete every unreferenced block, layer, linetype and text style.
|
||||||
|
|
||||||
|
A reference is not only an entity's own attribute. The style tables
|
||||||
|
reference each other — a DIMSTYLE names its text style (DIMTXSTY) and
|
||||||
|
its arrowhead blocks, an MLEADERSTYLE holds a text-style handle — and
|
||||||
|
the header names the current text style (``$TEXTSTYLE``, ``$DIMTXSTY``).
|
||||||
|
Measured before those were counted: ``dimstyle_create("ISO-25", …,
|
||||||
|
set_current=True)`` then ``drawing_purge()`` removed ISOCP, the next
|
||||||
|
dimension silently rendered in ``Standard`` while `dimstyle_list` still
|
||||||
|
said ISOCP, and ``drawing_save_as`` raised ``DXFTableEntryError`` after
|
||||||
|
leaving a truncated file on disk. Names are compared case-insensitively,
|
||||||
|
AutoCAD's rule for every symbol table.
|
||||||
|
"""
|
||||||
|
|
||||||
def _sync():
|
def _sync():
|
||||||
doc = self._require_doc()
|
doc = self._require_doc()
|
||||||
purged = {"blocks": 0, "layers": 0, "linetypes": 0, "text_styles": 0}
|
purged = {"blocks": 0, "layers": 0, "linetypes": 0, "text_styles": 0}
|
||||||
|
used_blocks, used_styles = _style_table_references(doc)
|
||||||
|
|
||||||
used_blocks: set[str] = set()
|
|
||||||
for ent in doc.entitydb.values():
|
for ent in doc.entitydb.values():
|
||||||
if ent.dxftype() == "INSERT":
|
if ent.dxftype() == "INSERT":
|
||||||
used_blocks.add(ent.dxf.name)
|
used_blocks.add(str(ent.dxf.name).lower())
|
||||||
for blk in list(doc.blocks):
|
for blk in list(doc.blocks):
|
||||||
name = blk.name
|
name = blk.name
|
||||||
if name.startswith("*") or name in used_blocks:
|
if name.startswith("*") or name.lower() in used_blocks:
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
doc.blocks.delete_block(name, safe=True)
|
doc.blocks.delete_block(name, safe=True)
|
||||||
@@ -2586,13 +2687,12 @@ class EzdxfBackend(AutoCADBackend):
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
used_styles: set[str] = {"Standard"}
|
|
||||||
for ent in doc.entitydb.values():
|
for ent in doc.entitydb.values():
|
||||||
if hasattr(ent.dxf, "style"):
|
if hasattr(ent.dxf, "style"):
|
||||||
used_styles.add(ent.dxf.style)
|
used_styles.add(str(ent.dxf.style).lower())
|
||||||
for st in list(doc.styles):
|
for st in list(doc.styles):
|
||||||
name = st.dxf.name
|
name = st.dxf.name
|
||||||
if name in used_styles:
|
if name.lower() in used_styles:
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
doc.styles.remove(name)
|
doc.styles.remove(name)
|
||||||
|
|||||||
@@ -12,8 +12,10 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import types
|
import types
|
||||||
|
|
||||||
|
import ezdxf
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
import config
|
||||||
from backends.base import UnsupportedCapabilityError
|
from backends.base import UnsupportedCapabilityError
|
||||||
from backends.capability import is_capability_default
|
from backends.capability import is_capability_default
|
||||||
from backends.ezdxf_backend import _current_dimstyle_name, _current_textstyle_name
|
from backends.ezdxf_backend import _current_dimstyle_name, _current_textstyle_name
|
||||||
@@ -187,6 +189,139 @@ async def test_dimstyle_set_current_reports_previous_and_survives_save_reopen(ba
|
|||||||
rows = await backend.dimstyle_list()
|
rows = await backend.dimstyle_list()
|
||||||
assert [r["name"] for r in rows if r["current"]] == ["ISO-25"]
|
assert [r["name"] for r in rows if r["current"]] == ["ISO-25"]
|
||||||
assert rows[0]["name"] == "ISO-25" and rows[0]["values"]["DIMDSEP"] == ","
|
assert rows[0]["name"] == "ISO-25" and rows[0]["values"]["DIMDSEP"] == ","
|
||||||
|
# The table's report was never the thing that could lie; the render is.
|
||||||
|
dim = await backend.dimension_linear(0, 0, 33.333, 0, 16, -30)
|
||||||
|
assert _rendered(backend, dim.handle) == ("33,33", 2.5, [2.5])
|
||||||
|
|
||||||
|
|
||||||
|
async def test_a_user_dimstyle_survives_every_dxf_round_trip_without_rounding(
|
||||||
|
backend, tmp_path, monkeypatch
|
||||||
|
):
|
||||||
|
"""ezdxf's exporter writes DIMRND 0.0 for *every* DIMSTYLE, and a stored 0.0
|
||||||
|
makes the renderer round every dimension to a whole unit. Measured before
|
||||||
|
`_normalise_dimstyle_rounding` walked the whole table: ISO-25 came back from
|
||||||
|
a save/open, a `transaction_rollback` and a `drawing_undo` rendering 33.333
|
||||||
|
as "33" and R6.35 as "R6" while `dimstyle_list` still reported DIMDEC 2."""
|
||||||
|
monkeypatch.setattr(config.settings, "ezdxf_undo_depth", 4)
|
||||||
|
await backend.drawing_new() # a history baseline with undo switched on
|
||||||
|
await backend.dimstyle_create("ISO-25", resolve_dimstyle("iso-25", None), set_current=True)
|
||||||
|
await backend.dimstyle_create("ANSI", resolve_dimstyle("ansi", None))
|
||||||
|
dim = await backend.dimension_linear(0, 0, 33.333, 0, 16, -30)
|
||||||
|
assert _rendered(backend, dim.handle) == ("33,33", 2.5, [2.5])
|
||||||
|
|
||||||
|
def _rounding_stored() -> dict[str, bool]:
|
||||||
|
return {s.dxf.name: s.dxf.hasattr("dimrnd") for s in backend._doc.dimstyles}
|
||||||
|
|
||||||
|
path = str(tmp_path / "roundtrip.dxf")
|
||||||
|
await backend.drawing_save_as(path)
|
||||||
|
assert ezdxf.readfile(path).dimstyles.get("ISO-25").dxf.get("dimrnd") == 0.0, (
|
||||||
|
"the premise: the file on disk carries the 0.0 sentinel for a user style"
|
||||||
|
)
|
||||||
|
await backend.drawing_open(path)
|
||||||
|
assert _rounding_stored() == {"Standard": False, "ISO-25": False, "ANSI": False}
|
||||||
|
reopened = await backend.dimension_linear(0, 0, 33.333, 0, 16, -60)
|
||||||
|
assert _rendered(backend, reopened.handle) == ("33,33", 2.5, [2.5])
|
||||||
|
radius = await backend.dimension_radius(50, 50, 56.35, 50)
|
||||||
|
assert _rendered(backend, radius.handle)[0] == "R6,35"
|
||||||
|
await backend.dimstyle_set_current("ANSI")
|
||||||
|
ansi = await backend.dimension_linear(0, 0, 12.75, 0, 6, -90)
|
||||||
|
assert _rendered(backend, ansi.handle)[0] == "12.75"
|
||||||
|
|
||||||
|
await backend.dimstyle_set_current("ISO-25")
|
||||||
|
await backend.transaction_begin()
|
||||||
|
await backend.entity_create_line(0, 0, 10, 10)
|
||||||
|
await backend.transaction_rollback()
|
||||||
|
assert _rounding_stored() == {"Standard": False, "ISO-25": False, "ANSI": False}
|
||||||
|
rolled_back = await backend.dimension_linear(0, 0, 33.333, 0, 16, -120)
|
||||||
|
assert _rendered(backend, rolled_back.handle) == ("33,33", 2.5, [2.5])
|
||||||
|
|
||||||
|
await backend.entity_create_line(0, 0, 20, 20)
|
||||||
|
assert (await backend.drawing_undo())["ok"] is True
|
||||||
|
assert _rounding_stored() == {"Standard": False, "ISO-25": False, "ANSI": False}
|
||||||
|
undone = await backend.dimension_linear(0, 0, 33.333, 0, 16, -150)
|
||||||
|
assert _rendered(backend, undone.handle) == ("33,33", 2.5, [2.5])
|
||||||
|
|
||||||
|
await backend.dimstyle_modify("ISO-25", {"DIMRND": 0.5})
|
||||||
|
await backend.drawing_save_as(path)
|
||||||
|
await backend.drawing_open(path)
|
||||||
|
assert backend._doc.dimstyles.get("ISO-25").dxf.dimrnd == 0.5, (
|
||||||
|
"only the 0.0 sentinel is discarded; a rounding the drafter asked for survives"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_drawing_purge_keeps_what_the_style_tables_and_header_reference(backend, tmp_path):
|
||||||
|
"""`drawing_purge` followed only entity `.dxf.style`; a text style that only
|
||||||
|
a DIMSTYLE, an MLEADERSTYLE or the header referenced was deleted, the next
|
||||||
|
dimension silently rendered in Standard, and `drawing_save_as` raised
|
||||||
|
`DXFTableEntryError` after leaving a truncated file on disk."""
|
||||||
|
await backend.dimstyle_create("ISO-25", resolve_dimstyle("iso-25", None), set_current=True)
|
||||||
|
await backend.mleaderstyle_create("ANSI", resolve_mleaderstyle("ansi", None))
|
||||||
|
await backend.textstyle_create("Notes", "arial.ttf", set_current=True)
|
||||||
|
await backend.textstyle_create("Junk", "isocpeur.ttf")
|
||||||
|
await backend.block_define("MYARROW", [{"type": "line", "x1": 0, "y1": 0, "x2": -1, "y2": 0.2}])
|
||||||
|
await backend.dimstyle_create("ARROWED", resolve_dimstyle("ansi", {"DIMBLK": "MYARROW"}))
|
||||||
|
|
||||||
|
result = await backend.drawing_purge()
|
||||||
|
assert result["purged"]["text_styles"] == 1, "only the style nothing references goes"
|
||||||
|
assert result["purged"]["blocks"] == 0
|
||||||
|
names = {row["name"] for row in await backend.textstyle_list()}
|
||||||
|
assert {"Standard", "ISOCP", "ROMANS", "Notes"} <= names and "Junk" not in names
|
||||||
|
assert [r["name"] for r in await backend.textstyle_list() if r["current"]] == ["Notes"]
|
||||||
|
assert "MYARROW" in backend._doc.blocks
|
||||||
|
leader_styles = {r["name"]: r["text_style"] for r in await backend.mleaderstyle_list()}
|
||||||
|
assert leader_styles["ANSI"] == "ROMANS"
|
||||||
|
|
||||||
|
dim = await backend.dimension_linear(0, 0, 33.333, 0, 16, -30)
|
||||||
|
assert _rendered(backend, dim.handle) == ("33,33", 2.5, [2.5])
|
||||||
|
path = str(tmp_path / "purged.dxf")
|
||||||
|
await backend.drawing_save_as(path)
|
||||||
|
reopened = ezdxf.readfile(path)
|
||||||
|
assert reopened.dimstyles.get("ISO-25").dxf.dimtxsty == "ISOCP"
|
||||||
|
assert reopened.header["$TEXTSTYLE"] == "Notes"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_set_current_restores_every_dim_variable_not_just_the_stored_ones(backend, tmp_path):
|
||||||
|
"""A live seat's `-DIMSTYLE Restore` replaces *all* DIM* variables. Writing
|
||||||
|
only what the target style stores left the previous style's values in the
|
||||||
|
header: measured, ISO-25 with DIMZIN 0 / DIMSCALE 2.0 then
|
||||||
|
`dimstyle_set_current("Standard")` rendered the next dimension at 5.0 mm as
|
||||||
|
"33.30" and the saved file carried those next to `$DIMSTYLE Standard`."""
|
||||||
|
from engineering.standards.dimstyles import DIM_VARIABLE_WHITELIST
|
||||||
|
|
||||||
|
header = backend._doc.header
|
||||||
|
fresh = {f"${var}": header.get(f"${var}", None) for var in DIM_VARIABLE_WHITELIST}
|
||||||
|
baseline = await backend.dimension_linear(0, 0, 33.3, 0, 16, -30)
|
||||||
|
|
||||||
|
values = resolve_dimstyle("iso-25", {"DIMZIN": 0, "DIMSCALE": 2.0})
|
||||||
|
await backend.dimstyle_create("ISO-25", values, set_current=True)
|
||||||
|
assert header["$DIMZIN"] == 0 and header["$DIMSCALE"] == 2.0
|
||||||
|
assert header["$DIMTXSTY"] == "ISOCP"
|
||||||
|
result = await backend.dimstyle_set_current("Standard")
|
||||||
|
assert result["current"] == "Standard"
|
||||||
|
assert {key: header.get(key, None) for key in fresh} == fresh, (
|
||||||
|
"restoring Standard must reproduce the header drawing_new made"
|
||||||
|
)
|
||||||
|
dim = await backend.dimension_linear(0, 0, 33.3, 0, 16, -60)
|
||||||
|
expected = ("33.3", 2.5, [2.5])
|
||||||
|
assert _rendered(backend, dim.handle) == _rendered(backend, baseline.handle) == expected
|
||||||
|
assert backend._doc.entitydb.get(dim.handle).override().dimstyle_attribs == {}, (
|
||||||
|
"nothing stale is folded onto the dimension"
|
||||||
|
)
|
||||||
|
|
||||||
|
# DIMRND 0 discards the style attribute; the header twin must follow.
|
||||||
|
await backend.dimstyle_set_current("ISO-25")
|
||||||
|
assert header["$DIMZIN"] == 0 and header["$DIMSCALE"] == 2.0
|
||||||
|
await backend.dimstyle_modify("ISO-25", {"DIMRND": 0.5})
|
||||||
|
assert header["$DIMRND"] == 0.5
|
||||||
|
cleared = await backend.dimstyle_modify("ISO-25", {"DIMRND": 0})
|
||||||
|
assert cleared["changed"] == {"DIMRND": [0.5, 0]}
|
||||||
|
assert header["$DIMRND"] == 0.0
|
||||||
|
await backend.dimstyle_set_current("Standard")
|
||||||
|
path = str(tmp_path / "restored.dxf")
|
||||||
|
await backend.drawing_save_as(path)
|
||||||
|
saved = ezdxf.readfile(path).header
|
||||||
|
assert saved["$DIMSTYLE"] == "Standard"
|
||||||
|
assert {key: saved.get(key, None) for key in fresh} == fresh
|
||||||
|
|
||||||
|
|
||||||
async def test_textstyle_create_list_set_current_and_new_text_uses_it(backend):
|
async def test_textstyle_create_list_set_current_and_new_text_uses_it(backend):
|
||||||
|
|||||||
Reference in New Issue
Block a user