feat(python): block contents (create_entity(..., block=))

BlockEntityAdd adds a validated entity to a block definition (owner set by the
host, same validation as a model-space entity, self-nesting inserts refused),
reusing the scene's block-editor routing. Deleting a block member now also
drops its handle from the block record. Real-IPC audit with an attribute
definition inside a block, DWG/DXF persistence and undo; IPC and Python unit
tests; docs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Felix RiestraandClaude Sonnet 5 committed 2026-09-21 16:54:30 +02:00
1 parent 8d20d280fe
commit b1edc9f578
8 files changed
+251 -7

No files matched your search

@@ -41,6 +41,7 @@ class DocumentModelTests(unittest.TestCase):
style_operation=lambda kind, op, name, options: self.calls.append((kind, op, name, options)) or 9,
block_records=lambda: [{"name": n, "entities": []} for n in ("Widget", "Gadget")],
block_operation=lambda op, name, options: self.calls.append(("block", op, name, options)) or 9,
add_to_block=lambda block, entity: self.calls.append(("add_to_block", block, entity)) or 1,
)
namespace = {"ocs": self.ocs}
exec(MODEL.read_text(), namespace)
@@ -96,6 +97,14 @@ class DocumentModelTests(unittest.TestCase):
dim.set_current("Standard")
self.assertEqual(self.calls[-1], ("dim", "set_current", "Standard", None))
def test_create_entity_in_block(self):
self.doc.create_entity("Line", block="Widget", start={"x": 0, "y": 0, "z": 0}, end={"x": 1, "y": 0, "z": 0})
self.assertEqual(self.calls[-1][:2], ("add_to_block", "Widget"))
self.assertEqual(self.calls[-1][2]["kind"], "Line")
self.assertNotIn("block", self.calls[-1][2])
self.doc.create_entity("Line", start={"x": 0, "y": 0, "z": 0}, end={"x": 1, "y": 0, "z": 0})
self.assertEqual(self.calls[-1][0], "add")
def test_blocks(self):
blocks = self.doc.blocks
self.assertIn("WIDGET", blocks)