Skip to content

Commit f65b7f8

Browse files
authored
Refactored run_time validation for Animation and Scene.wait() (#3982)
* Refactored Animation run_time validation * Rewrite error and warning messages, and add validations to wait(), pause() and wait_until() * Undo rewriting of imports
1 parent 20f44b4 commit f65b7f8

File tree

4 files changed

+42
-35
lines changed

4 files changed

+42
-35
lines changed

manim/animation/animation.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ def begin(self) -> None:
194194
method.
195195
196196
"""
197+
self.run_time = validate_run_time(self.run_time, str(self))
197198
self.starting_mobject = self.create_starting_mobject()
198199
if self.suspend_mobject_updating:
199200
# All calls to self.mobject's internal updaters
@@ -568,6 +569,33 @@ def prepare_animation(
568569
raise TypeError(f"Object {anim} cannot be converted to an animation")
569570

570571

572+
def validate_run_time(
573+
run_time: float, caller_name: str, parameter_name: str = "run_time"
574+
) -> float:
575+
if run_time <= 0:
576+
raise ValueError(
577+
f"{caller_name} has a {parameter_name} of {run_time:g} <= 0 "
578+
f"seconds which Manim cannot render. Please set the "
579+
f"{parameter_name} to a positive number."
580+
)
581+
582+
# config.frame_rate holds the number of frames per second
583+
fps = config.frame_rate
584+
seconds_per_frame = 1 / fps
585+
if run_time < seconds_per_frame:
586+
logger.warning(
587+
f"The original {parameter_name} of {caller_name}, {run_time:g} "
588+
f"seconds, is too short for the current frame rate of {fps:g} "
589+
f"FPS. Rendering with the shortest possible {parameter_name} of "
590+
f"{seconds_per_frame:g} seconds instead."
591+
)
592+
new_run_time = seconds_per_frame
593+
else:
594+
new_run_time = run_time
595+
596+
return new_run_time
597+
598+
571599
class Wait(Animation):
572600
"""A "no operation" animation.
573601
@@ -610,7 +638,7 @@ def __init__(
610638
self.mobject.shader_wrapper_list = []
611639

612640
def begin(self) -> None:
613-
pass
641+
self.run_time = validate_run_time(self.run_time, str(self))
614642

615643
def finish(self) -> None:
616644
pass

manim/animation/composition.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import numpy as np
1010

1111
from manim._config import config
12-
from manim.animation.animation import Animation, prepare_animation
12+
from manim.animation.animation import Animation, prepare_animation, validate_run_time
1313
from manim.constants import RendererType
1414
from manim.mobject.mobject import Group, Mobject
1515
from manim.mobject.opengl.opengl_mobject import OpenGLGroup
@@ -87,7 +87,7 @@ def begin(self) -> None:
8787
f"Trying to play {self} without animations, this is not supported. "
8888
"Please add at least one subanimation."
8989
)
90-
90+
self.run_time = validate_run_time(self.run_time, str(self))
9191
self.anim_group_time = 0.0
9292
if self.suspend_mobject_updating:
9393
self.group.suspend_updating()
@@ -235,6 +235,7 @@ def begin(self) -> None:
235235
f"Trying to play {self} without animations, this is not supported. "
236236
"Please add at least one subanimation."
237237
)
238+
self.run_time = validate_run_time(self.run_time, str(self))
238239
self.update_active_animation(0)
239240

240241
def finish(self) -> None:

manim/scene/scene.py

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
from manim.mobject.opengl.opengl_mobject import OpenGLPoint
3838

3939
from .. import config, logger
40-
from ..animation.animation import Animation, Wait, prepare_animation
40+
from ..animation.animation import Animation, Wait, prepare_animation, validate_run_time
4141
from ..camera.camera import Camera
4242
from ..constants import *
4343
from ..gui.gui import configure_pygui
@@ -1030,28 +1030,7 @@ def get_run_time(self, animations: list[Animation]):
10301030
float
10311031
The total ``run_time`` of all of the animations in the list.
10321032
"""
1033-
max_run_time = 0
1034-
frame_rate = (
1035-
1 / config.frame_rate
1036-
) # config.frame_rate holds the number of frames per second
1037-
for animation in animations:
1038-
if animation.run_time <= 0:
1039-
raise ValueError(
1040-
f"{animation} has a run_time of <= 0 seconds which Manim cannot render. "
1041-
"Please set the run_time to be positive."
1042-
)
1043-
elif animation.run_time < frame_rate:
1044-
logger.warning(
1045-
f"Original run time of {animation} is shorter than current frame "
1046-
f"rate (1 frame every {frame_rate:.2f} sec.) which cannot be rendered. "
1047-
"Rendering with the shortest possible duration instead."
1048-
)
1049-
animation.run_time = frame_rate
1050-
1051-
if animation.run_time > max_run_time:
1052-
max_run_time = animation.run_time
1053-
1054-
return max_run_time
1033+
return max(animation.run_time for animation in animations)
10551034

10561035
def play(
10571036
self,
@@ -1147,6 +1126,7 @@ def wait(
11471126
--------
11481127
:class:`.Wait`, :meth:`.should_mobjects_update`
11491128
"""
1129+
duration = validate_run_time(duration, str(self) + ".wait()", "duration")
11501130
self.play(
11511131
Wait(
11521132
run_time=duration,
@@ -1170,6 +1150,7 @@ def pause(self, duration: float = DEFAULT_WAIT_TIME):
11701150
--------
11711151
:meth:`.wait`, :class:`.Wait`
11721152
"""
1153+
duration = validate_run_time(duration, str(self) + ".pause()", "duration")
11731154
self.wait(duration=duration, frozen_frame=True)
11741155

11751156
def wait_until(self, stop_condition: Callable[[], bool], max_time: float = 60):
@@ -1183,6 +1164,7 @@ def wait_until(self, stop_condition: Callable[[], bool], max_time: float = 60):
11831164
max_time
11841165
The maximum wait time in seconds.
11851166
"""
1167+
max_time = validate_run_time(max_time, str(self) + ".wait_until()", "max_time")
11861168
self.wait(max_time, stop_condition=stop_condition)
11871169

11881170
def compile_animation_data(

tests/module/animation/test_animation.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,20 @@
1111
)
1212
def test_animation_forbidden_run_time(run_time):
1313
test_scene = Scene()
14-
with pytest.raises(ValueError, match="Please set the run_time to be positive"):
14+
with pytest.raises(
15+
ValueError, match="Please set the run_time to a positive number."
16+
):
1517
test_scene.play(FadeIn(None, run_time=run_time))
1618

1719

1820
def test_animation_run_time_shorter_than_frame_rate(manim_caplog, config):
1921
test_scene = Scene()
2022
test_scene.play(FadeIn(None, run_time=1 / (config.frame_rate + 1)))
21-
assert (
22-
"Original run time of FadeIn(Mobject) is shorter than current frame rate"
23-
in manim_caplog.text
24-
)
23+
assert "too short for the current frame rate" in manim_caplog.text
2524

2625

2726
@pytest.mark.parametrize("frozen_frame", [False, True])
2827
def test_wait_run_time_shorter_than_frame_rate(manim_caplog, frozen_frame):
2928
test_scene = Scene()
3029
test_scene.wait(1e-9, frozen_frame=frozen_frame)
31-
assert (
32-
"Original run time of Wait(Mobject) is shorter than current frame rate"
33-
in manim_caplog.text
34-
)
30+
assert "too short for the current frame rate" in manim_caplog.text

0 commit comments

Comments
 (0)