From c41b2cac184fd9a5f62181bd333d60843f879e02 Mon Sep 17 00:00:00 2001 From: zrgt Date: Tue, 5 May 2026 17:12:47 +0200 Subject: [PATCH] fix: OrderedNamespaceSet.__setitem__ slice uses exhausted iterator slice branch stored exhausted islice iterator back into _order instead of the materialized successful_new_items list, resulting in an empty slice assignment that discarded all newly added items. Fixes #494 --- sdk/basyx/aas/model/base.py | 2 +- sdk/test/model/test_base.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/sdk/basyx/aas/model/base.py b/sdk/basyx/aas/model/base.py index c9c8c8fe..f668fc58 100644 --- a/sdk/basyx/aas/model/base.py +++ b/sdk/basyx/aas/model/base.py @@ -2248,7 +2248,7 @@ def __setitem__(self, s, o) -> None: for i in successful_new_items: super().remove(i) raise - self._order[s] = new_items + self._order[s] = successful_new_items for i in deleted_items: super().remove(i) diff --git a/sdk/test/model/test_base.py b/sdk/test/model/test_base.py index e300cc1f..8513c1c3 100644 --- a/sdk/test/model/test_base.py +++ b/sdk/test/model/test_base.py @@ -722,6 +722,35 @@ def test_OrderedNamespace(self) -> None: f"{self._namespace_class.__name__}[{self.namespace.id}]'", # type: ignore[has-type] str(cm2.exception)) + def test_ordered_namespaceset_slice_setitem_preserves_order(self) -> None: + # Replace a slice of items; the new items must appear in the correct positions after replacement + ns = ExampleOrderedNamespace() + sid1 = model.ExternalReference((model.Key(model.KeyTypes.GLOBAL_REFERENCE, "http://example.org/sid1"),)) + sid2 = model.ExternalReference((model.Key(model.KeyTypes.GLOBAL_REFERENCE, "http://example.org/sid2"),)) + sid3 = model.ExternalReference((model.Key(model.KeyTypes.GLOBAL_REFERENCE, "http://example.org/sid3"),)) + sid4 = model.ExternalReference((model.Key(model.KeyTypes.GLOBAL_REFERENCE, "http://example.org/sid4"),)) + sid5 = model.ExternalReference((model.Key(model.KeyTypes.GLOBAL_REFERENCE, "http://example.org/sid5"),)) + p1 = model.Property("PA", model.datatypes.Int, semantic_id=sid1) + p2 = model.Property("PB", model.datatypes.Int, semantic_id=sid2) + p3 = model.Property("PC", model.datatypes.Int, semantic_id=sid3) + ns.set1.add(p1) + ns.set1.add(p2) + ns.set1.add(p3) + self.assertEqual([p1, p2, p3], list(ns.set1)) + + # Replace slice [0:2] (p1, p2) with two new items + new1 = model.Property("PX", model.datatypes.Int, semantic_id=sid4) + new2 = model.Property("PY", model.datatypes.Int, semantic_id=sid5) + ns.set1[0:2] = [new1, new2] + + # After replacement: [new1, new2, p3] + result = list(ns.set1) + self.assertEqual([new1, new2, p3], result) + self.assertIsNone(p1.parent) + self.assertIsNone(p2.parent) + self.assertIs(ns, new1.parent) + self.assertIs(ns, new2.parent) + class ExternalReferenceTest(unittest.TestCase): def test_constraints(self):