qet-mcp: a symbol's own texts are not free texts on the folio

qet_diff's texts, shapes and pictures sections collected every <input>,
<shape> and <image> under a folio with iter(). Symbols in older files carry
their own <inputs><input> texts, so those were counted as the folio's free
texts: schema_indus.qet folio 1 showed 124 where QElectroTech has 2, and
editing one of those symbol texts would have been reported as a free text
changing.

Only the folio's direct <inputs>, <shapes> and <images> children are read
now. Shapes and pictures have no nested copies in the shipped examples;
they are changed too so the three stay alike. Found by comparing the
tools' answers with QElectroTech's own lists over the shipped examples.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ispyisail
2026-09-28 13:19:54 +13:00
parent f5b644918b
commit a89a57bb10
2 changed files with 23 additions and 3 deletions
+7 -3
View File
@@ -329,13 +329,17 @@ def _extras(root: ET.Element) -> dict:
for n, d in _folios(root):
folios[n] = {f: d.get(f, "") for f in _FOLIO_FIELDS}
for t in d.iter("input"):
# The folio's own items only: direct children of its <inputs>,
# <shapes> and <images>. Symbols in older files carry their own
# <inputs><input> texts, which iter() would count as free texts
# (122 extra in schema_indus.qet).
for t in d.findall("inputs/input"):
texts.append(record(
t, {"folio": n, "x": t.get("x", ""), "y": t.get("y", ""),
"text": _plain_text(t.get("text", ""))},
{"rotation": t.get("rotation", "0"),
"font": t.get("font", ""), "color": t.get("color", "")}))
for sh in d.iter("shape"):
for sh in d.findall("shapes/shape"):
pen, brush = sh.find("pen"), sh.find("brush")
shapes.append(record(
sh, {"folio": n, "type": sh.get("type", ""),
@@ -347,7 +351,7 @@ def _extras(root: ET.Element) -> dict:
"fill": (brush.get("color", "") if brush is not None and
brush.get("style", "") != "NoBrush" else "none"),
"rotation": sh.get("rotation", "0")}))
for im in d.iter("image"):
for im in d.findall("images/image"):
images.append(record(
im, {"folio": n, "x": im.get("x", ""), "y": im.get("y", "")},
{"scale": im.get("size", ""), "rotation": im.get("rotation", "")}))
+16
View File
@@ -750,6 +750,22 @@ class Diff(unittest.TestCase):
self.assertFalse(d[k]["added"] or d[k]["removed"] or d[k]["changed"])
self.assertEqual(d["folios"]["changed"], [])
def test_a_symbols_own_texts_are_not_free_texts(self):
"""Symbols in older files carry their own <inputs><input> texts;
counting them made schema_indus.qet show 124 free texts where
QElectroTech has 2."""
d = self.dir
a, b = d / "sym_a.qet", d / "sym_b.qet"
body = ('<project><diagram><elements><element uuid="{e}" type="x">'
'<inputs><input x="0" y="0" text="{t}"/></inputs></element></elements>'
'<conductors/><inputs><input uuid="{f}" x="1" y="1" text="free"/></inputs>'
'</diagram></project>')
a.write_text(body.replace("{t}", "inside"))
b.write_text(body.replace("{t}", "changed inside"))
t = m.tool_diff(str(a), str(b))["texts"]
self.assertEqual((t["before"], t["after"], t["added"], t["removed"], t["changed"]),
(1, 1, [], [], []))
def test_edited_text_reads_as_removed_plus_added(self):
a = self.project("a.qet", texts=[(1, 2, "note")])
b = self.project("b.qet", texts=[(1, 2, "note EDITED")])