1
1
"""Utilities for using Manim with IPython (in particular: Jupyter notebooks)"""
2
2
3
- import hashlib
4
3
import mimetypes
5
- import os
6
- import shutil
7
4
from pathlib import Path
8
5
9
- from manim import config , tempconfig
6
+ from manim .__main__ import main
7
+ from click .testing import CliRunner
10
8
11
9
try :
12
- from IPython import get_ipython
13
10
from IPython .core .magic import (
14
11
Magics ,
15
12
magics_class ,
@@ -62,73 +59,26 @@ def construct(self):
62
59
"""
63
60
if cell :
64
61
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 ,
123
83
)
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