11"""Utilities for using Manim with IPython (in particular: Jupyter notebooks)"""
22
3- import hashlib
43import mimetypes
5- import os
6- import shutil
74from pathlib import Path
85
9- from manim import config , tempconfig
6+ from manim .__main__ import main
7+ from click .testing import CliRunner
108
119try :
12- from IPython import get_ipython
1310 from IPython .core .magic import (
1411 Magics ,
1512 magics_class ,
@@ -62,73 +59,26 @@ def construct(self):
6259 """
6360 if cell :
6461 exec (cell , local_ns )
65-
66- cli_args = ["manim" , "" ] + line .split ()
67- if len (cli_args ) == 2 :
68- # empty line.split(): no commands have been passed, call with -h
69- cli_args .append ("-h" )
70-
71- class ClickArgs :
72- def __init__ (self , args ):
73- for name in args :
74- setattr (self , name , args [name ])
75-
76- def _get_kwargs (self ):
77- return list (self .__dict__ .items ())
78-
79- def __eq__ (self , other ):
80- if not isinstance (other , ClickArgs ):
81- return NotImplemented
82- return vars (self ) == vars (other )
83-
84- def __contains__ (self , key ):
85- return key in self .__dict__
86-
87- try :
88- args = ClickArgs (cli_args )
89- except SystemExit :
90- return # probably manim -h was called, process ended preemptively
91-
92- with tempconfig (local_ns .get ("config" , {})):
93- config .digest_args (args )
94-
95- exec (f"{ config ['scene_names' ][0 ]} ().render()" , local_ns )
96- local_path = Path (config ["output_file" ]).relative_to (Path .cwd ())
97- tmpfile = (
98- Path (config ["media_dir" ])
99- / "jupyter"
100- / f"{ _video_hash (local_path )} { local_path .suffix } "
101- )
102-
103- if local_path in self .rendered_files :
104- self .rendered_files [local_path ].unlink ()
105- self .rendered_files [local_path ] = tmpfile
106- os .makedirs (tmpfile .parent , exist_ok = True )
107- shutil .copy (local_path , tmpfile )
108-
109- file_type = mimetypes .guess_type (config ["output_file" ])[0 ]
110- if file_type .startswith ("image" ):
111- display (Image (filename = config ["output_file" ]))
112- return
113-
114- # videos need to be embedded when running in google colab
115- video_embed = "google.colab" in str (get_ipython ())
116-
117- display (
118- Video (
119- tmpfile ,
120- html_attributes = 'controls autoplay loop style="max-width: 100%;"' ,
121- embed = video_embed ,
122- )
62+ args = line .split ()
63+ if not len (args ) or "-h" in args or "--help" in args or "--version" in args :
64+ main .main (args , standalone_mode = False )
65+ return
66+
67+ runner = CliRunner () # This runs the command.
68+ result = runner .invoke (main , args , input = cell )
69+
70+ config = main .main (["--jupyter" ]+ args , standalone_mode = False ) # This runs the render subcommand, but returns config
71+ file = Path (config .output_file )
72+
73+ file_type = mimetypes .guess_type (file )[0 ]
74+ if file_type .startswith ("image" ):
75+ display (Image (filename = config ["output_file" ]))
76+ return
77+
78+ display (
79+ Video (
80+ file ,
81+ html_attributes = 'controls autoplay loop style="max-width: 100%;"' ,
82+ embed = True ,
12383 )
124-
125-
126- def _video_hash (path ):
127- sha1 = hashlib .sha1 ()
128- with open (path , "rb" ) as f :
129- while True :
130- data = f .read (65536 )
131- if not data :
132- break
133- sha1 .update (data )
134- return sha1 .hexdigest ()
84+ )
0 commit comments