Repository: idaholab/MontePy

Issue:
Materials.append_renumber adds double materials


**Describe the bug**

If you use `problem.materials.append_renumber(mat)` there will be two instances of `mat` in `problem.data_inputs` which will break a lot of things. 

**To Reproduce**


``` python
problem = montepy.read_input("foo.imcnp")
new_mat = ...
new_mat.number = 5
problem.write_problem("bar")
new_problem.read_input("bar"0
```

**Error Message (if any)**

If an error message was printed please include the entire stacktrace. If it includes any specific values please change or remove them. For example:

``` python
In [6]: problem.cells.append(copy.deepcopy(cell))
---------------------------------------------------------------------------
NumberConflictError                       Traceback (most recent call last)
Cell In[6], line 1
----> 1 problem.cells.append(copy.deepcopy(cell))

File ~/dev/montepy/montepy/numbered_object_collection.py:202, in NumberedObjectCollection.append(self, obj)
    200     raise TypeError(f"object being appended must be of type: {self._obj_class}")
    201 if obj.number in self.numbers:
--> 202     raise NumberConflictError(
    203         (
    204             "There was a numbering conflict when attempting to add "
    205             f"{obj} to {type(self)}. Conflict was with {self[obj.number]}"
    206         )
    207     )
    208 else:
    209     self.__num_cache[obj.number] = obj

NumberConflictError: There was a numbering conflict when attempting to add CELL: 3, mat: 3, DENS: 1.0 g/cm3 to <class 'montepy.cells.Cells'>. Conflict was with CELL: 3, mat: 3, DENS: 1.0 g/cm3
```

**MCNP input file snippet**

If applicable, please include a small section of the input file you were working on. If it includes any specific values please change or remove them. For example:

```
1 1 20
         -1000  $ dollar comment
        imp:n,p=1 U=350 trcl=5

C surfaces
1000 SO 1

C data
C materials
C UO2 5 atpt enriched
m1        92235.80c           5 &
92238.80c          95
```

**Version**

 - Version 0.4.0 (technically: 0.4.1.dev0+ged6f2d3.d20240827)



Discussion:

Patch:
diff --git a/doc/source/changelog.rst b/doc/source/changelog.rst
index 530c536c..89e89561 100644
--- a/doc/source/changelog.rst
+++ b/doc/source/changelog.rst
@@ -4,6 +4,10 @@ MontePy Changelog
 #Next Version#
 --------------
 
+**Bug Fixes**
+
+* Fixed a bug where ``problem.materials.append_renumber`` would double add a material to ``problem.data_inputs`` (:issue:`516`).
+
 **Performance Improvement**
 
 * Fixed method of linking ``Material`` to ``ThermalScattering`` objects, avoiding a very expensive O(N:sup:`2`) (:issue:`510`).
diff --git a/montepy/numbered_object_collection.py b/montepy/numbered_object_collection.py
index e542c82e..bbbd49d3 100644
--- a/montepy/numbered_object_collection.py
+++ b/montepy/numbered_object_collection.py
@@ -439,6 +439,7 @@ class NumberedDataObjectCollection(NumberedObjectCollection):
         :type insert_in_data: bool
         :raises NumberConflictError: if this object has a number that is already in use.
         """
+        super().append(obj)
         if self._problem:
             if self._last_index:
                 index = self._last_index
@@ -452,7 +453,6 @@ class NumberedDataObjectCollection(NumberedObjectCollection):
             if insert_in_data:
                 self._problem.data_inputs.insert(index + 1, obj)
             self._last_index = index + 1
-        super().append(obj)
 
     def __delitem__(self, idx):
         if not isinstance(idx, int):


Test patch:
diff --git a/tests/test_numbered_collection.py b/tests/test_numbered_collection.py
index f88cf831..d5a43f9e 100644
--- a/tests/test_numbered_collection.py
+++ b/tests/test_numbered_collection.py
@@ -317,11 +317,13 @@ def test_data_append(cp_simple_problem):
     prob.materials.append(new_mat)
     assert new_mat in prob.materials
     assert new_mat in prob.data_inputs
+    assert prob.data_inputs.count(new_mat) == 1
     # trigger getting data_inputs end
     prob.materials.clear()
     prob.materials.append(new_mat)
     assert new_mat in prob.materials
     assert new_mat in prob.data_inputs
+    assert prob.data_inputs.count(new_mat) == 1
     prob.data_inputs.clear()
     prob.materials._last_index = None
     new_mat = copy.deepcopy(next(iter(prob.materials)))
@@ -329,6 +331,7 @@ def test_data_append(cp_simple_problem):
     prob.materials.append(new_mat)
     assert new_mat in prob.materials
     assert new_mat in prob.data_inputs
+    assert prob.data_inputs.count(new_mat) == 1
     # trigger getting index of last material
     prob.materials._last_index = None
     new_mat = copy.deepcopy(next(iter(prob.materials)))
@@ -336,6 +339,16 @@ def test_data_append(cp_simple_problem):
     prob.materials.append(new_mat)
     assert new_mat in prob.materials
     assert new_mat in prob.data_inputs
+    assert prob.data_inputs.count(new_mat) == 1
+
+
+def test_data_append_renumber(cp_simple_problem):
+    prob = cp_simple_problem
+    new_mat = copy.deepcopy(next(iter(prob.materials)))
+    prob.materials.append_renumber(new_mat)
+    assert new_mat in prob.materials
+    assert new_mat in prob.data_inputs
+    assert prob.data_inputs.count(new_mat) == 1
 
 
 def test_data_remove(cp_simple_problem):