Skip to content

Commit 9aef19f

Browse files
committed
Move validate_run_time to Scene and fix some tests in test_animation.py
1 parent 5be4c13 commit 9aef19f

File tree

4 files changed

+48
-38
lines changed

4 files changed

+48
-38
lines changed

manim/animation/animation.py

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
from manim.mobject.opengl.opengl_mobject import OpenGLMobject
1414

15-
from .. import config, logger
15+
from .. import logger
1616
from ..mobject import mobject
1717
from ..mobject.mobject import Group, Mobject
1818
from ..mobject.opengl import opengl_mobject
@@ -224,7 +224,6 @@ def begin(self) -> None:
224224
method.
225225
226226
"""
227-
self.run_time = validate_run_time(self.run_time, str(self))
228227
self.starting_mobject = self.create_starting_mobject()
229228
if self.suspend_mobject_updating:
230229
# All calls to self.mobject's internal updaters
@@ -567,33 +566,6 @@ def prepare_animation(
567566
raise TypeError(f"Object {anim} cannot be converted to an animation") from None
568567

569568

570-
def validate_run_time(
571-
run_time: float, caller_name: str, parameter_name: str = "run_time"
572-
) -> float:
573-
if run_time <= 0:
574-
raise ValueError(
575-
f"{caller_name} has a {parameter_name} of {run_time:g} <= 0 "
576-
f"seconds which Manim cannot render. Please set the "
577-
f"{parameter_name} to a positive number."
578-
)
579-
580-
# config.frame_rate holds the number of frames per second
581-
fps = config.frame_rate
582-
seconds_per_frame = 1 / fps
583-
if run_time < seconds_per_frame:
584-
logger.warning(
585-
f"The original {parameter_name} of {caller_name}, {run_time:g} "
586-
f"seconds, is too short for the current frame rate of {fps:g} "
587-
f"FPS. Rendering with the shortest possible {parameter_name} of "
588-
f"{seconds_per_frame:g} seconds instead."
589-
)
590-
new_run_time = seconds_per_frame
591-
else:
592-
new_run_time = run_time
593-
594-
return new_run_time
595-
596-
597569
class Wait(Animation):
598570
"""A "no operation" animation.
599571
@@ -633,7 +605,7 @@ def __init__(
633605
super().__init__(None, run_time=run_time, rate_func=rate_func, **kwargs)
634606

635607
def begin(self) -> None:
636-
self.run_time = validate_run_time(self.run_time, str(self))
608+
pass
637609

638610
def finish(self) -> None:
639611
pass

manim/animation/composition.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import numpy as np
99

1010
from manim._config import config
11-
from manim.animation.animation import Animation, prepare_animation, validate_run_time
11+
from manim.animation.animation import Animation, prepare_animation
1212
from manim.constants import RendererType
1313
from manim.mobject.mobject import Group, Mobject
1414
from manim.mobject.opengl.opengl_mobject import OpenGLGroup
@@ -93,7 +93,6 @@ def begin(self) -> None:
9393
anim.begin()
9494
self.process_subanimation_buffer(anim.buffer)
9595

96-
self.run_time = validate_run_time(self.run_time, str(self))
9796
self.anim_group_time = 0.0
9897
if self.suspend_mobject_updating:
9998
self.group.suspend_updating()
@@ -238,7 +237,6 @@ def begin(self) -> None:
238237
f"Trying to play {self} without animations, this is not supported. "
239238
"Please add at least one subanimation."
240239
)
241-
self.run_time = validate_run_time(self.run_time, str(self))
242240
self.update_active_animation(0)
243241

244242
def finish(self) -> None:

manim/scene/scene.py

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from typing_extensions import assert_never
1111

1212
from manim import config, logger
13-
from manim.animation.animation import prepare_animation, validate_run_time
13+
from manim.animation.animation import prepare_animation
1414
from manim.animation.scene_buffer import SceneBuffer, SceneOperation
1515
from manim.camera.camera import Camera
1616
from manim.constants import DEFAULT_WAIT_TIME
@@ -353,6 +353,35 @@ def finish_animations(self, animations: Iterable[AnimationProtocol]) -> None:
353353
animation.finish()
354354
self.process_buffer(animation.buffer)
355355

356+
@classmethod
357+
def validate_run_time(
358+
cls,
359+
run_time: float,
360+
method: Callable[[Any, ...], Any],
361+
parameter_name: str = "run_time",
362+
) -> float:
363+
method_name = f"{cls.__name__}.{method.__name__}()"
364+
if run_time <= 0:
365+
raise ValueError(
366+
f"{method_name} has a {parameter_name} of "
367+
f"{run_time:g} <= 0 seconds which Manim cannot render. "
368+
f"The {parameter_name} must be a positive number."
369+
)
370+
371+
# config.frame_rate holds the number of frames per second
372+
fps = config.frame_rate
373+
seconds_per_frame = 1 / fps
374+
if run_time < seconds_per_frame:
375+
logger.warning(
376+
f"The original {parameter_name} of {method_name}, "
377+
f"{run_time:g} seconds, is too short for the current frame "
378+
f"rate of {fps:g} FPS. Rendering with the shortest possible "
379+
f"{parameter_name} of {seconds_per_frame:g} seconds instead."
380+
)
381+
run_time = seconds_per_frame
382+
383+
return run_time
384+
356385
def play(
357386
self,
358387
# the OpenGLMobject is a side-effect of the return type of animate, it will
@@ -367,11 +396,21 @@ def play(
367396
if len(proto_animations) == 0:
368397
logger.warning("Called Scene.play with no animations")
369398
return
370-
# build animationbuilders
399+
400+
# Build _AnimationBuilders.
371401
animations = [prepare_animation(x) for x in proto_animations]
372402
for anim in animations:
373403
anim.update_rate_info(run_time, rate_func, lag_ratio)
374404

405+
# Validate the final run_time.
406+
total_run_time = max(anim.get_run_time() for anim in animations)
407+
new_total_run_time = self.validate_run_time(
408+
total_run_time, self.play, "total run_time"
409+
)
410+
if new_total_run_time != total_run_time:
411+
for anim in animations:
412+
anim.update_rate_info(new_total_run_time)
413+
375414
# NOTE: Should be changed at some point with the 2 pass rendering system 21.06.2024
376415
self.manager._play(*animations)
377416

@@ -382,7 +421,7 @@ def wait(
382421
note: str | None = None,
383422
ignore_presenter_mode: bool = False,
384423
):
385-
duration = validate_run_time(duration, str(self) + ".wait()", "duration")
424+
duration = self.validate_run_time(duration, self.wait, "duration")
386425
self.manager._wait(duration, stop_condition=stop_condition)
387426
# if (
388427
# self.presenter_mode
@@ -394,7 +433,7 @@ def wait(
394433
# self.hold_loop()
395434

396435
def wait_until(self, stop_condition: Callable[[], bool], max_time: float = 60):
397-
max_time = validate_run_time(max_time, str(self) + ".wait_until()", "max_time")
436+
max_time = self.validate_run_time(max_time, self.wait_until, "max_time")
398437
self.wait(max_time, stop_condition=stop_condition)
399438

400439
def add_sound(

tests/module/animation/test_animation.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ def test_pause_invalid_duration(duration):
5858

5959
@pytest.mark.parametrize("max_time", [0, -1])
6060
def test_wait_until_invalid_max_time(max_time):
61-
test_scene = Manager(Scene)
61+
manager = Manager(Scene)
62+
test_scene = manager.scene
6263
with pytest.raises(ValueError, match="The max_time must be a positive number."):
6364
test_scene.wait_until(lambda: True, max_time)

0 commit comments

Comments
 (0)