diff --git a/manim/cli/render/commands.py b/manim/cli/render/commands.py index fde82f4970..29a82d92dd 100644 --- a/manim/cli/render/commands.py +++ b/manim/cli/render/commands.py @@ -101,7 +101,9 @@ def render(**kwargs: Any) -> ClickArgs | dict[str, Any]: renderer = OpenGLRenderer() keep_running = True while keep_running: - for SceneClass in scene_classes_from_file(file): + for SceneClass in scene_classes_from_file( + file, include_imported=kwargs["render_imported_scenes"] + ): with tempconfig({}): scene = SceneClass(renderer) rerun = scene.render() @@ -118,7 +120,9 @@ def render(**kwargs: Any) -> ClickArgs | dict[str, Any]: error_console.print_exception() sys.exit(1) else: - for SceneClass in scene_classes_from_file(file): + for SceneClass in scene_classes_from_file( + file, include_imported=kwargs["render_imported_scenes"] + ): try: with tempconfig({}): scene = SceneClass() diff --git a/manim/cli/render/render_options.py b/manim/cli/render/render_options.py index 9a31d36ed4..b9e1c6a208 100644 --- a/manim/cli/render/render_options.py +++ b/manim/cli/render/render_options.py @@ -212,4 +212,10 @@ def validate_resolution( help="Use shaders for OpenGLVMobject stroke which are compatible with transformation matrices.", default=None, ), + option( + "--render_imported_scenes", + is_flag=True, + help="Also render scenes which have been imported into the specified file.", + default=None, + ), ) diff --git a/manim/utils/module_ops.py b/manim/utils/module_ops.py index e4d921d8b3..0b58d263c3 100644 --- a/manim/utils/module_ops.py +++ b/manim/utils/module_ops.py @@ -69,16 +69,29 @@ def get_module(file_name: Path) -> types.ModuleType: raise FileNotFoundError(f"{file_name} not found") -def get_scene_classes_from_module(module: types.ModuleType) -> list[type[Scene]]: +def get_scene_classes_from_module( + module: types.ModuleType, include_imported: bool = False +) -> list[type[Scene]]: from ..scene.scene import Scene - def is_child_scene(obj: Any, module: types.ModuleType) -> bool: - return ( - inspect.isclass(obj) - and issubclass(obj, Scene) - and obj != Scene - and obj.__module__.startswith(module.__name__) - ) + if include_imported: + + def is_child_scene(obj: Any, module: types.ModuleType) -> bool: + return ( + inspect.isclass(obj) + and issubclass(obj, Scene) + and obj != Scene + and not obj.__module__.startswith("manim.") + ) + else: + + def is_child_scene(obj: Any, module: types.ModuleType) -> bool: + return ( + inspect.isclass(obj) + and issubclass(obj, Scene) + and obj != Scene + and obj.__module__ == module.__name__ + ) return [ member[1] @@ -139,7 +152,10 @@ def prompt_user_for_choice(scene_classes: list[type[Scene]]) -> list[type[Scene] @overload def scene_classes_from_file( - file_path: Path, require_single_scene: bool, full_list: Literal[True] + file_path: Path, + require_single_scene: bool, + full_list: Literal[True], + include_imported: bool = False, ) -> list[type[Scene]]: ... @@ -148,6 +164,7 @@ def scene_classes_from_file( file_path: Path, require_single_scene: Literal[True], full_list: Literal[False] = False, + include_imported: bool = False, ) -> type[Scene]: ... @@ -156,14 +173,18 @@ def scene_classes_from_file( file_path: Path, require_single_scene: Literal[False] = False, full_list: Literal[False] = False, + include_imported: bool = False, ) -> list[type[Scene]]: ... def scene_classes_from_file( - file_path: Path, require_single_scene: bool = False, full_list: bool = False + file_path: Path, + require_single_scene: bool = False, + full_list: bool = False, + include_imported: bool = False, ) -> type[Scene] | list[type[Scene]]: module = get_module(file_path) - all_scene_classes = get_scene_classes_from_module(module) + all_scene_classes = get_scene_classes_from_module(module, include_imported) if full_list: return all_scene_classes scene_classes_to_render = get_scenes_to_render(all_scene_classes)