Don't write new file when inserting embed line

Instead, load the relevant module of the true file, and execute the modified code within that.

This also cleans up some of the previous now-unnecessary code around get_module_with_inserted_embed_line
This commit is contained in:
Grant Sanderson
2024-12-06 11:05:57 -07:00
parent dd0aa14442
commit fadd045fc1
2 changed files with 15 additions and 35 deletions

View File

@ -207,20 +207,18 @@ def get_manim_dir():
return os.path.abspath(os.path.join(manimlib_dir, "..")) return os.path.abspath(os.path.join(manimlib_dir, ".."))
def get_indent(code_lines: list[str], line_number: int): def get_indent(code_lines: list[str], line_number: int) -> str:
for line in code_lines[line_number:0:-1]: for line in code_lines[line_number - 1::-1]:
if len(line.strip()) == 0: if len(line.strip()) == 0:
continue continue
n_spaces = len(line) - len(line.lstrip()) n_spaces = len(line) - len(line.lstrip())
if line.endswith(":"): if line.endswith(":"):
n_spaces += 4 n_spaces += 4
return n_spaces return n_spaces * " "
return 0 return ""
def get_module_with_inserted_embed_line( def get_module_with_inserted_embed_line(file_name: str, line_number: int):
file_name: str, scene_name: str, line_number: int
):
""" """
This is hacky, but convenient. When user includes the argument "-e", it will try This is hacky, but convenient. When user includes the argument "-e", it will try
to recreate a file that inserts the line `self.embed()` into the end of the scene's to recreate a file that inserts the line `self.embed()` into the end of the scene's
@ -229,31 +227,18 @@ def get_module_with_inserted_embed_line(
""" """
lines = Path(file_name).read_text().splitlines() lines = Path(file_name).read_text().splitlines()
scene_line_numbers = [ # Add the relevant embed line to the code
n for n, line in enumerate(lines) indent = get_indent(lines, line_number)
if line.startswith("class SurfaceTest") lines.insert(line_number, indent + "self.embed()")
] new_code = "\n".join(lines)
if len(scene_line_numbers) == 0:
log.error(f"No scene {scene_name}")
return
scene_line_number = scene_line_numbers[0]
n_spaces = get_indent(lines, line_number - 1)
inserted_line = " " * n_spaces + "self.embed()"
new_lines = list(lines)
new_lines.insert(line_number, inserted_line)
new_file = file_name.replace(".py", "_insert_embed.py")
Path(new_file).write_text("\n".join(new_lines))
# Load the module for the original file, then exectue the new code within
# it, which should redefined the scene to have the inserted embed line
from manimlib.reload_manager import reload_manager from manimlib.reload_manager import reload_manager
module = ModuleLoader.get_module(new_file, is_during_reload=reload_manager.is_reload) module = ModuleLoader.get_module(file_name, is_during_reload=reload_manager.is_reload)
# This is to pretend the module imported from the edited lines
# of code actually comes from the original file.
module.__file__ = file_name
os.remove(new_file)
code_object = compile(new_code, module.__name__, 'exec')
exec(code_object, module.__dict__)
return module return module
@ -261,9 +246,7 @@ def get_scene_module(args: Namespace) -> Module:
if args.embed is None: if args.embed is None:
return ModuleLoader.get_module(args.file) return ModuleLoader.get_module(args.file)
else: else:
return get_module_with_inserted_embed_line( return get_module_with_inserted_embed_line(args.file, int(args.embed))
args.file, args.scene_names[0], int(args.embed)
)
def load_yaml(file_path: str): def load_yaml(file_path: str):

View File

@ -76,10 +76,7 @@ class ModuleLoader:
builtins.__import__ = tracked_import builtins.__import__ = tracked_import
try: try:
# Remove the "_insert_embed" suffix from the module name
module_name = module.__name__ module_name = module.__name__
if module.__name__.endswith("_insert_embed"):
module_name = module_name[:-13]
log.debug('Reloading module "%s"', module_name) log.debug('Reloading module "%s"', module_name)
spec.loader.exec_module(module) spec.loader.exec_module(module)