From 5a4fed87a94ab49d641ff343f0695437839e1a85 Mon Sep 17 00:00:00 2001 From: Richard Vodden Date: Fri, 31 Oct 2025 09:59:27 +0000 Subject: [PATCH 1/2] Permit rendering scenes imported into specified file --- manim/cli/render/commands.py | 4 ++-- manim/cli/render/render_options.py | 6 +++++ manim/utils/module_ops.py | 35 ++++++++++++++++++++---------- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/manim/cli/render/commands.py b/manim/cli/render/commands.py index fde82f4970..10af275a24 100644 --- a/manim/cli/render/commands.py +++ b/manim/cli/render/commands.py @@ -101,7 +101,7 @@ 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 +118,7 @@ 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..e638feed9a 100644 --- a/manim/utils/module_ops.py +++ b/manim/utils/module_ops.py @@ -69,16 +69,25 @@ 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 +148,7 @@ 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 +157,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 +166,15 @@ 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) From d3f6a6768a4f5eea6b9bd678a866778ff100bbdd Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 31 Oct 2025 10:01:25 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- manim/cli/render/commands.py | 8 ++++++-- manim/utils/module_ops.py | 18 ++++++++++++++---- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/manim/cli/render/commands.py b/manim/cli/render/commands.py index 10af275a24..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, include_imported=kwargs["render_imported_scenes"]): + 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, include_imported=kwargs["render_imported_scenes"]): + for SceneClass in scene_classes_from_file( + file, include_imported=kwargs["render_imported_scenes"] + ): try: with tempconfig({}): scene = SceneClass() diff --git a/manim/utils/module_ops.py b/manim/utils/module_ops.py index e638feed9a..0b58d263c3 100644 --- a/manim/utils/module_ops.py +++ b/manim/utils/module_ops.py @@ -69,10 +69,13 @@ def get_module(file_name: Path) -> types.ModuleType: raise FileNotFoundError(f"{file_name} not found") -def get_scene_classes_from_module(module: types.ModuleType, include_imported: bool = False) -> list[type[Scene]]: +def get_scene_classes_from_module( + module: types.ModuleType, include_imported: bool = False +) -> list[type[Scene]]: from ..scene.scene import Scene - + if include_imported: + def is_child_scene(obj: Any, module: types.ModuleType) -> bool: return ( inspect.isclass(obj) @@ -81,6 +84,7 @@ def is_child_scene(obj: Any, module: types.ModuleType) -> bool: and not obj.__module__.startswith("manim.") ) else: + def is_child_scene(obj: Any, module: types.ModuleType) -> bool: return ( inspect.isclass(obj) @@ -148,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], include_imported: bool = False + file_path: Path, + require_single_scene: bool, + full_list: Literal[True], + include_imported: bool = False, ) -> list[type[Scene]]: ... @@ -171,7 +178,10 @@ def scene_classes_from_file( def scene_classes_from_file( - file_path: Path, require_single_scene: bool = False, full_list: bool = False, include_imported: 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, include_imported)