Repository: ManimCommunity/manim

Issue:
Mobjects add_to_back is missing sanity checks
## Description of bug / unexpected behavior
the Mobject.add method contains sanity checks to make sure, no submobject gets added twice and self is not in self.submobjects.
Mobjext.add_to_back is missing this functionality.


## Expected behavior
Adding self should produce a ValueError: Mobject cannot contain self.
Addin a Mobject multiple times should result in it beeing just once in self.submobjects


## How to reproduce the issue
<details><summary>Code for reproducing the problem</summary>

```py
a = Mobject()
b = Line()
a.add_to_back(a)
a.add_to_back(b,b)
print(a.submobjects)
# results in [Mobject, Line, Line]
```

</details>


Discussion:
Thanks for the tip! Sorry it took so long for one of us to respond.

If you'd like to tackle this problem, feel free to, and let me know by commenting. In the mean time I'll tag it as a good first issue.

Resolving patch:
diff --git a/manim/mobject/mobject.py b/manim/mobject/mobject.py
--- a/manim/mobject/mobject.py
+++ b/manim/mobject/mobject.py
@@ -353,9 +353,36 @@ def add_to_back(self, *mobjects: "Mobject") -> "Mobject":
             the head of :attr:`submobjects`. The head of this list is rendered
             first, which places the corresponding mobjects behind the
             subsequent list members.
+
+        Raises
+        ------
+        :class:`ValueError`
+            When a mobject tries to add itself.
+        :class:`TypeError`
+            When trying to add an object that is not an instance of :class:`Mobject`.
+
+        Notes
+        -----
+        A mobject cannot contain itself, and it cannot contain a submobject
+        more than once.  If the parent mobject is displayed, the newly-added
+        submobjects will also be displayed (i.e. they are automatically added
+        to the parent Scene).
+
+        See Also
+        --------
+        :meth:`remove`
+        :meth:`add`
+
         """
+        for mobject in mobjects:
+            if self in mobjects:
+                raise ValueError("Mobject cannot contain self")
+            if not isinstance(mobject, Mobject):
+                raise TypeError("All submobjects must be of type Mobject")
+
+        filtered = list_update(mobjects, self.submobjects)
         self.remove(*mobjects)
-        self.submobjects = list(mobjects) + self.submobjects
+        self.submobjects = list(filtered) + self.submobjects
         return self
 
     def remove(self, *mobjects: "Mobject") -> "Mobject":


Test patch:
diff --git a/tests/test_vectorized_mobject.py b/tests/test_vectorized_mobject.py
--- a/tests/test_vectorized_mobject.py
+++ b/tests/test_vectorized_mobject.py
@@ -1,6 +1,6 @@
 import pytest
 
-from manim import Mobject, VDict, VGroup, VMobject
+from manim import Line, Mobject, VDict, VGroup, VMobject
 
 
 def test_vgroup_init():
@@ -86,6 +86,24 @@ def test_vgroup_remove_dunder():
     assert len(obj.submobjects) == 0
 
 
+def test_vmob_add_to_back():
+    """Test the Mobject add_to_back method."""
+    a = VMobject()
+    b = Line()
+    c = "text"
+    with pytest.raises(ValueError):
+        # Mobject cannot contain self
+        a.add_to_back(a)
+    with pytest.raises(TypeError):
+        # All submobjects must be of type Mobject
+        a.add_to_back(c)
+
+    # No submobject gets added twice
+    a.add_to_back(b)
+    a.add_to_back(b, b)
+    assert len(a.submobjects) == 1
+
+
 def test_vdict_init():
     """Test the VDict instantiation."""
     # Test empty VDict