manim 0.17.0__py3-none-any.whl → 0.19.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- manim/__init__.py +11 -6
- manim/__main__.py +62 -19
- manim/_config/__init__.py +10 -9
- manim/_config/cli_colors.py +26 -9
- manim/_config/default.cfg +1 -3
- manim/_config/logger_utils.py +23 -13
- manim/_config/utils.py +662 -468
- manim/animation/animation.py +164 -18
- manim/animation/changing.py +34 -23
- manim/animation/composition.py +265 -67
- manim/animation/creation.py +208 -26
- manim/animation/fading.py +16 -18
- manim/animation/growing.py +35 -15
- manim/animation/indication.py +150 -76
- manim/animation/movement.py +56 -22
- manim/animation/numbers.py +64 -6
- manim/animation/rotation.py +78 -7
- manim/animation/specialized.py +6 -7
- manim/animation/speedmodifier.py +13 -10
- manim/animation/transform.py +14 -11
- manim/animation/transform_matching_parts.py +3 -4
- manim/animation/updaters/mobject_update_utils.py +152 -30
- manim/animation/updaters/update.py +10 -7
- manim/camera/camera.py +182 -118
- manim/camera/mapping_camera.py +34 -3
- manim/camera/moving_camera.py +95 -74
- manim/camera/multi_camera.py +23 -15
- manim/camera/three_d_camera.py +70 -52
- manim/cli/__init__.py +17 -0
- manim/cli/cfg/group.py +76 -44
- manim/cli/checkhealth/checks.py +192 -0
- manim/cli/checkhealth/commands.py +90 -0
- manim/cli/default_group.py +158 -25
- manim/cli/init/commands.py +33 -25
- manim/cli/plugins/commands.py +16 -3
- manim/cli/render/commands.py +72 -60
- manim/cli/render/ease_of_access_options.py +4 -3
- manim/cli/render/global_options.py +59 -17
- manim/cli/render/output_options.py +6 -5
- manim/cli/render/render_options.py +98 -33
- manim/constants.py +109 -59
- manim/data_structures.py +31 -0
- manim/mobject/frame.py +8 -5
- manim/mobject/geometry/__init__.py +1 -0
- manim/mobject/geometry/arc.py +277 -135
- manim/mobject/geometry/boolean_ops.py +32 -31
- manim/mobject/geometry/labeled.py +376 -0
- manim/mobject/geometry/line.py +192 -87
- manim/mobject/geometry/polygram.py +224 -58
- manim/mobject/geometry/shape_matchers.py +61 -25
- manim/mobject/geometry/tips.py +122 -48
- manim/mobject/graph.py +1027 -419
- manim/mobject/graphing/coordinate_systems.py +533 -278
- manim/mobject/graphing/functions.py +53 -32
- manim/mobject/graphing/number_line.py +123 -65
- manim/mobject/graphing/probability.py +88 -62
- manim/mobject/graphing/scale.py +33 -19
- manim/mobject/logo.py +118 -28
- manim/mobject/matrix.py +87 -83
- manim/mobject/mobject.py +912 -442
- manim/mobject/opengl/dot_cloud.py +16 -5
- manim/mobject/opengl/opengl_compatibility.py +4 -2
- manim/mobject/opengl/opengl_geometry.py +254 -153
- manim/mobject/opengl/opengl_image_mobject.py +3 -1
- manim/mobject/opengl/opengl_mobject.py +779 -482
- manim/mobject/opengl/opengl_point_cloud_mobject.py +41 -14
- manim/mobject/opengl/opengl_surface.py +14 -92
- manim/mobject/opengl/opengl_three_dimensions.py +12 -8
- manim/mobject/opengl/opengl_vectorized_mobject.py +98 -100
- manim/mobject/svg/brace.py +173 -41
- manim/mobject/svg/svg_mobject.py +139 -53
- manim/mobject/table.py +61 -68
- manim/mobject/text/code_mobject.py +193 -539
- manim/mobject/text/numbers.py +81 -34
- manim/mobject/text/tex_mobject.py +130 -78
- manim/mobject/text/text_mobject.py +288 -164
- manim/mobject/three_d/polyhedra.py +111 -13
- manim/mobject/three_d/three_d_utils.py +17 -8
- manim/mobject/three_d/three_dimensions.py +239 -106
- manim/mobject/types/image_mobject.py +50 -30
- manim/mobject/types/point_cloud_mobject.py +120 -75
- manim/mobject/types/vectorized_mobject.py +841 -408
- manim/mobject/value_tracker.py +105 -38
- manim/mobject/vector_field.py +50 -31
- manim/opengl/__init__.py +3 -3
- manim/plugins/__init__.py +14 -1
- manim/plugins/plugins_flags.py +10 -14
- manim/renderer/cairo_renderer.py +65 -50
- manim/renderer/opengl_renderer.py +89 -69
- manim/renderer/opengl_renderer_window.py +39 -18
- manim/renderer/shader.py +123 -87
- manim/renderer/shader_wrapper.py +44 -28
- manim/renderer/vectorized_mobject_rendering.py +38 -10
- manim/scene/moving_camera_scene.py +32 -3
- manim/scene/scene.py +507 -242
- manim/scene/scene_file_writer.py +371 -220
- manim/scene/section.py +20 -16
- manim/scene/three_d_scene.py +14 -22
- manim/scene/vector_space_scene.py +223 -129
- manim/scene/zoomed_scene.py +46 -41
- manim/typing.py +990 -0
- manim/utils/bezier.py +1823 -371
- manim/utils/caching.py +12 -5
- manim/utils/color/AS2700.py +236 -0
- manim/utils/color/BS381.py +318 -0
- manim/utils/color/DVIPSNAMES.py +96 -0
- manim/utils/color/SVGNAMES.py +179 -0
- manim/utils/color/X11.py +533 -0
- manim/utils/color/XKCD.py +952 -0
- manim/utils/color/__init__.py +61 -0
- manim/utils/color/core.py +1667 -0
- manim/utils/color/manim_colors.py +218 -0
- manim/utils/commands.py +48 -20
- manim/utils/config_ops.py +39 -19
- manim/utils/debug.py +8 -7
- manim/utils/deprecation.py +86 -39
- manim/utils/docbuild/__init__.py +17 -0
- manim/utils/docbuild/autoaliasattr_directive.py +236 -0
- manim/utils/docbuild/autocolor_directive.py +99 -0
- manim/utils/docbuild/manim_directive.py +94 -41
- manim/utils/docbuild/module_parsing.py +245 -0
- manim/utils/exceptions.py +6 -0
- manim/utils/family.py +5 -3
- manim/utils/family_ops.py +17 -4
- manim/utils/file_ops.py +27 -17
- manim/utils/hashing.py +55 -45
- manim/utils/images.py +13 -7
- manim/utils/ipython_magic.py +13 -7
- manim/utils/iterables.py +163 -120
- manim/utils/module_ops.py +66 -24
- manim/utils/opengl.py +77 -24
- manim/utils/parameter_parsing.py +32 -0
- manim/utils/paths.py +30 -33
- manim/utils/polylabel.py +235 -0
- manim/utils/qhull.py +218 -0
- manim/utils/rate_functions.py +98 -32
- manim/utils/simple_functions.py +25 -33
- manim/utils/sounds.py +7 -1
- manim/utils/space_ops.py +188 -115
- manim/utils/testing/__init__.py +17 -0
- manim/utils/testing/_frames_testers.py +13 -8
- manim/utils/testing/_show_diff.py +5 -3
- manim/utils/testing/_test_class_makers.py +34 -18
- manim/utils/testing/frames_comparison.py +37 -19
- manim/utils/tex.py +130 -198
- manim/utils/tex_file_writing.py +77 -47
- manim/utils/tex_templates.py +2 -1
- manim/utils/unit.py +6 -5
- {manim-0.17.0.dist-info → manim-0.19.1.dist-info}/METADATA +64 -65
- manim-0.19.1.dist-info/RECORD +220 -0
- {manim-0.17.0.dist-info → manim-0.19.1.dist-info}/WHEEL +1 -1
- manim-0.19.1.dist-info/entry_points.txt +3 -0
- {manim-0.17.0.dist-info → manim-0.19.1.dist-info/licenses}/LICENSE.community +1 -1
- manim/cli/new/group.py +0 -189
- manim/communitycolors.py +0 -9
- manim/gui/__init__.py +0 -0
- manim/gui/gui.py +0 -82
- manim/plugins/import_plugins.py +0 -43
- manim/utils/color.py +0 -552
- manim-0.17.0.dist-info/RECORD +0 -206
- manim-0.17.0.dist-info/entry_points.txt +0 -4
- /manim/cli/{new → checkhealth}/__init__.py +0 -0
- {manim-0.17.0.dist-info → manim-0.19.1.dist-info/licenses}/LICENSE +0 -0
manim/cli/plugins/commands.py
CHANGED
|
@@ -5,12 +5,15 @@ plugin``. Here you can specify options, subcommands, and subgroups for the plugi
|
|
|
5
5
|
group.
|
|
6
6
|
|
|
7
7
|
"""
|
|
8
|
+
|
|
8
9
|
from __future__ import annotations
|
|
9
10
|
|
|
10
11
|
import cloup
|
|
11
12
|
|
|
12
|
-
from
|
|
13
|
-
from
|
|
13
|
+
from manim.constants import CONTEXT_SETTINGS, EPILOG
|
|
14
|
+
from manim.plugins.plugins_flags import list_plugins
|
|
15
|
+
|
|
16
|
+
__all__ = ["plugins"]
|
|
14
17
|
|
|
15
18
|
|
|
16
19
|
@cloup.command(
|
|
@@ -26,6 +29,16 @@ from ...plugins.plugins_flags import list_plugins
|
|
|
26
29
|
is_flag=True,
|
|
27
30
|
help="List available plugins.",
|
|
28
31
|
)
|
|
29
|
-
def plugins(list_available):
|
|
32
|
+
def plugins(list_available: bool) -> None:
|
|
33
|
+
"""Print a list of all available plugins when calling ``manim plugins -l``
|
|
34
|
+
or ``manim plugins --list``.
|
|
35
|
+
|
|
36
|
+
Parameters
|
|
37
|
+
----------
|
|
38
|
+
list_available
|
|
39
|
+
If the ``-l`` or ``-list`` option is passed to ``manim plugins``, this
|
|
40
|
+
parameter will be set to ``True``, which will print a list of all
|
|
41
|
+
available plugins.
|
|
42
|
+
"""
|
|
30
43
|
if list_available:
|
|
31
44
|
list_plugins()
|
manim/cli/render/commands.py
CHANGED
|
@@ -5,24 +5,56 @@ Manim's render subcommand is accessed in the command-line interface via
|
|
|
5
5
|
can specify options, and arguments for the render command.
|
|
6
6
|
|
|
7
7
|
"""
|
|
8
|
+
|
|
8
9
|
from __future__ import annotations
|
|
9
10
|
|
|
11
|
+
import http.client
|
|
10
12
|
import json
|
|
11
13
|
import sys
|
|
14
|
+
import urllib.error
|
|
15
|
+
import urllib.request
|
|
16
|
+
from argparse import Namespace
|
|
12
17
|
from pathlib import Path
|
|
18
|
+
from typing import Any, cast
|
|
13
19
|
|
|
14
|
-
import click
|
|
15
20
|
import cloup
|
|
16
|
-
import requests
|
|
17
21
|
|
|
18
|
-
from
|
|
19
|
-
from
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
from manim import __version__
|
|
23
|
+
from manim._config import (
|
|
24
|
+
config,
|
|
25
|
+
console,
|
|
26
|
+
error_console,
|
|
27
|
+
logger,
|
|
28
|
+
tempconfig,
|
|
29
|
+
)
|
|
30
|
+
from manim.cli.render.ease_of_access_options import ease_of_access_options
|
|
31
|
+
from manim.cli.render.global_options import global_options
|
|
32
|
+
from manim.cli.render.output_options import output_options
|
|
33
|
+
from manim.cli.render.render_options import render_options
|
|
34
|
+
from manim.constants import EPILOG, RendererType
|
|
35
|
+
from manim.utils.module_ops import scene_classes_from_file
|
|
36
|
+
|
|
37
|
+
__all__ = ["render"]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class ClickArgs(Namespace):
|
|
41
|
+
def __init__(self, args: dict[str, Any]) -> None:
|
|
42
|
+
for name in args:
|
|
43
|
+
setattr(self, name, args[name])
|
|
44
|
+
|
|
45
|
+
def _get_kwargs(self) -> list[tuple[str, Any]]:
|
|
46
|
+
return list(self.__dict__.items())
|
|
47
|
+
|
|
48
|
+
def __eq__(self, other: object) -> bool:
|
|
49
|
+
if not isinstance(other, ClickArgs):
|
|
50
|
+
return NotImplemented
|
|
51
|
+
return vars(self) == vars(other)
|
|
52
|
+
|
|
53
|
+
def __contains__(self, key: str) -> bool:
|
|
54
|
+
return key in self.__dict__
|
|
55
|
+
|
|
56
|
+
def __repr__(self) -> str:
|
|
57
|
+
return str(self.__dict__)
|
|
26
58
|
|
|
27
59
|
|
|
28
60
|
@cloup.command(
|
|
@@ -30,56 +62,34 @@ from .render_options import render_options
|
|
|
30
62
|
no_args_is_help=True,
|
|
31
63
|
epilog=EPILOG,
|
|
32
64
|
)
|
|
33
|
-
@
|
|
34
|
-
@
|
|
65
|
+
@cloup.argument("file", type=cloup.Path(path_type=Path), required=True)
|
|
66
|
+
@cloup.argument("scene_names", required=False, nargs=-1)
|
|
35
67
|
@global_options
|
|
36
68
|
@output_options
|
|
37
|
-
@render_options
|
|
69
|
+
@render_options
|
|
38
70
|
@ease_of_access_options
|
|
39
|
-
def render(
|
|
40
|
-
**args,
|
|
41
|
-
):
|
|
71
|
+
def render(**kwargs: Any) -> ClickArgs | dict[str, Any]:
|
|
42
72
|
"""Render SCENE(S) from the input FILE.
|
|
43
73
|
|
|
44
74
|
FILE is the file path of the script or a config file.
|
|
45
75
|
|
|
46
76
|
SCENES is an optional list of scenes in the file.
|
|
47
77
|
"""
|
|
48
|
-
|
|
49
|
-
if args["save_as_gif"]:
|
|
78
|
+
if kwargs["save_as_gif"]:
|
|
50
79
|
logger.warning("--save_as_gif is deprecated, please use --format=gif instead!")
|
|
51
|
-
|
|
80
|
+
kwargs["format"] = "gif"
|
|
52
81
|
|
|
53
|
-
if
|
|
82
|
+
if kwargs["save_pngs"]:
|
|
54
83
|
logger.warning("--save_pngs is deprecated, please use --format=png instead!")
|
|
55
|
-
|
|
84
|
+
kwargs["format"] = "png"
|
|
56
85
|
|
|
57
|
-
if
|
|
86
|
+
if kwargs["show_in_file_browser"]:
|
|
58
87
|
logger.warning(
|
|
59
88
|
"The short form of show_in_file_browser is deprecated and will be moved to support --format.",
|
|
60
89
|
)
|
|
61
90
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
for name in args:
|
|
65
|
-
setattr(self, name, args[name])
|
|
66
|
-
|
|
67
|
-
def _get_kwargs(self):
|
|
68
|
-
return list(self.__dict__.items())
|
|
69
|
-
|
|
70
|
-
def __eq__(self, other):
|
|
71
|
-
if not isinstance(other, ClickArgs):
|
|
72
|
-
return NotImplemented
|
|
73
|
-
return vars(self) == vars(other)
|
|
74
|
-
|
|
75
|
-
def __contains__(self, key):
|
|
76
|
-
return key in self.__dict__
|
|
77
|
-
|
|
78
|
-
def __repr__(self):
|
|
79
|
-
return str(self.__dict__)
|
|
80
|
-
|
|
81
|
-
click_args = ClickArgs(args)
|
|
82
|
-
if args["jupyter"]:
|
|
91
|
+
click_args = ClickArgs(kwargs)
|
|
92
|
+
if kwargs["jupyter"]:
|
|
83
93
|
return click_args
|
|
84
94
|
|
|
85
95
|
config.digest_args(click_args)
|
|
@@ -120,13 +130,26 @@ def render(
|
|
|
120
130
|
if config.notify_outdated_version:
|
|
121
131
|
manim_info_url = "https://pypi.org/pypi/manim/json"
|
|
122
132
|
warn_prompt = "Cannot check if latest release of manim is installed"
|
|
123
|
-
req_info = {}
|
|
124
133
|
|
|
125
134
|
try:
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
135
|
+
with urllib.request.urlopen(
|
|
136
|
+
urllib.request.Request(manim_info_url),
|
|
137
|
+
timeout=10,
|
|
138
|
+
) as response:
|
|
139
|
+
response = cast(http.client.HTTPResponse, response)
|
|
140
|
+
json_data = json.loads(response.read())
|
|
141
|
+
except urllib.error.HTTPError:
|
|
142
|
+
logger.debug("HTTP Error: %s", warn_prompt)
|
|
143
|
+
except urllib.error.URLError:
|
|
144
|
+
logger.debug("URL Error: %s", warn_prompt)
|
|
145
|
+
except json.JSONDecodeError:
|
|
146
|
+
logger.debug(
|
|
147
|
+
"Error while decoding JSON from %r: %s", manim_info_url, warn_prompt
|
|
148
|
+
)
|
|
149
|
+
except Exception:
|
|
150
|
+
logger.debug("Something went wrong: %s", warn_prompt)
|
|
151
|
+
else:
|
|
152
|
+
stable = json_data["info"]["version"]
|
|
130
153
|
if stable != __version__:
|
|
131
154
|
console.print(
|
|
132
155
|
f"You are using manim version [red]v{__version__}[/red], but version [green]v{stable}[/green] is available.",
|
|
@@ -134,16 +157,5 @@ def render(
|
|
|
134
157
|
console.print(
|
|
135
158
|
"You should consider upgrading via [yellow]pip install -U manim[/yellow]",
|
|
136
159
|
)
|
|
137
|
-
except requests.exceptions.HTTPError:
|
|
138
|
-
logger.debug(f"HTTP Error: {warn_prompt}")
|
|
139
|
-
except requests.exceptions.ConnectionError:
|
|
140
|
-
logger.debug(f"Connection Error: {warn_prompt}")
|
|
141
|
-
except requests.exceptions.Timeout:
|
|
142
|
-
logger.debug(f"Timed Out: {warn_prompt}")
|
|
143
|
-
except json.JSONDecodeError:
|
|
144
|
-
logger.debug(warn_prompt)
|
|
145
|
-
logger.debug(f"Error decoding JSON from {manim_info_url}")
|
|
146
|
-
except Exception:
|
|
147
|
-
logger.debug(f"Something went wrong: {warn_prompt}")
|
|
148
160
|
|
|
149
|
-
return
|
|
161
|
+
return kwargs
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
|
|
3
|
+
from cloup import Choice, option, option_group
|
|
4
|
+
|
|
5
|
+
__all__ = ["ease_of_access_options"]
|
|
5
6
|
|
|
6
7
|
ease_of_access_options = option_group(
|
|
7
8
|
"Ease of access options",
|
|
@@ -9,7 +10,7 @@ ease_of_access_options = option_group(
|
|
|
9
10
|
"--progress_bar",
|
|
10
11
|
default=None,
|
|
11
12
|
show_default=False,
|
|
12
|
-
type=
|
|
13
|
+
type=Choice(
|
|
13
14
|
["display", "leave", "none"],
|
|
14
15
|
case_sensitive=False,
|
|
15
16
|
),
|
|
@@ -1,28 +1,59 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import logging
|
|
3
4
|
import re
|
|
5
|
+
import sys
|
|
4
6
|
from typing import TYPE_CHECKING
|
|
5
7
|
|
|
6
|
-
import
|
|
7
|
-
from cloup import option, option_group
|
|
8
|
-
|
|
9
|
-
from ... import logger
|
|
8
|
+
from cloup import Choice, option, option_group
|
|
10
9
|
|
|
11
10
|
if TYPE_CHECKING:
|
|
12
|
-
from
|
|
11
|
+
from click import Context, Option
|
|
12
|
+
|
|
13
|
+
__all__ = ["global_options"]
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger("manim")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def validate_gui_location(
|
|
19
|
+
ctx: Context, param: Option, value: str | None
|
|
20
|
+
) -> tuple[int, int] | None:
|
|
21
|
+
"""If the ``value`` string is given, extract from it the GUI location,
|
|
22
|
+
which should be in any of these formats: 'x;y', 'x,y' or 'x-y'.
|
|
13
23
|
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
ctx
|
|
27
|
+
The Click context.
|
|
28
|
+
param
|
|
29
|
+
A Click option.
|
|
30
|
+
value
|
|
31
|
+
The optional string which will be parsed.
|
|
14
32
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
except Exception:
|
|
21
|
-
logger.error("GUI location option is invalid.")
|
|
22
|
-
exit()
|
|
33
|
+
Returns
|
|
34
|
+
-------
|
|
35
|
+
tuple[int, int] | None
|
|
36
|
+
If ``value`` is ``None``, the return value is ``None``. Otherwise, it's
|
|
37
|
+
the ``(x, y)`` location for the GUI.
|
|
23
38
|
|
|
39
|
+
Raises
|
|
40
|
+
------
|
|
41
|
+
ValueError
|
|
42
|
+
If ``value`` has an invalid format.
|
|
43
|
+
"""
|
|
44
|
+
if value is None:
|
|
45
|
+
return None
|
|
24
46
|
|
|
25
|
-
|
|
47
|
+
try:
|
|
48
|
+
x_offset, y_offset = map(int, re.split(r"[;,\-]", value))
|
|
49
|
+
except Exception:
|
|
50
|
+
logger.error("GUI location option is invalid.")
|
|
51
|
+
sys.exit()
|
|
52
|
+
|
|
53
|
+
return (x_offset, y_offset)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
global_options = option_group(
|
|
26
57
|
"Global options",
|
|
27
58
|
option(
|
|
28
59
|
"-c",
|
|
@@ -53,7 +84,7 @@ global_options: OptionGroupDecorator = option_group(
|
|
|
53
84
|
option(
|
|
54
85
|
"-v",
|
|
55
86
|
"--verbosity",
|
|
56
|
-
type=
|
|
87
|
+
type=Choice(
|
|
57
88
|
["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
|
|
58
89
|
case_sensitive=False,
|
|
59
90
|
),
|
|
@@ -94,12 +125,23 @@ global_options: OptionGroupDecorator = option_group(
|
|
|
94
125
|
"--force_window",
|
|
95
126
|
is_flag=True,
|
|
96
127
|
help="Force window to open when using the opengl renderer, intended for debugging as it may impact performance",
|
|
97
|
-
default=
|
|
128
|
+
default=None,
|
|
98
129
|
),
|
|
99
130
|
option(
|
|
100
131
|
"--dry_run",
|
|
101
132
|
is_flag=True,
|
|
102
133
|
help="Renders animations without outputting image or video files and disables the window",
|
|
103
|
-
default=
|
|
134
|
+
default=None,
|
|
135
|
+
),
|
|
136
|
+
option(
|
|
137
|
+
"--no_latex_cleanup",
|
|
138
|
+
is_flag=True,
|
|
139
|
+
help="Prevents deletion of .aux, .dvi, and .log files produced by Tex and MathTex.",
|
|
140
|
+
default=None,
|
|
141
|
+
),
|
|
142
|
+
option(
|
|
143
|
+
"--preview_command",
|
|
144
|
+
help="The command used to preview the output file (for example vlc for video files)",
|
|
145
|
+
default=None,
|
|
104
146
|
),
|
|
105
147
|
)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
|
|
3
|
+
from cloup import IntRange, Path, option, option_group
|
|
4
|
+
|
|
5
|
+
__all__ = ["output_options"]
|
|
5
6
|
|
|
6
7
|
output_options = option_group(
|
|
7
8
|
"Output options",
|
|
@@ -15,7 +16,7 @@ output_options = option_group(
|
|
|
15
16
|
option(
|
|
16
17
|
"-0",
|
|
17
18
|
"--zero_pad",
|
|
18
|
-
type=
|
|
19
|
+
type=IntRange(0, 9),
|
|
19
20
|
default=None,
|
|
20
21
|
help="Zero padding for PNG file names.",
|
|
21
22
|
),
|
|
@@ -27,13 +28,13 @@ output_options = option_group(
|
|
|
27
28
|
),
|
|
28
29
|
option(
|
|
29
30
|
"--media_dir",
|
|
30
|
-
type=
|
|
31
|
+
type=Path(),
|
|
31
32
|
default=None,
|
|
32
33
|
help="Path to store rendered videos and latex.",
|
|
33
34
|
),
|
|
34
35
|
option(
|
|
35
36
|
"--log_dir",
|
|
36
|
-
type=
|
|
37
|
+
type=Path(),
|
|
37
38
|
help="Path to store render logs.",
|
|
38
39
|
default=None,
|
|
39
40
|
),
|
|
@@ -1,39 +1,105 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import logging
|
|
3
4
|
import re
|
|
5
|
+
import sys
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
4
7
|
|
|
5
|
-
import
|
|
6
|
-
from cloup import option, option_group
|
|
8
|
+
from cloup import Choice, option, option_group
|
|
7
9
|
|
|
8
10
|
from manim.constants import QUALITIES, RendererType
|
|
9
11
|
|
|
10
|
-
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from click import Context, Option
|
|
11
14
|
|
|
15
|
+
__all__ = ["render_options"]
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger("manim")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def validate_scene_range(
|
|
21
|
+
ctx: Context, param: Option, value: str | None
|
|
22
|
+
) -> tuple[int] | tuple[int, int] | None:
|
|
23
|
+
"""If the ``value`` string is given, extract from it the scene range, which
|
|
24
|
+
should be in any of these formats: 'start', 'start;end', 'start,end' or
|
|
25
|
+
'start-end'. Otherwise, return ``None``.
|
|
26
|
+
|
|
27
|
+
Parameters
|
|
28
|
+
----------
|
|
29
|
+
ctx
|
|
30
|
+
The Click context.
|
|
31
|
+
param
|
|
32
|
+
A Click option.
|
|
33
|
+
value
|
|
34
|
+
The optional string which will be parsed.
|
|
35
|
+
|
|
36
|
+
Returns
|
|
37
|
+
-------
|
|
38
|
+
tuple[int] | tuple[int, int] | None
|
|
39
|
+
If ``value`` is ``None``, the return value is ``None``. Otherwise, it's
|
|
40
|
+
the scene range, given by a tuple which may contain a single value
|
|
41
|
+
``start`` or two values ``start`` and ``end``.
|
|
42
|
+
|
|
43
|
+
Raises
|
|
44
|
+
------
|
|
45
|
+
ValueError
|
|
46
|
+
If ``value`` has an invalid format.
|
|
47
|
+
"""
|
|
48
|
+
if value is None:
|
|
49
|
+
return None
|
|
12
50
|
|
|
13
|
-
def validate_scene_range(ctx, param, value):
|
|
14
51
|
try:
|
|
15
52
|
start = int(value)
|
|
16
53
|
return (start,)
|
|
17
54
|
except Exception:
|
|
18
55
|
pass
|
|
19
56
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
57
|
+
try:
|
|
58
|
+
start, end = map(int, re.split(r"[;,\-]", value))
|
|
59
|
+
except Exception:
|
|
60
|
+
logger.error("Couldn't determine a range for -n option.")
|
|
61
|
+
sys.exit()
|
|
62
|
+
|
|
63
|
+
return start, end
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def validate_resolution(
|
|
67
|
+
ctx: Context, param: Option, value: str | None
|
|
68
|
+
) -> tuple[int, int] | None:
|
|
69
|
+
"""If the ``value`` string is given, extract from it the resolution, which
|
|
70
|
+
should be in any of these formats: 'W;H', 'W,H' or 'W-H'. Otherwise, return
|
|
71
|
+
``None``.
|
|
72
|
+
|
|
73
|
+
Parameters
|
|
74
|
+
----------
|
|
75
|
+
ctx
|
|
76
|
+
The Click context.
|
|
77
|
+
param
|
|
78
|
+
A Click option.
|
|
79
|
+
value
|
|
80
|
+
The optional string which will be parsed.
|
|
81
|
+
|
|
82
|
+
Returns
|
|
83
|
+
-------
|
|
84
|
+
tuple[int, int] | None
|
|
85
|
+
If ``value`` is ``None``, the return value is ``None``. Otherwise, it's
|
|
86
|
+
the resolution as a ``(W, H)`` tuple.
|
|
87
|
+
|
|
88
|
+
Raises
|
|
89
|
+
------
|
|
90
|
+
ValueError
|
|
91
|
+
If ``value`` has an invalid format.
|
|
92
|
+
"""
|
|
93
|
+
if value is None:
|
|
94
|
+
return None
|
|
27
95
|
|
|
96
|
+
try:
|
|
97
|
+
width, height = map(int, re.split(r"[;,\-]", value))
|
|
98
|
+
except Exception:
|
|
99
|
+
logger.error("Resolution option is invalid.")
|
|
100
|
+
sys.exit()
|
|
28
101
|
|
|
29
|
-
|
|
30
|
-
if value:
|
|
31
|
-
try:
|
|
32
|
-
start, end = map(int, re.split(r"[;,\-]", value))
|
|
33
|
-
return (start, end)
|
|
34
|
-
except Exception:
|
|
35
|
-
logger.error("Resolution option is invalid.")
|
|
36
|
-
exit()
|
|
102
|
+
return width, height
|
|
37
103
|
|
|
38
104
|
|
|
39
105
|
render_options = option_group(
|
|
@@ -55,23 +121,29 @@ render_options = option_group(
|
|
|
55
121
|
),
|
|
56
122
|
option(
|
|
57
123
|
"--format",
|
|
58
|
-
type=
|
|
124
|
+
type=Choice(["png", "gif", "mp4", "webm", "mov"], case_sensitive=False),
|
|
125
|
+
default=None,
|
|
126
|
+
),
|
|
127
|
+
option(
|
|
128
|
+
"-s",
|
|
129
|
+
"--save_last_frame",
|
|
59
130
|
default=None,
|
|
131
|
+
is_flag=True,
|
|
132
|
+
help="Render and save only the last frame of a scene as a PNG image.",
|
|
60
133
|
),
|
|
61
|
-
option("-s", "--save_last_frame", is_flag=True, default=None),
|
|
62
134
|
option(
|
|
63
135
|
"-q",
|
|
64
136
|
"--quality",
|
|
65
137
|
default=None,
|
|
66
|
-
type=
|
|
67
|
-
list(reversed([q["flag"] for q in QUALITIES.values() if q["flag"]])),
|
|
138
|
+
type=Choice(
|
|
139
|
+
list(reversed([q["flag"] for q in QUALITIES.values() if q["flag"]])),
|
|
68
140
|
case_sensitive=False,
|
|
69
141
|
),
|
|
70
142
|
help="Render quality at the follow resolution framerates, respectively: "
|
|
71
143
|
+ ", ".join(
|
|
72
144
|
reversed(
|
|
73
145
|
[
|
|
74
|
-
f
|
|
146
|
+
f"{q['pixel_width']}x{q['pixel_height']} {q['frame_rate']}FPS"
|
|
75
147
|
for q in QUALITIES.values()
|
|
76
148
|
if q["flag"]
|
|
77
149
|
]
|
|
@@ -83,7 +155,7 @@ render_options = option_group(
|
|
|
83
155
|
"--resolution",
|
|
84
156
|
callback=validate_resolution,
|
|
85
157
|
default=None,
|
|
86
|
-
help=
|
|
158
|
+
help='Resolution in "W,H" for when 16:9 aspect ratio isn\'t possible.',
|
|
87
159
|
),
|
|
88
160
|
option(
|
|
89
161
|
"--fps",
|
|
@@ -95,7 +167,7 @@ render_options = option_group(
|
|
|
95
167
|
),
|
|
96
168
|
option(
|
|
97
169
|
"--renderer",
|
|
98
|
-
type=
|
|
170
|
+
type=Choice(
|
|
99
171
|
[renderer_type.value for renderer_type in RendererType],
|
|
100
172
|
case_sensitive=False,
|
|
101
173
|
),
|
|
@@ -122,13 +194,6 @@ render_options = option_group(
|
|
|
122
194
|
is_flag=True,
|
|
123
195
|
help="Save section videos in addition to movie file.",
|
|
124
196
|
),
|
|
125
|
-
option(
|
|
126
|
-
"-s",
|
|
127
|
-
"--save_last_frame",
|
|
128
|
-
default=None,
|
|
129
|
-
is_flag=True,
|
|
130
|
-
help="Save last frame as png (Deprecated).",
|
|
131
|
-
),
|
|
132
197
|
option(
|
|
133
198
|
"-t",
|
|
134
199
|
"--transparent",
|