diff --git a/basyx/aas/model/_string_constraints.py b/basyx/aas/model/_string_constraints.py index 0fd05d631..d471201f4 100644 --- a/basyx/aas/model/_string_constraints.py +++ b/basyx/aas/model/_string_constraints.py @@ -130,6 +130,8 @@ def _setter(self, value: Optional[str]) -> None: constraint_check_fn(value) setattr(self, "_" + pub_attr_name, value) + if hasattr(decorated_class, pub_attr_name): + raise AttributeError(f"{decorated_class.__name__} already has an attribute named '{pub_attr_name}'") setattr(decorated_class, pub_attr_name, property(_getter, _setter)) return decorated_class diff --git a/test/model/test_string_constraints.py b/test/model/test_string_constraints.py index 3b347ea2c..5adb15523 100644 --- a/test/model/test_string_constraints.py +++ b/test/model/test_string_constraints.py @@ -83,3 +83,19 @@ def test_ignore_none_values(self) -> None: dc = self.DummyClass(None) # type: ignore self.assertIsNone(dc.some_attr) dc.some_attr = None # type: ignore + + def test_attribute_name_conflict(self) -> None: + # We don't want to overwrite existing attributes in case of a name conflict + with self.assertRaises(AttributeError) as cm: + @_string_constraints.constrain_revision_type("foo") + class DummyClass: + foo = property() + self.assertEqual("DummyClass already has an attribute named 'foo'", cm.exception.args[0]) + + with self.assertRaises(AttributeError) as cm: + @_string_constraints.constrain_label_type("bar") + class DummyClass2: + @property + def bar(self): + return "baz" + self.assertEqual("DummyClass2 already has an attribute named 'bar'", cm.exception.args[0])