From 5e689286fe923876fba8481e05c802975b68ff6d Mon Sep 17 00:00:00 2001 From: Irvanal Haq Date: Fri, 9 May 2025 19:15:37 +0700 Subject: [PATCH 1/5] Avoid duplicate references to the same object in self.mobjects --- manim/scene/scene.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/manim/scene/scene.py b/manim/scene/scene.py index fc3d3ede54..c45fd04a73 100644 --- a/manim/scene/scene.py +++ b/manim/scene/scene.py @@ -553,6 +553,10 @@ def replace(self, old_mobject: Mobject, new_mobject: Mobject) -> None: def replace_in_list( mobj_list: list[Mobject], old_m: Mobject, new_m: Mobject ) -> bool: + # Avoid duplicate references to the same object in self.mobjects + if new_m in mobj_list: + mobj_list.remove(new_m) + # We use breadth-first search because some Mobjects get very deep and # we expect top-level elements to be the most common targets for replace. for i in range(0, len(mobj_list)): From 5fb819dc1e3cd99b18f60f49a0fbf4fe0069a92c Mon Sep 17 00:00:00 2001 From: Irvanal Haq Date: Fri, 9 May 2025 19:58:31 +0700 Subject: [PATCH 2/5] add unit test for ReplacementTransform --- tests/module/animation/test_transform.py | 27 ++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 tests/module/animation/test_transform.py diff --git a/tests/module/animation/test_transform.py b/tests/module/animation/test_transform.py new file mode 100644 index 0000000000..d1b9c43aef --- /dev/null +++ b/tests/module/animation/test_transform.py @@ -0,0 +1,27 @@ +from __future__ import annotations + +from manim import Circle, ReplacementTransform, Scene, Square, VGroup + + +def test_no_duplicate_references(): + scene = Scene() + c = Circle() + sq = Square() + scene.add(c, sq) + + scene.play(ReplacementTransform(c, sq)) + assert len(scene.mobjects) == 1 + assert scene.mobjects[0] is sq + + +def test_duplicate_references_in_group(): + scene = Scene() + c = Circle() + sq = Square() + vg = VGroup(c, sq) + scene.add(vg) + + scene.play(ReplacementTransform(c, sq)) + submobs = vg.submobjects + assert len(submobs) == 1 + assert submobs[0] is sq From 2012dbefc0ebdcbdfc9768b72a8d455021a2d045 Mon Sep 17 00:00:00 2001 From: Irvanal Haq <125118413+irvanalhaq9@users.noreply.github.com> Date: Sat, 26 Jul 2025 06:01:57 +0700 Subject: [PATCH 3/5] Handle case where new mobject is the same as old mobject MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Francisco ManrĂ­quez Novoa <49853152+chopan050@users.noreply.github.com> --- manim/scene/scene.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/manim/scene/scene.py b/manim/scene/scene.py index c45fd04a73..1dd3114c72 100644 --- a/manim/scene/scene.py +++ b/manim/scene/scene.py @@ -555,6 +555,15 @@ def replace_in_list( ) -> bool: # Avoid duplicate references to the same object in self.mobjects if new_m in mobj_list: + if old_m is new_m: + # In this case, one could say that the old Mobject was already found. + # No replacement is needed, since old_m is new_m, so no action is required. + # This might be unexpected, so raise a warning. + logging.warning( + f"Attempted to replace {type(old_m).__name__} " + "with itself in Scene.mobjects." + ) + return True mobj_list.remove(new_m) # We use breadth-first search because some Mobjects get very deep and From ef653201e11c12f8f9788e0833e7bbaa8489d9be Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 25 Jul 2025 23:02:12 +0000 Subject: [PATCH 4/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- manim/scene/scene.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manim/scene/scene.py b/manim/scene/scene.py index 1dd3114c72..99dc2eaccd 100644 --- a/manim/scene/scene.py +++ b/manim/scene/scene.py @@ -562,7 +562,7 @@ def replace_in_list( logging.warning( f"Attempted to replace {type(old_m).__name__} " "with itself in Scene.mobjects." - ) + ) return True mobj_list.remove(new_m) From d0f032f7757d75af2f4868f260cdb9d5cb8f20a9 Mon Sep 17 00:00:00 2001 From: Irvanal Haq <125118413+irvanalhaq9@users.noreply.github.com> Date: Sat, 26 Jul 2025 06:22:10 +0700 Subject: [PATCH 5/5] Change logging to logger --- manim/scene/scene.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manim/scene/scene.py b/manim/scene/scene.py index 99dc2eaccd..562a4c9102 100644 --- a/manim/scene/scene.py +++ b/manim/scene/scene.py @@ -559,7 +559,7 @@ def replace_in_list( # In this case, one could say that the old Mobject was already found. # No replacement is needed, since old_m is new_m, so no action is required. # This might be unexpected, so raise a warning. - logging.warning( + logger.warning( f"Attempted to replace {type(old_m).__name__} " "with itself in Scene.mobjects." )