diff --git a/src/easyscience/global_object/map.py b/src/easyscience/global_object/map.py index 53a3aac4..7edacba1 100644 --- a/src/easyscience/global_object/map.py +++ b/src/easyscience/global_object/map.py @@ -126,7 +126,19 @@ def change_type(self, obj, new_type: str): def add_vertex(self, obj: object, obj_type: str = None): name = obj.unique_name if name in self._store.keys(): - raise ValueError(f'Object name {name} already exists in the graph.') + # modify the name to make it unique: + # add "_1" or increment the number if already exists + suffix = 1 + base_name = name + new_name = base_name + '_' + str(suffix) + while new_name in self._store.keys(): + suffix += 1 + new_name = base_name + '_' + str(suffix) + # Update the object's unique_name directly to avoid recursive add_vertex call + obj._unique_name = new_name # Direct assignment to avoid setter + name = new_name + # too much overhead in logging + # print(f"Warning: Object name already exists. Changed to unique name '{name}'") self._store[name] = obj self.__type_dict[name] = _EntryList() # Add objects type to the list of types self.__type_dict[name].finalizer = weakref.finalize(self._store[name], self.prune, name) diff --git a/tests/unit_tests/global_object/test_map.py b/tests/unit_tests/global_object/test_map.py index df344aed..fb64835a 100644 --- a/tests/unit_tests/global_object/test_map.py +++ b/tests/unit_tests/global_object/test_map.py @@ -58,12 +58,36 @@ def test_get_item_by_key(self, clear, base_object, parameter_object): assert global_object.map.get_item_by_key(parameter_object.unique_name) == parameter_object @pytest.mark.parametrize("cls, kwargs", [(ObjBase, {}), (Parameter, {"value": 2.0})]) - def test_identical_unique_names_exception(self, clear, cls, kwargs): + def test_identical_unique_names_auto_rename(self, clear, cls, kwargs): # When test_obj = cls(name="test", unique_name="test", **kwargs) - # Then Expect - with pytest.raises(ValueError): - test_obj2 = cls(name="test2", unique_name="test", **kwargs) + original_unique_name = test_obj.unique_name + # Then + test_obj2 = cls(name="test2", unique_name="test", **kwargs) + # Expect - the second object should be automatically renamed + assert test_obj.unique_name == original_unique_name # First object keeps original name + assert test_obj2.unique_name == "test_1" # Second object gets suffix + assert test_obj.unique_name != test_obj2.unique_name # Names are different + # Both objects should be in the map with their respective names + assert global_object.map.get_item_by_key(test_obj.unique_name) == test_obj + assert global_object.map.get_item_by_key(test_obj2.unique_name) == test_obj2 + + def test_multiple_identical_unique_names_increment(self, clear): + # When - Create multiple objects with the same initial unique name + obj1 = ObjBase(name="test1", unique_name="duplicate") + obj2 = ObjBase(name="test2", unique_name="duplicate") + obj3 = ObjBase(name="test3", unique_name="duplicate") + + # Expect - Each should get a unique incremented name + assert obj1.unique_name == "duplicate" # First keeps original + assert obj2.unique_name == "duplicate_1" # Second gets _1 + assert obj3.unique_name == "duplicate_2" # Third gets _2 + + # All should be accessible in the map + assert global_object.map.get_item_by_key("duplicate") == obj1 + assert global_object.map.get_item_by_key("duplicate_1") == obj2 + assert global_object.map.get_item_by_key("duplicate_2") == obj3 + assert len(global_object.map._store) == 3 def test_unique_name_change_still_in_map(self, clear, base_object, parameter_object): # When