Repository: ManimCommunity/manim
File: manim/animation/speedmodifier.py (Python)

Code before:
            )
        else:
            mobject.add_updater(update_function, index=index, call_updater=call_updater)

    def interpolate(self, alpha: float) -> None:
        self.anim.interpolate(alpha)

    def update_mobjects(self, dt: float) -> None:
        self.anim.update_mobjects(dt)

    def finish(self) -> None:
        ChangeSpeed.changed = False
        self.anim.finish()

    def begin(self) -> None:
        ChangeSpeed.changed = True
        self.anim.begin()

    def clean_up_from_scene(self, scene: Scene) -> None:
        self.anim.clean_up_from_scene(scene)

    def _setup_scene(self, scene) -> None:
        self.anim._setup_scene(scene)


class ChangedWait(Wait):
    """
    Wait animation but follows `rate_func`
    """

    def __init__(
        self,
        run_time: float = 1,
        stop_condition: Callable[[], bool] | None = None,
        frozen_frame: bool | None = None,
        rate_func: Callable[[float], float] = linear,
        **kwargs,
    ):
        super().__init__(
            run_time=run_time,
            rate_func=rate_func,
            stop_condition=stop_condition,
            frozen_frame=frozen_frame,
            **kwargs,
        )

    def interpolate(self, alpha: float) -> None:
        self.get_sub_alpha(alpha, 0, 0)


Review comment (suggestion):
If I understand correctly, this change is necessary because you need the `interpolate` method to call the rate function, right? If this is the sole reason, then this still feels a bit convoluted; my suggestion would be to locally assign `wait_animation_object.interpolate` to a bound method which explicitly evaluates `self.rate_func(alpha)`, and does nothing else.

What about doing something like this instead (if it works)?

```
if type(anim) is Wait:
    anim.interpolate = types.MethodType(lambda self, alpha: self.rate_func(alpha), anim)
```

Code after:
            rate_func=self.rate_func,
            run_time=scaled_total_time * self.anim.run_time,
            **kwargs,
        )

    def setup(self, anim):
        if type(anim) is Wait:
            anim.interpolate = types.MethodType(
                lambda self, alpha: self.rate_func(alpha), anim
            )
        return prepare_animation(anim)

    def get_scaled_total_time(self) -> float:
        """The time taken by the animation under the assumption that the ``run_time`` is 1."""
        prevnode = 0
        init_speed = self.speedinfo[0]
        total_time = 0
        for node, final_speed in list(self.speedinfo.items())[1:]:
            dur = node - prevnode
            total_time += dur * self.f_inv_1(init_speed, final_speed)
            prevnode = node
            init_speed = final_speed
        return total_time

    @classmethod
    def add_updater(
        self,
        mobject: Mobject,
        update_function: Updater,
        index: int | None = None,
        call_updater: bool = False,
    ):
        """This static method can be used to apply speed change to updaters.

        This updater will follow speed and rate function of any :class:`.ChangeSpeed`
        animation that is playing with ``affects_speed_updaters=True``. By default,
        updater functions added via the usual :meth:`.Mobject.add_updater` method
        do not respect the change of animation speed.

        Parameters
        ----------
        mobject
            The mobject to which the updater should be attached.
        update_function
            The function that is called whenever a new frame is rendered.
        index
            The position in the list of the mobject's updaters at which the
            function should be inserted.
        call_updater
            If ``True``, calls the update function when attaching it to the
            mobject.