diff --git a/manim/scene/scene.py b/manim/scene/scene.py index fc3d3ede54..da9073d5ff 100644 --- a/manim/scene/scene.py +++ b/manim/scene/scene.py @@ -464,6 +464,9 @@ def add(self, *mobjects: Mobject): The same scene after adding the Mobjects in. """ + # Allows passing an iterable of mobjects without unpacking it first + mobjects = flatten_iterable_parameters(mobjects) + if config.renderer == RendererType.OPENGL: new_mobjects = [] new_meshes = [] @@ -899,9 +902,10 @@ def compile_animations( Tuple[:class:`Animation`] Animations to be played. """ - animations = [] + # Allow passing a generator or any iterable to self.play instead of comma separated arguments + # and also without needing to unpack it first arg_anims = flatten_iterable_parameters(args) - # Allow passing a generator to self.play instead of comma separated arguments + animations = [] for arg in arg_anims: try: animations.append(prepare_animation(arg)) diff --git a/manim/utils/parameter_parsing.py b/manim/utils/parameter_parsing.py index d3676c7301..7d57f36cc9 100644 --- a/manim/utils/parameter_parsing.py +++ b/manim/utils/parameter_parsing.py @@ -25,8 +25,14 @@ def flatten_iterable_parameters( """ flattened_parameters: list[T] = [] for arg in args: - if isinstance(arg, (Iterable, GeneratorType)): + # If we want to pass a Mobject, we must consider that it is technically iterable + # because it defines `__iter__()`. However, Mobject and its subclasses should be + # treated as single objects rather than being expanded. To identify them, + # we check for the `submobjects` attribute. + if isinstance(arg, (Iterable, GeneratorType)) and not hasattr( + arg, "submobjects" + ): flattened_parameters.extend(arg) else: - flattened_parameters.append(arg) + flattened_parameters.append(arg) # type: ignore[arg-type] return flattened_parameters