mirror of
https://github.com/3b1b/manim.git
synced 2025-08-02 11:03:03 +08:00
Add reload()
command for interactive scene reloading (#2240)
* Init reload command (lots of things not working yet)
* Add back in class line (accidentally deleted)
* Add back in key modifiers (accidentally deleted)
* Unpack tuple from changed `get_module`
* Init MainRunManager & respawn IPython shell
* Init cleanup of scenes from manager
* Restore string quotes
* Still take `self.preview` into account
* Remove left-over code from module experimentation
* Remove double window activation
* Reset scenes array in RunManager
* Move self.args None check up
* Use first available window
* Don't use constructor for RunManager
* Use self. syntax
* Init moderngl context manually
* Add some comments for failed attempts to reset scene
* Reuse existing shell (this fixed the bug 🎉)
* Remove unused code
* Remove unnecessary intermediate ReloadSceneException
* Allow users to finally exit
* Rename main_run_manager to reload_manager
* Add docstrings to `ReloadManager`
* Improve reset management in window
* Clarify why we use magic exit_raise command
* Add comment about window reuse
* Improve docstrings in ReloadManager & handle case of 0 scenes
* Set scene and title earlier
* Run linter suggestions
This commit is contained in:
84
manimlib/reload_manager.py
Normal file
84
manimlib/reload_manager.py
Normal file
@ -0,0 +1,84 @@
|
||||
from typing import Any
|
||||
from IPython.terminal.embed import KillEmbedded
|
||||
|
||||
|
||||
class ReloadManager:
|
||||
"""
|
||||
Manages the loading and running of scenes and is called directly from the
|
||||
main entry point of ManimGL.
|
||||
|
||||
The name "reload" comes from the fact that this class handles the
|
||||
reinitialization of scenes when requested by the user via the `reload()`
|
||||
command in the IPython shell.
|
||||
"""
|
||||
|
||||
args: Any = None
|
||||
scenes: list[Any] = []
|
||||
window = None
|
||||
|
||||
# The line number to load the scene from when reloading
|
||||
start_at_line = None
|
||||
|
||||
def set_new_start_at_line(self, start_at_line):
|
||||
"""
|
||||
Sets/Updates the line number to load the scene from when reloading.
|
||||
"""
|
||||
self.start_at_line = start_at_line
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
Runs the scenes in a loop and detects when a scene reload is requested.
|
||||
"""
|
||||
while True:
|
||||
try:
|
||||
# blocking call since a scene will init an IPython shell()
|
||||
self.retrieve_scenes_and_run(self.start_at_line)
|
||||
return
|
||||
except KillEmbedded:
|
||||
# Requested via the `exit_raise` IPython runline magic
|
||||
# by means of our scene.reload() command
|
||||
print("Reloading...")
|
||||
|
||||
for scene in self.scenes:
|
||||
scene.tear_down()
|
||||
|
||||
self.scenes = []
|
||||
|
||||
except KeyboardInterrupt:
|
||||
break
|
||||
|
||||
def retrieve_scenes_and_run(self, overwrite_start_at_line: int | None = None):
|
||||
"""
|
||||
Creates a new configuration based on the CLI args and runs the scenes.
|
||||
"""
|
||||
import manimlib.config
|
||||
import manimlib.extract_scene
|
||||
|
||||
# Args
|
||||
if self.args is None:
|
||||
raise RuntimeError("Fatal error: No args were passed to the ReloadManager")
|
||||
if overwrite_start_at_line is not None:
|
||||
self.args.embed = str(overwrite_start_at_line)
|
||||
|
||||
# Args to Config
|
||||
config = manimlib.config.get_configuration(self.args)
|
||||
if self.window:
|
||||
config["existing_window"] = self.window # see scene initialization
|
||||
|
||||
# Scenes
|
||||
self.scenes = manimlib.extract_scene.main(config)
|
||||
if len(self.scenes) == 0:
|
||||
print("No scenes found to run")
|
||||
return
|
||||
|
||||
# Find first available window
|
||||
for scene in self.scenes:
|
||||
if scene.window is not None:
|
||||
self.window = scene.window
|
||||
break
|
||||
|
||||
for scene in self.scenes:
|
||||
scene.run()
|
||||
|
||||
|
||||
reload_manager = ReloadManager()
|
Reference in New Issue
Block a user