feat(sheet): ISO 5457 frames and ISO 7200 title blocks for A4-A0
SECTION 24 opens with sheet_frame and titleblock_apply. engineering/sheet/frames.py transcribes ISO 216's trimmed sizes, ISO 5457's 20 mm filing margin and 10 mm edges, the grid reference system (an even number of divisions per side, that side of the frame over 50 mm; letters from the top, numbers from the left), the centring marks (trimmed edge to 5 mm inside the frame) and the 10 x 5 mm corner trimming marks. Every one of those numbers is pinned by a test against the clause it comes from, because a wrong margin is visible on every drawing this server makes. engineering/sheet/titleblock.py draws the ISO 7200 block -- 180 mm wide, which is exactly the drawing-space width of a portrait A4, which is why one block fits every size -- and carries the ISO 128-30 projection-angle symbol. Which symbol is which is derived rather than remembered: first-angle projection puts the view seen from the left on the right, and the view of the cone from its small end is the small circle inside the large one, so first angle draws the cone left and the circles right. The old A3 module folds in. apply_iso_a3_titleblock now forwards to apply_titleblock(size="A3", projection=None, zones=False, marks=False), which is the geometry it always drew, and tests/test_engineering_titleblock.py passes unchanged -- that is the regression gate for the fold. No new ActiveX member is called: both tools reach the drawing only through contract members the A3 title block has used on both engines since v1.0 (entity_create_polyline / _line / _circle / _text, layout_list, layout_set_current), so there was nothing to probe live. Declared, not glossed: the zone divisions drawn here are equal, so ISO 5457's allowance for shorter corner fields is not implemented; the division counts, which are what a zone reference quotes, are the standard's. ISO 7200's full optional-field list is not transcribed, only the fields this block has a cell for. Coverage is A4-A0; an unknown size is refused by name with the five it has. 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
2bb8044144
commit
56e6ff7206
@@ -0,0 +1,268 @@
|
||||
"""ISO 5457 sheet frames: sizes, margins, the zone grid, centring and trim marks.
|
||||
|
||||
The frame is the one thing every drawing this server makes carries, so a wrong
|
||||
margin or a wrong division count is visible on all of them. Every number
|
||||
asserted here is transcribed in `engineering/sheet/frames.py` with its clause.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from engineering.sheet.frames import (
|
||||
CENTRING_OVERSHOOT,
|
||||
EDGE_MARGIN,
|
||||
FILING_MARGIN,
|
||||
SHEETS,
|
||||
TRIM_MARK_LONG,
|
||||
TRIM_MARK_SHORT,
|
||||
ZONE_DIVISIONS,
|
||||
ZONE_MODULE,
|
||||
frame_metrics,
|
||||
sheet_size,
|
||||
zone_divisions,
|
||||
)
|
||||
|
||||
EPS = 1e-9
|
||||
|
||||
|
||||
def test_sheet_sizes_are_the_iso_216_a_series():
|
||||
assert SHEETS == {
|
||||
"A4": (210.0, 297.0),
|
||||
"A3": (297.0, 420.0),
|
||||
"A2": (420.0, 594.0),
|
||||
"A1": (594.0, 841.0),
|
||||
"A0": (841.0, 1189.0),
|
||||
}
|
||||
|
||||
|
||||
def test_sheet_sizes_agree_with_the_page_setup_table():
|
||||
"""Two tables of one standard in one repository is one too many unless
|
||||
they are pinned to each other."""
|
||||
from engineering.standards.papers import PAPER_SIZES
|
||||
|
||||
for name, (w, h) in SHEETS.items():
|
||||
assert PAPER_SIZES[f"ISO_{name}"] == (int(w), int(h))
|
||||
|
||||
|
||||
def test_landscape_swaps_the_portrait_pair():
|
||||
assert sheet_size("A3", "landscape") == (420.0, 297.0)
|
||||
assert sheet_size("A3", "portrait") == (297.0, 420.0)
|
||||
assert sheet_size("a3") == (420.0, 297.0)
|
||||
|
||||
|
||||
def test_an_unknown_sheet_is_refused_by_name_with_the_coverage():
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
sheet_size("A5")
|
||||
message = str(excinfo.value)
|
||||
assert "A5" in message
|
||||
for name in SHEETS:
|
||||
assert name in message
|
||||
|
||||
|
||||
def test_an_unknown_orientation_is_refused():
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
sheet_size("A3", "diagonal")
|
||||
assert "diagonal" in str(excinfo.value)
|
||||
|
||||
|
||||
def test_margins_are_the_iso_5457_filing_20_and_edge_10():
|
||||
assert (FILING_MARGIN, EDGE_MARGIN) == (20.0, 10.0)
|
||||
m = frame_metrics("A3")
|
||||
assert m["margins"] == {"left": 20.0, "right": 10.0, "top": 10.0, "bottom": 10.0}
|
||||
assert m["frame"] == [20.0, 10.0, 410.0, 287.0]
|
||||
assert m["drawing_area"] == [390.0, 277.0]
|
||||
assert m["centre"] == [210.0, 148.5]
|
||||
|
||||
|
||||
def test_a4_portrait_drawing_area_is_exactly_the_titleblock_width():
|
||||
"""ISO 7200's 180 mm title block has to fit the smallest sheet."""
|
||||
m = frame_metrics("A4", orientation="portrait")
|
||||
assert m["drawing_area"][0] == pytest.approx(180.0, abs=EPS)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("size", "orientation", "columns", "rows"),
|
||||
[
|
||||
("A4", "portrait", 4, 6),
|
||||
("A4", "landscape", 6, 4),
|
||||
("A3", "landscape", 8, 6),
|
||||
("A3", "portrait", 6, 8),
|
||||
("A2", "landscape", 12, 8),
|
||||
("A2", "portrait", 8, 12),
|
||||
("A1", "landscape", 16, 12),
|
||||
("A0", "landscape", 24, 16),
|
||||
("A0", "portrait", 16, 24),
|
||||
],
|
||||
)
|
||||
def test_zone_division_counts_match_the_authored_table(size, orientation, columns, rows):
|
||||
z = frame_metrics(size, orientation=orientation)["zones"]
|
||||
assert (z["columns"], z["rows"]) == (columns, rows)
|
||||
long_side, short_side = ZONE_DIVISIONS[size]
|
||||
if orientation == "landscape":
|
||||
assert (z["columns"], z["rows"]) == (long_side, short_side)
|
||||
else:
|
||||
assert (z["columns"], z["rows"]) == (short_side, long_side)
|
||||
|
||||
|
||||
def test_zone_divisions_follow_the_even_rule_over_50_mm():
|
||||
assert ZONE_MODULE == 50.0
|
||||
assert zone_divisions(390.0) == 8 # 7.80 -> 8
|
||||
assert zone_divisions(277.0) == 6 # 5.54 -> 6
|
||||
assert zone_divisions(564.0) == 12 # 11.28 -> 12
|
||||
assert zone_divisions(1159.0) == 24 # 23.18 -> 24
|
||||
assert zone_divisions(821.0) == 16 # 16.42 -> 16
|
||||
|
||||
|
||||
def test_zone_labels_cover_every_cell_and_letters_start_at_the_top():
|
||||
z = frame_metrics("A0")["zones"]
|
||||
assert z["numbers"][0] == "1" and z["numbers"][-1] == "24"
|
||||
assert len(z["numbers"]) == 24
|
||||
assert z["letters"][0] == "A" and z["letters"][-1] == "P"
|
||||
assert len(z["letters"]) == 16
|
||||
assert z["column_width"] == pytest.approx(1159.0 / 24.0, abs=EPS)
|
||||
assert z["row_height"] == pytest.approx(821.0 / 16.0, abs=EPS)
|
||||
|
||||
|
||||
def test_the_mark_constants_are_the_standard_s():
|
||||
assert CENTRING_OVERSHOOT == 5.0
|
||||
assert (TRIM_MARK_LONG, TRIM_MARK_SHORT) == (10.0, 5.0)
|
||||
|
||||
|
||||
# ── primitives ──────────────────────────────────────────────────────────────
|
||||
|
||||
from engineering.mech.primitives import Line, Poly, Text # noqa: E402
|
||||
from engineering.sheet.frames import frame_prims # noqa: E402
|
||||
|
||||
|
||||
def _polys(prims):
|
||||
return [p for p in prims if isinstance(p, Poly)]
|
||||
|
||||
|
||||
def _lines(prims):
|
||||
return [p for p in prims if isinstance(p, Line)]
|
||||
|
||||
|
||||
def _texts(prims):
|
||||
return [p for p in prims if isinstance(p, Text)]
|
||||
|
||||
|
||||
def test_the_first_two_primitives_are_the_trimmed_sheet_and_the_frame():
|
||||
prims = frame_prims("A3", zones=False, marks=False)
|
||||
assert len(prims) == 2
|
||||
sheet, frame = prims
|
||||
assert isinstance(sheet, Poly) and sheet.closed and sheet.role == "visible"
|
||||
assert sheet.points == ((0.0, 0.0), (420.0, 0.0), (420.0, 297.0), (0.0, 297.0))
|
||||
assert frame.points == ((20.0, 10.0), (410.0, 10.0), (410.0, 287.0), (20.0, 287.0))
|
||||
|
||||
|
||||
def test_the_zone_grid_has_a_tick_pair_per_interior_boundary_and_a_label_pair_per_cell():
|
||||
prims = frame_prims("A3", zones=True, marks=False)
|
||||
# 7 interior column boundaries x 2 edges + 5 interior row boundaries x 2 edges
|
||||
assert len(_lines(prims)) == (8 - 1) * 2 + (6 - 1) * 2
|
||||
# 8 columns x 2 edges + 6 rows x 2 edges
|
||||
assert len(_texts(prims)) == 8 * 2 + 6 * 2
|
||||
assert {t.text for t in _texts(prims)} == {
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"E",
|
||||
"F",
|
||||
}
|
||||
|
||||
|
||||
def test_zone_ticks_span_the_margin_band_only():
|
||||
prims = frame_prims("A3", zones=True, marks=False)
|
||||
for line in [ln for ln in _lines(prims) if ln.p1[0] == ln.p2[0]]:
|
||||
ys = sorted((line.p1[1], line.p2[1]))
|
||||
assert ys in ([0.0, 10.0], [287.0, 297.0]), f"tick {line} leaves the margin band"
|
||||
for line in [ln for ln in _lines(prims) if ln.p1[1] == ln.p2[1]]:
|
||||
xs = sorted((line.p1[0], line.p2[0]))
|
||||
assert xs in ([0.0, 20.0], [410.0, 420.0]), f"tick {line} leaves the margin band"
|
||||
|
||||
|
||||
def test_the_first_zone_letter_is_at_the_top_of_the_sheet():
|
||||
prims = frame_prims("A3", zones=True, marks=False)
|
||||
a_labels = [t for t in _texts(prims) if t.text == "A"]
|
||||
f_labels = [t for t in _texts(prims) if t.text == "F"]
|
||||
assert len(a_labels) == 2 and len(f_labels) == 2
|
||||
assert min(t.at[1] for t in a_labels) > max(t.at[1] for t in f_labels)
|
||||
|
||||
|
||||
def test_centring_marks_run_from_the_trimmed_edge_to_5_mm_inside_the_frame():
|
||||
prims = frame_prims("A3", zones=False, marks=True)
|
||||
centre_lines = [p for p in _lines(prims) if p.role == "center"]
|
||||
assert len(centre_lines) == 4
|
||||
spans = {(tuple(c.p1), tuple(c.p2)) for c in centre_lines}
|
||||
assert ((0.0, 148.5), (25.0, 148.5)) in spans
|
||||
assert ((420.0, 148.5), (405.0, 148.5)) in spans
|
||||
assert ((210.0, 0.0), (210.0, 15.0)) in spans
|
||||
assert ((210.0, 297.0), (210.0, 282.0)) in spans
|
||||
|
||||
|
||||
def test_each_corner_carries_two_overlapping_10_by_5_trim_rectangles():
|
||||
prims = frame_prims("A3", zones=False, marks=True)
|
||||
rects = _polys(prims)[2:] # after the trimmed sheet and the frame
|
||||
assert len(rects) == 8
|
||||
for rect in rects:
|
||||
xs = [p[0] for p in rect.points]
|
||||
ys = [p[1] for p in rect.points]
|
||||
span = (abs(max(xs) - min(xs)), abs(max(ys) - min(ys)))
|
||||
assert span in ((10.0, 5.0), (5.0, 10.0)), span
|
||||
assert rect.closed
|
||||
|
||||
|
||||
# ── drawing ─────────────────────────────────────────────────────────────────
|
||||
|
||||
from engineering.sheet.frames import draw_sheet_frame # noqa: E402
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_draw_sheet_frame_puts_the_border_on_titleblock_and_the_zones_on_text(backend):
|
||||
result = await draw_sheet_frame(backend, "A3", zones=True, marks=True)
|
||||
assert result["ok"] is True
|
||||
assert result["size"] == "A3"
|
||||
assert result["bbox"] == {"min": [0.0, 0.0], "max": [420.0, 297.0]}
|
||||
outer = await backend.entity_get(result["outer_border"])
|
||||
inner = await backend.entity_get(result["inner_border"])
|
||||
assert outer.layer == "TITLEBLOCK" and inner.layer == "TITLEBLOCK"
|
||||
texts = [
|
||||
e for e in await backend.entity_list(type_filter="TEXT") if e.properties["text"] == "A"
|
||||
]
|
||||
assert texts and all(e.layer == "TEXT" for e in texts)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_draw_sheet_frame_offsets_every_primitive_by_the_origin(backend):
|
||||
result = await draw_sheet_frame(
|
||||
backend, "A4", orientation="portrait", zones=False, marks=False, origin=(100.0, 50.0)
|
||||
)
|
||||
assert result["bbox"] == {"min": [100.0, 50.0], "max": [310.0, 347.0]}
|
||||
assert len(result["handles"]) == 2
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_a_bad_size_is_refused_before_anything_is_drawn(backend):
|
||||
before = len(await backend.entity_list())
|
||||
with pytest.raises(ValueError):
|
||||
await draw_sheet_frame(backend, "A5")
|
||||
assert len(await backend.entity_list()) == before
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_a_missing_layout_is_refused_before_anything_is_drawn(backend):
|
||||
before = len(await backend.entity_list())
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
await draw_sheet_frame(backend, "A3", layout="NoSuchSheet")
|
||||
assert "NoSuchSheet" in str(excinfo.value)
|
||||
assert "layout_create" in str(excinfo.value)
|
||||
assert len(await backend.entity_list()) == before
|
||||
@@ -0,0 +1,190 @@
|
||||
"""ISO 7200 title blocks for A4-A0, and the A3 geometry that must not move."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from engineering.mech.primitives import Circle, Line, Poly, Text
|
||||
from engineering.sheet.titleblock import (
|
||||
TB_HEIGHT,
|
||||
TB_WIDTH,
|
||||
TITLE_TEXT_INDEX,
|
||||
TITLEBLOCK_FIELDS,
|
||||
TITLEBLOCK_RULE_COUNT,
|
||||
VALUE_FIELDS,
|
||||
TitleBlockMetadata,
|
||||
apply_titleblock,
|
||||
projection_symbol_prims,
|
||||
titleblock_origin,
|
||||
titleblock_prims,
|
||||
value_text_indices,
|
||||
)
|
||||
|
||||
EPS = 1e-9
|
||||
|
||||
|
||||
def _meta(**overrides) -> TitleBlockMetadata:
|
||||
base = dict(
|
||||
title="HELICAL GEAR",
|
||||
drawing_no="AM-2026-001",
|
||||
part_no="GR-24T-M3",
|
||||
material="C45",
|
||||
scale="1:1",
|
||||
units="mm",
|
||||
drawn_by="Umutcan",
|
||||
checked_by="QA",
|
||||
date="2026-04-28",
|
||||
sheet="1/1",
|
||||
revision="A",
|
||||
company="Anka-Makine",
|
||||
)
|
||||
base.update(overrides)
|
||||
return TitleBlockMetadata(**base)
|
||||
|
||||
|
||||
def test_the_block_is_the_iso_7200_180_mm_wide_and_sits_in_the_frame_corner():
|
||||
assert TB_WIDTH == 180.0 and TB_HEIGHT == 60.0
|
||||
assert titleblock_origin("A3") == (230.0, 10.0)
|
||||
assert titleblock_origin("A4", orientation="portrait") == (20.0, 10.0)
|
||||
assert titleblock_origin("A0") == (999.0, 10.0)
|
||||
|
||||
|
||||
def test_every_declared_field_is_a_metadata_attribute():
|
||||
meta = _meta()
|
||||
for field in TITLEBLOCK_FIELDS:
|
||||
assert hasattr(meta, field), field
|
||||
|
||||
|
||||
def test_the_a3_rules_are_exactly_where_they_have_always_been():
|
||||
prims = titleblock_prims("A3", _meta(), projection=None)
|
||||
rules = prims[:TITLEBLOCK_RULE_COUNT]
|
||||
assert isinstance(rules[0], Poly) and rules[0].closed
|
||||
assert rules[0].points == ((230.0, 10.0), (410.0, 10.0), (410.0, 70.0), (230.0, 70.0))
|
||||
assert [(r.p1[1], r.p1[0], r.p2[0]) for r in rules[1:4]] == [
|
||||
(20.0, 230.0, 410.0),
|
||||
(35.0, 230.0, 410.0),
|
||||
(50.0, 230.0, 410.0),
|
||||
]
|
||||
assert [(r.p1[0], r.p1[1], r.p2[1]) for r in rules[4:]] == [
|
||||
(320.0, 35.0, 50.0),
|
||||
(365.0, 35.0, 50.0),
|
||||
(290.0, 20.0, 35.0),
|
||||
(350.0, 20.0, 35.0),
|
||||
(275.0, 10.0, 20.0),
|
||||
(320.0, 10.0, 20.0),
|
||||
(365.0, 10.0, 20.0),
|
||||
]
|
||||
|
||||
|
||||
def test_the_a3_value_texts_are_exactly_where_they_have_always_been():
|
||||
prims = titleblock_prims("A3", _meta(), projection=None)
|
||||
index = value_text_indices()
|
||||
assert prims[index["drawing_no"]] == Text(at=(233.0, 40.0), text="AM-2026-001", height=3.5)
|
||||
assert prims[index["revision"]] == Text(at=(323.0, 40.0), text="A", height=3.5)
|
||||
assert prims[index["sheet"]] == Text(at=(368.0, 40.0), text="1/1", height=3.5)
|
||||
assert prims[index["part_no"]] == Text(at=(233.0, 25.0), text="GR-24T-M3", height=3.5)
|
||||
assert prims[index["material"]] == Text(at=(293.0, 25.0), text="C45", height=3.5)
|
||||
assert prims[index["scale"]] == Text(at=(353.0, 25.0), text="1:1", height=3.5)
|
||||
assert prims[index["drawn_by"]] == Text(at=(233.0, 11.5), text="Umutcan", height=3.5)
|
||||
assert prims[index["checked_by"]] == Text(at=(278.0, 11.5), text="QA", height=3.5)
|
||||
assert prims[index["date"]] == Text(at=(323.0, 11.5), text="2026-04-28", height=3.5)
|
||||
assert prims[index["company"]] == Text(at=(368.0, 11.5), text="Anka-Makine", height=3.5)
|
||||
|
||||
|
||||
def test_the_title_sits_at_the_pinned_index_and_carries_the_text_verbatim():
|
||||
prims = titleblock_prims("A3", _meta(title="SPUR GEAR / M3 Z24"), projection=None)
|
||||
title = prims[TITLE_TEXT_INDEX]
|
||||
assert isinstance(title, Text)
|
||||
assert title.text == "SPUR GEAR / M3 Z24"
|
||||
assert title.height == 5.0
|
||||
assert title.at[1] == pytest.approx(57.5, abs=EPS)
|
||||
|
||||
|
||||
def test_projection_none_draws_no_symbol_and_first_draws_one():
|
||||
plain = titleblock_prims("A3", _meta(), projection=None)
|
||||
first = titleblock_prims("A3", _meta(), projection="first")
|
||||
assert len(plain) == TITLE_TEXT_INDEX + 1 + 2 * len(VALUE_FIELDS)
|
||||
assert len(first) == len(plain) + 4
|
||||
|
||||
|
||||
def test_first_angle_puts_the_circles_to_the_right_of_the_cone():
|
||||
first = projection_symbol_prims((0.0, 0.0), "first")
|
||||
third = projection_symbol_prims((0.0, 0.0), "third")
|
||||
cone_first = next(p for p in first if isinstance(p, Poly))
|
||||
circles_first = [p for p in first if isinstance(p, Circle)]
|
||||
assert max(x for x, _ in cone_first.points) < min(c.center[0] for c in circles_first)
|
||||
cone_third = next(p for p in third if isinstance(p, Poly))
|
||||
circles_third = [p for p in third if isinstance(p, Circle)]
|
||||
assert min(x for x, _ in cone_third.points) > max(c.center[0] for c in circles_third)
|
||||
assert {round(c.radius, 6) for c in circles_first} == {4.0, 2.0}
|
||||
assert any(isinstance(p, Line) and p.role == "center" for p in first)
|
||||
|
||||
|
||||
def test_the_cone_s_small_end_faces_the_circles_side_in_first_angle():
|
||||
"""The derivation only holds if the view drawn as circles really is the
|
||||
view from the cone's small end."""
|
||||
cone = next(p for p in projection_symbol_prims((0.0, 0.0), "first") if isinstance(p, Poly))
|
||||
left_x = min(x for x, _ in cone.points)
|
||||
right_x = max(x for x, _ in cone.points)
|
||||
left_height = max(y for x, y in cone.points if x == left_x) * 2
|
||||
right_height = max(y for x, y in cone.points if x == right_x) * 2
|
||||
assert left_height == pytest.approx(4.0, abs=EPS)
|
||||
assert right_height == pytest.approx(8.0, abs=EPS)
|
||||
|
||||
|
||||
def test_an_unknown_projection_angle_is_refused():
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
titleblock_prims("A3", _meta(), projection="second")
|
||||
assert "second" in str(excinfo.value)
|
||||
|
||||
|
||||
def test_a_sheet_narrower_than_the_title_block_is_refused_by_name():
|
||||
"""There is no such size in A4-A0; the guard exists so a future size cannot
|
||||
ship a title block hanging off the paper."""
|
||||
from engineering.sheet import frames
|
||||
|
||||
original = dict(frames.SHEETS)
|
||||
frames.SHEETS["A9"] = (100.0, 140.0)
|
||||
try:
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
titleblock_origin("A9", orientation="portrait")
|
||||
assert "180" in str(excinfo.value)
|
||||
finally:
|
||||
frames.SHEETS.clear()
|
||||
frames.SHEETS.update(original)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_apply_titleblock_returns_the_payload_the_a3_tool_always_returned(backend):
|
||||
result = await apply_titleblock(backend, size="A3", metadata=_meta(), projection=None)
|
||||
assert result["bbox"] == {"min": [0.0, 0.0], "max": [420.0, 297.0]}
|
||||
assert set(result["value_texts"]) == {
|
||||
"drawing_no",
|
||||
"revision",
|
||||
"sheet",
|
||||
"part_no",
|
||||
"material",
|
||||
"scale",
|
||||
"drawn_by",
|
||||
"checked_by",
|
||||
"date",
|
||||
"company",
|
||||
}
|
||||
assert len(result["titleblock_lines"]) == TITLEBLOCK_RULE_COUNT
|
||||
title = await backend.entity_get(result["title_text"])
|
||||
assert title.type == "TEXT" and title.properties["text"] == "HELICAL GEAR"
|
||||
assert title.layer == "TEXT"
|
||||
for handle in result["titleblock_lines"]:
|
||||
assert (await backend.entity_get(handle)).layer == "TITLEBLOCK"
|
||||
assert result["projection_symbol"] == []
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_apply_titleblock_draws_every_size_with_its_symbol(backend):
|
||||
for size in ("A4", "A3", "A2", "A1", "A0"):
|
||||
orientation = "portrait" if size == "A4" else "landscape"
|
||||
result = await apply_titleblock(
|
||||
backend, size=size, metadata=_meta(), orientation=orientation
|
||||
)
|
||||
assert result["ok"] is True and result["size"] == size
|
||||
assert len(result["projection_symbol"]) == 4
|
||||
@@ -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 (204 tools, 23 groups).
|
||||
"""Frozen snapshot of the surface (206 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
|
||||
@@ -527,7 +527,14 @@ async def test_tool_group_sizes_are_unchanged():
|
||||
merge task tagged them, the four groups had filed those 28 tools under
|
||||
`layouts` / `templates` / `drawing` / `layers` / `view` / `system` by
|
||||
their secondary tags; those counts returned to their pre-track-E values
|
||||
when the section tags landed.) Every other number here has been unchanged
|
||||
when the section tags landed.)
|
||||
`engineering` moved 10 -> 12 when v1.6's SECTION 24 opened with
|
||||
`sheet_frame` and `titleblock_apply` (the ISO 5457 frame and the ISO 7200
|
||||
title block for every size A4-A0). Both are tagged `engineering` and
|
||||
`sheet`, and `sheet` is not in `_GROUP_TAG_PRIORITY`, so they file under
|
||||
`engineering` beside `titleblock_apply_iso_a3` rather than opening a
|
||||
24th group.
|
||||
Every other number here has been unchanged
|
||||
since the snapshot was taken.
|
||||
"""
|
||||
sizes = {label: len(names) for label, names in (await server._tool_groups()).items()}
|
||||
@@ -538,7 +545,7 @@ async def test_tool_group_sizes_are_unchanged():
|
||||
"corner_ops": 4,
|
||||
"dimensions": 5,
|
||||
"drawing": 11,
|
||||
"engineering": 10,
|
||||
"engineering": 12,
|
||||
"entity_creation": 18,
|
||||
"entity_modification": 16,
|
||||
"entity_query": 9,
|
||||
@@ -556,4 +563,4 @@ async def test_tool_group_sizes_are_unchanged():
|
||||
"validation": 1,
|
||||
"view": 4,
|
||||
}
|
||||
assert sum(sizes.values()) == 204
|
||||
assert sum(sizes.values()) == 206
|
||||
|
||||
Reference in New Issue
Block a user