Fixed division by 0 in "turn_animation_into_updater" (#4567)

* fixed division by 0

* fixed division by 0

* fixed division by 0

* updated lock file

* Revert "fixed division by 0"

This reverts commit b916a0c9c9.

* Add tests for turn_animation_into_updater with zero/negative run_time

* updated lock file

---------

Co-authored-by: Benjamin Hackl <mail@behackl.dev>
This commit is contained in:
Sacha 2026-02-03 14:40:09 -08:00 committed by GitHub
commit d49115316e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 66 additions and 0 deletions

View file

@ -214,6 +214,16 @@ def turn_animation_into_updater(
def update(m: Mobject, dt: float):
if animation.total_time >= 0:
run_time = animation.get_run_time()
# handle zero/negative runtime safely
if run_time <= 0:
# instantly snap to final state once, then remove updater
animation.interpolate(1)
animation.update_mobjects(dt)
animation.finish()
m.remove_updater(update)
return
time_ratio = animation.total_time / run_time
if cycle:
alpha = time_ratio % 1

View file

@ -0,0 +1,56 @@
from __future__ import annotations
from manim import Circle, FadeIn
from manim.animation.updaters.mobject_update_utils import turn_animation_into_updater
def test_turn_animation_into_updater_zero_run_time():
"""Test that turn_animation_into_updater handles zero run_time correctly."""
# Create a simple mobject and animation
mobject = Circle()
animation = FadeIn(mobject, run_time=0)
# Track updater calls
update_calls = []
original_updaters = mobject.updaters.copy()
# Call turn_animation_into_updater
result = turn_animation_into_updater(animation)
# Verify mobject is returned
assert result is mobject
# Get the updater that was added
assert len(mobject.updaters) == len(original_updaters) + 1
updater = mobject.updaters[-1]
# Simulate calling the updater
updater(mobject, dt=0.1)
# The updater should have finished and removed itself
assert len(mobject.updaters) == len(original_updaters)
assert updater not in mobject.updaters
# Animation should be in finished state
assert animation.total_time >= 0
def test_turn_animation_into_updater_positive_run_time_persists():
"""Test that updater persists with positive run_time."""
mobject = Circle()
animation = FadeIn(mobject, run_time=1.0)
original_updaters = mobject.updaters.copy()
# Call turn_animation_into_updater
result = turn_animation_into_updater(animation)
# Get the updater that was added
updater = mobject.updaters[-1]
# Simulate calling the updater (partial progress)
updater(mobject, dt=0.1)
# The updater should still be present (not finished)
assert len(mobject.updaters) == len(original_updaters) + 1
assert updater in mobject.updaters