34
34
from watchdog .events import DirModifiedEvent , FileModifiedEvent , FileSystemEventHandler
35
35
from watchdog .observers import Observer
36
36
37
+ from manim .data_structures import MethodWithArgs , SceneInteractExit , SceneInteractRerun
37
38
from manim .mobject .mobject import Mobject
38
39
from manim .mobject .opengl .opengl_mobject import OpenGLPoint
39
40
55
56
if TYPE_CHECKING :
56
57
from collections .abc import Iterable , Sequence
57
58
from types import FrameType
58
- from typing import Any , Callable , TypeAlias
59
+ from typing import Any , Callable , TypeAlias , Union
59
60
60
61
from typing_extensions import Self
61
62
62
63
from manim .typing import Point3D
63
64
64
- SceneInteractAction : TypeAlias = tuple [str , Iterable [Any ], dict [str , Any ]]
65
- """
66
- The SceneInteractAction type alias is used for elements in the queue
65
+ SceneInteractAction : TypeAlias = Union [
66
+ MethodWithArgs , SceneInteractExit , SceneInteractRerun
67
+ ]
68
+ """The SceneInteractAction type alias is used for elements in the queue
67
69
used by Scene.interact().
68
- The elements consist consist of:
69
70
70
- - a string, which is either the name of a Scene method or some special keyword
71
- starting with "rerun" or "exit",
72
- - a list of args for the Scene method (only used if the first string actually
73
- corresponds to a method) and
74
- - a dict of kwargs for the Scene method (if the first string corresponds to one.
75
- Otherwise, currently Scene.interact() extracts a possible "from_animation_number" from it if the first string starts with "rerun"),
76
- as seen around the source code where it's common to use self.queue.put((method_name, [], {})) and similar items.
71
+ The elements can be one of the following three:
77
72
73
+ - a :class:`~.MethodWithArgs` object, which represents a :class:`Scene`
74
+ method to be called along with its args and kwargs,
75
+ - a :class:`~.SceneInteractExit` object, indicating that the scene
76
+ interaction is over, or
77
+ - a :class:`~.SceneInteractRerun` object, indicating that the scene should
78
+ render again.
78
79
"""
79
80
80
81
@@ -86,7 +87,7 @@ def __init__(self, queue: Queue[SceneInteractAction]) -> None:
86
87
self .queue = queue
87
88
88
89
def on_modified (self , event : DirModifiedEvent | FileModifiedEvent ) -> None :
89
- self .queue .put (( "rerun_file" , [], {} ))
90
+ self .queue .put (SceneInteractRerun ( "file" ))
90
91
91
92
92
93
class Scene :
@@ -1102,20 +1103,15 @@ def play(
1102
1103
and config .renderer == RendererType .OPENGL
1103
1104
and threading .current_thread ().name != "MainThread"
1104
1105
):
1106
+ # TODO: are these actually being used?
1105
1107
kwargs .update (
1106
1108
{
1107
1109
"subcaption" : subcaption ,
1108
1110
"subcaption_duration" : subcaption_duration ,
1109
1111
"subcaption_offset" : subcaption_offset ,
1110
1112
}
1111
1113
)
1112
- self .queue .put (
1113
- (
1114
- "play" ,
1115
- args ,
1116
- kwargs ,
1117
- )
1118
- )
1114
+ self .queue .put (SceneInteractRerun ("play" , ** kwargs ))
1119
1115
return
1120
1116
1121
1117
start_time = self .time
@@ -1359,17 +1355,19 @@ def load_module_into_namespace(
1359
1355
load_module_into_namespace (manim .opengl , namespace )
1360
1356
1361
1357
def embedded_rerun (* args : Any , ** kwargs : Any ) -> None :
1362
- self .queue .put (( "rerun_keyboard" , args , kwargs ))
1358
+ self .queue .put (SceneInteractRerun ( "keyboard" ))
1363
1359
shell .exiter ()
1364
1360
1365
1361
namespace ["rerun" ] = embedded_rerun
1366
1362
1367
1363
shell (local_ns = namespace )
1368
- self .queue .put (( "exit_keyboard" , [], {} ))
1364
+ self .queue .put (SceneInteractExit ( "keyboard" ))
1369
1365
1370
1366
def get_embedded_method (method_name : str ) -> Callable [..., None ]:
1367
+ method = getattr (self , method_name )
1368
+
1371
1369
def embedded_method (* args : Any , ** kwargs : Any ) -> None :
1372
- self .queue .put (( method_name , args , kwargs ))
1370
+ self .queue .put (MethodWithArgs ( method , args , kwargs ))
1373
1371
1374
1372
return embedded_method
1375
1373
@@ -1434,34 +1432,33 @@ def interact(self, shell: Any, keyboard_thread: threading.Thread) -> None:
1434
1432
last_time = time .time ()
1435
1433
while not (self .renderer .window .is_closing or self .quit_interaction ):
1436
1434
if not self .queue .empty ():
1437
- tup = self .queue .get_nowait ()
1438
- if tup [ 0 ]. startswith ( "rerun" ):
1435
+ action = self .queue .get_nowait ()
1436
+ if isinstance ( action , SceneInteractRerun ):
1439
1437
# Intentionally skip calling join() on the file thread to save time.
1440
- if not tup [ 0 ]. endswith ( "keyboard" ) :
1438
+ if action . sender != "keyboard" :
1441
1439
if shell .pt_app :
1442
1440
shell .pt_app .app .exit (exception = EOFError )
1443
1441
file_observer .unschedule_all ()
1444
1442
raise RerunSceneException
1445
1443
keyboard_thread .join ()
1446
1444
1447
- kwargs = tup [2 ]
1448
- if "from_animation_number" in kwargs :
1449
- config ["from_animation_number" ] = kwargs [
1445
+ if "from_animation_number" in action .kwargs :
1446
+ config ["from_animation_number" ] = action .kwargs [
1450
1447
"from_animation_number"
1451
1448
]
1452
1449
# # TODO: This option only makes sense if interactive_embed() is run at the
1453
1450
# # end of a scene by default.
1454
- # if "upto_animation_number" in kwargs:
1455
- # config["upto_animation_number"] = kwargs[
1451
+ # if "upto_animation_number" in action. kwargs:
1452
+ # config["upto_animation_number"] = action. kwargs[
1456
1453
# "upto_animation_number"
1457
1454
# ]
1458
1455
1459
1456
keyboard_thread .join ()
1460
1457
file_observer .unschedule_all ()
1461
1458
raise RerunSceneException
1462
- elif tup [ 0 ]. startswith ( "exit" ):
1459
+ elif isinstance ( action , SceneInteractExit ):
1463
1460
# Intentionally skip calling join() on the file thread to save time.
1464
- if not tup [ 0 ]. endswith ( "keyboard" ) and shell .pt_app :
1461
+ if action . sender != "keyboard" and shell .pt_app :
1465
1462
shell .pt_app .app .exit (exception = EOFError )
1466
1463
keyboard_thread .join ()
1467
1464
# Remove exit_keyboard from the queue if necessary.
@@ -1470,8 +1467,7 @@ def interact(self, shell: Any, keyboard_thread: threading.Thread) -> None:
1470
1467
keyboard_thread_needs_join = False
1471
1468
break
1472
1469
else :
1473
- method , args , kwargs = tup
1474
- getattr (self , method )(* args , ** kwargs )
1470
+ action .method (* action .args , ** action .kwargs )
1475
1471
else :
1476
1472
self .renderer .animation_start_time = 0
1477
1473
dt = time .time () - last_time
0 commit comments