manim 0.18.0.post0__py3-none-any.whl → 0.19.0__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.
Potentially problematic release.
This version of manim might be problematic. Click here for more details.
- manim/__init__.py +3 -6
- manim/__main__.py +61 -20
- manim/_config/__init__.py +6 -3
- manim/_config/cli_colors.py +16 -8
- manim/_config/default.cfg +1 -3
- manim/_config/logger_utils.py +14 -8
- manim/_config/utils.py +651 -472
- manim/animation/animation.py +152 -5
- manim/animation/composition.py +80 -39
- manim/animation/creation.py +196 -14
- manim/animation/fading.py +5 -9
- manim/animation/indication.py +103 -47
- manim/animation/movement.py +22 -5
- manim/animation/rotation.py +3 -2
- manim/animation/specialized.py +4 -6
- manim/animation/speedmodifier.py +10 -5
- manim/animation/transform.py +4 -5
- manim/animation/transform_matching_parts.py +1 -1
- manim/animation/updaters/mobject_update_utils.py +17 -14
- manim/camera/camera.py +15 -6
- manim/cli/__init__.py +17 -0
- manim/cli/cfg/group.py +70 -44
- manim/cli/checkhealth/checks.py +93 -75
- manim/cli/checkhealth/commands.py +14 -5
- manim/cli/default_group.py +157 -25
- manim/cli/init/commands.py +32 -24
- 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 +51 -15
- manim/cli/render/output_options.py +6 -5
- manim/cli/render/render_options.py +97 -32
- manim/constants.py +65 -19
- manim/gui/gui.py +2 -0
- manim/mobject/frame.py +0 -1
- manim/mobject/geometry/arc.py +112 -78
- manim/mobject/geometry/boolean_ops.py +32 -25
- manim/mobject/geometry/labeled.py +300 -77
- manim/mobject/geometry/line.py +132 -64
- manim/mobject/geometry/polygram.py +126 -30
- manim/mobject/geometry/shape_matchers.py +35 -15
- manim/mobject/geometry/tips.py +38 -29
- manim/mobject/graph.py +414 -133
- manim/mobject/graphing/coordinate_systems.py +126 -64
- manim/mobject/graphing/functions.py +25 -15
- manim/mobject/graphing/number_line.py +24 -10
- manim/mobject/graphing/probability.py +2 -10
- manim/mobject/graphing/scale.py +6 -5
- manim/mobject/matrix.py +17 -19
- manim/mobject/mobject.py +314 -165
- manim/mobject/opengl/opengl_compatibility.py +2 -0
- manim/mobject/opengl/opengl_geometry.py +30 -9
- manim/mobject/opengl/opengl_image_mobject.py +2 -0
- manim/mobject/opengl/opengl_mobject.py +509 -343
- manim/mobject/opengl/opengl_point_cloud_mobject.py +5 -7
- manim/mobject/opengl/opengl_surface.py +3 -2
- manim/mobject/opengl/opengl_three_dimensions.py +2 -0
- manim/mobject/opengl/opengl_vectorized_mobject.py +46 -79
- manim/mobject/svg/brace.py +63 -13
- manim/mobject/svg/svg_mobject.py +4 -3
- manim/mobject/table.py +11 -13
- manim/mobject/text/code_mobject.py +186 -548
- manim/mobject/text/numbers.py +9 -7
- manim/mobject/text/tex_mobject.py +23 -14
- manim/mobject/text/text_mobject.py +70 -24
- manim/mobject/three_d/polyhedra.py +98 -1
- manim/mobject/three_d/three_d_utils.py +4 -4
- manim/mobject/three_d/three_dimensions.py +62 -34
- manim/mobject/types/image_mobject.py +42 -24
- manim/mobject/types/point_cloud_mobject.py +105 -67
- manim/mobject/types/vectorized_mobject.py +496 -228
- manim/mobject/value_tracker.py +5 -4
- manim/mobject/vector_field.py +5 -5
- manim/opengl/__init__.py +3 -3
- manim/plugins/__init__.py +14 -1
- manim/plugins/plugins_flags.py +14 -8
- manim/renderer/cairo_renderer.py +20 -10
- manim/renderer/opengl_renderer.py +21 -23
- manim/renderer/opengl_renderer_window.py +2 -0
- manim/renderer/shader.py +2 -3
- manim/renderer/shader_wrapper.py +5 -2
- manim/renderer/vectorized_mobject_rendering.py +5 -0
- manim/scene/moving_camera_scene.py +23 -0
- manim/scene/scene.py +90 -43
- manim/scene/scene_file_writer.py +316 -165
- manim/scene/section.py +17 -15
- manim/scene/three_d_scene.py +13 -21
- manim/scene/vector_space_scene.py +22 -9
- manim/typing.py +830 -70
- manim/utils/bezier.py +1667 -399
- manim/utils/caching.py +13 -5
- manim/utils/color/AS2700.py +2 -0
- manim/utils/color/BS381.py +3 -0
- manim/utils/color/DVIPSNAMES.py +96 -0
- manim/utils/color/SVGNAMES.py +179 -0
- manim/utils/color/X11.py +3 -0
- manim/utils/color/XKCD.py +3 -0
- manim/utils/color/__init__.py +8 -5
- manim/utils/color/core.py +844 -309
- manim/utils/color/manim_colors.py +7 -9
- manim/utils/commands.py +48 -20
- manim/utils/config_ops.py +18 -13
- manim/utils/debug.py +8 -7
- manim/utils/deprecation.py +90 -40
- manim/utils/docbuild/__init__.py +17 -0
- manim/utils/docbuild/autoaliasattr_directive.py +234 -0
- manim/utils/docbuild/autocolor_directive.py +21 -17
- manim/utils/docbuild/manim_directive.py +50 -35
- 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 +26 -16
- manim/utils/hashing.py +9 -7
- manim/utils/images.py +10 -4
- manim/utils/ipython_magic.py +14 -8
- manim/utils/iterables.py +161 -119
- manim/utils/module_ops.py +57 -19
- manim/utils/opengl.py +83 -24
- manim/utils/parameter_parsing.py +32 -0
- manim/utils/paths.py +21 -23
- manim/utils/polylabel.py +168 -0
- manim/utils/qhull.py +218 -0
- manim/utils/rate_functions.py +74 -39
- manim/utils/simple_functions.py +24 -15
- manim/utils/sounds.py +7 -1
- manim/utils/space_ops.py +125 -69
- 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 +33 -18
- manim/utils/testing/frames_comparison.py +27 -19
- manim/utils/tex.py +127 -197
- manim/utils/tex_file_writing.py +47 -45
- manim/utils/tex_templates.py +2 -1
- manim/utils/unit.py +6 -5
- {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/LICENSE.community +1 -1
- {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/METADATA +40 -39
- manim-0.19.0.dist-info/RECORD +221 -0
- {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/WHEEL +1 -1
- manim/cli/new/__init__.py +0 -0
- manim/cli/new/group.py +0 -189
- manim/plugins/import_plugins.py +0 -43
- manim-0.18.0.post0.dist-info/RECORD +0 -217
- {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/LICENSE +0 -0
- {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/entry_points.txt +0 -0
manim/cli/default_group.py
CHANGED
|
@@ -1,65 +1,197 @@
|
|
|
1
|
-
"""DefaultGroup allows a subcommand to act as the main command
|
|
1
|
+
"""``DefaultGroup`` allows a subcommand to act as the main command.
|
|
2
2
|
|
|
3
3
|
In particular, this class is what allows ``manim`` to act as ``manim render``.
|
|
4
|
+
|
|
5
|
+
.. note::
|
|
6
|
+
This is a vendored version of https://github.com/click-contrib/click-default-group/
|
|
7
|
+
under the BSD 3-Clause "New" or "Revised" License.
|
|
8
|
+
|
|
9
|
+
This library isn't used as a dependency, as we need to inherit from
|
|
10
|
+
:class:`cloup.Group` instead of :class:`click.Group`.
|
|
4
11
|
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import warnings
|
|
16
|
+
from typing import TYPE_CHECKING, Any, Callable
|
|
17
|
+
|
|
5
18
|
import cloup
|
|
6
19
|
|
|
7
|
-
from
|
|
20
|
+
from manim.utils.deprecation import deprecated
|
|
8
21
|
|
|
9
22
|
__all__ = ["DefaultGroup"]
|
|
10
23
|
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from click import Command, Context
|
|
26
|
+
|
|
11
27
|
|
|
12
28
|
class DefaultGroup(cloup.Group):
|
|
13
|
-
"""Invokes a subcommand marked with ``default=True`` if any subcommand not
|
|
29
|
+
"""Invokes a subcommand marked with ``default=True`` if any subcommand is not
|
|
14
30
|
chosen.
|
|
31
|
+
|
|
32
|
+
Parameters
|
|
33
|
+
----------
|
|
34
|
+
*args
|
|
35
|
+
Positional arguments to forward to :class:`cloup.Group`.
|
|
36
|
+
**kwargs
|
|
37
|
+
Keyword arguments to forward to :class:`cloup.Group`. The keyword
|
|
38
|
+
``ignore_unknown_options`` must be set to ``False``.
|
|
39
|
+
|
|
40
|
+
Attributes
|
|
41
|
+
----------
|
|
42
|
+
default_cmd_name : str | None
|
|
43
|
+
The name of the default command, if specified through the ``default``
|
|
44
|
+
keyword argument. Otherwise, this is set to ``None``.
|
|
45
|
+
default_if_no_args : bool
|
|
46
|
+
Whether to include or not the default command, if no command arguments
|
|
47
|
+
are supplied. This can be specified through the ``default_if_no_args``
|
|
48
|
+
keyword argument. Default is ``False``.
|
|
15
49
|
"""
|
|
16
50
|
|
|
17
|
-
def __init__(self, *args, **kwargs):
|
|
51
|
+
def __init__(self, *args: Any, **kwargs: Any):
|
|
18
52
|
# To resolve as the default command.
|
|
19
53
|
if not kwargs.get("ignore_unknown_options", True):
|
|
20
54
|
raise ValueError("Default group accepts unknown options")
|
|
21
55
|
self.ignore_unknown_options = True
|
|
22
|
-
self.default_cmd_name = kwargs.pop("default", None)
|
|
23
|
-
self.default_if_no_args = kwargs.pop("default_if_no_args", False)
|
|
56
|
+
self.default_cmd_name: str | None = kwargs.pop("default", None)
|
|
57
|
+
self.default_if_no_args: bool = kwargs.pop("default_if_no_args", False)
|
|
24
58
|
super().__init__(*args, **kwargs)
|
|
25
59
|
|
|
26
|
-
def set_default_command(self, command):
|
|
27
|
-
"""Sets a command function as the default command.
|
|
60
|
+
def set_default_command(self, command: Command) -> None:
|
|
61
|
+
"""Sets a command function as the default command.
|
|
62
|
+
|
|
63
|
+
Parameters
|
|
64
|
+
----------
|
|
65
|
+
command
|
|
66
|
+
The command to set as default.
|
|
67
|
+
"""
|
|
28
68
|
cmd_name = command.name
|
|
29
69
|
self.add_command(command)
|
|
30
70
|
self.default_cmd_name = cmd_name
|
|
31
71
|
|
|
32
|
-
def parse_args(self, ctx, args):
|
|
33
|
-
|
|
72
|
+
def parse_args(self, ctx: Context, args: list[str]) -> list[str]:
|
|
73
|
+
"""Parses the list of ``args`` by forwarding it to
|
|
74
|
+
:meth:`cloup.Group.parse_args`. Before doing so, if
|
|
75
|
+
:attr:`default_if_no_args` is set to ``True`` and ``args`` is empty,
|
|
76
|
+
this function appends to it the name of the default command specified
|
|
77
|
+
by :attr:`default_cmd_name`.
|
|
78
|
+
|
|
79
|
+
Parameters
|
|
80
|
+
----------
|
|
81
|
+
ctx
|
|
82
|
+
The Click context.
|
|
83
|
+
args
|
|
84
|
+
A list of arguments. If it's empty and :attr:`default_if_no_args`
|
|
85
|
+
is ``True``, append the name of the default command to it.
|
|
86
|
+
|
|
87
|
+
Returns
|
|
88
|
+
-------
|
|
89
|
+
list[str]
|
|
90
|
+
The parsed arguments.
|
|
91
|
+
"""
|
|
92
|
+
if not args and self.default_if_no_args and self.default_cmd_name:
|
|
34
93
|
args.insert(0, self.default_cmd_name)
|
|
35
|
-
|
|
94
|
+
parsed_args: list[str] = super().parse_args(ctx, args)
|
|
95
|
+
return parsed_args
|
|
96
|
+
|
|
97
|
+
def get_command(self, ctx: Context, cmd_name: str) -> Command | None:
|
|
98
|
+
"""Get a command function by its name, by forwarding the arguments to
|
|
99
|
+
:meth:`cloup.Group.get_command`. If ``cmd_name`` does not match any of
|
|
100
|
+
the command names in :attr:`commands`, attempt to get the default command
|
|
101
|
+
instead.
|
|
102
|
+
|
|
103
|
+
Parameters
|
|
104
|
+
----------
|
|
105
|
+
ctx
|
|
106
|
+
The Click context.
|
|
107
|
+
cmd_name
|
|
108
|
+
The name of the command to get.
|
|
36
109
|
|
|
37
|
-
|
|
38
|
-
|
|
110
|
+
Returns
|
|
111
|
+
-------
|
|
112
|
+
:class:`click.Command` | None
|
|
113
|
+
The command, if found. Otherwise, ``None``.
|
|
114
|
+
"""
|
|
115
|
+
if cmd_name not in self.commands and self.default_cmd_name:
|
|
39
116
|
# No command name matched.
|
|
40
|
-
ctx.arg0 = cmd_name
|
|
117
|
+
ctx.meta["arg0"] = cmd_name
|
|
41
118
|
cmd_name = self.default_cmd_name
|
|
42
119
|
return super().get_command(ctx, cmd_name)
|
|
43
120
|
|
|
44
|
-
def resolve_command(
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
121
|
+
def resolve_command(
|
|
122
|
+
self, ctx: Context, args: list[str]
|
|
123
|
+
) -> tuple[str | None, Command | None, list[str]]:
|
|
124
|
+
"""Given a list of ``args`` given by a CLI, find a command which
|
|
125
|
+
matches the first element, and return its name (``cmd_name``), the
|
|
126
|
+
command function itself (``cmd``) and the rest of the arguments which
|
|
127
|
+
shall be passed to the function (``cmd_args``). If not found, return
|
|
128
|
+
``None``, ``None`` and the rest of the arguments.
|
|
129
|
+
|
|
130
|
+
After resolving the command, if the Click context given by ``ctx``
|
|
131
|
+
contains an ``arg0`` attribute in its :attr:`click.Context.meta`
|
|
132
|
+
dictionary, insert it as the first element of the returned
|
|
133
|
+
``cmd_args``.
|
|
134
|
+
|
|
135
|
+
Parameters
|
|
136
|
+
----------
|
|
137
|
+
ctx
|
|
138
|
+
The Click context.
|
|
139
|
+
cmd_name
|
|
140
|
+
The name of the command to get.
|
|
141
|
+
|
|
142
|
+
Returns
|
|
143
|
+
-------
|
|
144
|
+
cmd_name : str | None
|
|
145
|
+
The command name, if found. Otherwise, ``None``.
|
|
146
|
+
cmd : :class:`click.Command` | None
|
|
147
|
+
The command, if found. Otherwise, ``None``.
|
|
148
|
+
cmd_args : list[str]
|
|
149
|
+
The rest of the arguments to be passed to ``cmd``.
|
|
150
|
+
"""
|
|
151
|
+
cmd_name, cmd, args = super().resolve_command(ctx, args)
|
|
152
|
+
if "arg0" in ctx.meta:
|
|
153
|
+
args.insert(0, ctx.meta["arg0"])
|
|
154
|
+
if cmd is not None:
|
|
155
|
+
cmd_name = cmd.name
|
|
50
156
|
return cmd_name, cmd, args
|
|
51
157
|
|
|
52
|
-
|
|
158
|
+
@deprecated
|
|
159
|
+
def command(
|
|
160
|
+
self, *args: Any, **kwargs: Any
|
|
161
|
+
) -> Callable[[Callable[..., object]], Command]:
|
|
162
|
+
"""Return a decorator which converts any function into the default
|
|
163
|
+
subcommand for this :class:`DefaultGroup`.
|
|
164
|
+
|
|
165
|
+
.. warning::
|
|
166
|
+
This method is deprecated. Use the ``default`` parameter of
|
|
167
|
+
:class:`DefaultGroup` or :meth:`set_default_command` instead.
|
|
168
|
+
|
|
169
|
+
Parameters
|
|
170
|
+
----------
|
|
171
|
+
*args
|
|
172
|
+
Positional arguments to pass to :meth:`cloup.Group.command`.
|
|
173
|
+
**kwargs
|
|
174
|
+
Keyword arguments to pass to :meth:`cloup.Group.command`.
|
|
175
|
+
|
|
176
|
+
Returns
|
|
177
|
+
-------
|
|
178
|
+
Callable[[Callable[..., object]], click.Command]
|
|
179
|
+
A decorator which transforms its input into this
|
|
180
|
+
:class:`DefaultGroup`'s default subcommand.
|
|
181
|
+
"""
|
|
53
182
|
default = kwargs.pop("default", False)
|
|
54
|
-
decorator = super().command(
|
|
183
|
+
decorator: Callable[[Callable[..., object]], Command] = super().command(
|
|
184
|
+
*args, **kwargs
|
|
185
|
+
)
|
|
55
186
|
if not default:
|
|
56
187
|
return decorator
|
|
57
|
-
|
|
58
|
-
"Use default param of DefaultGroup or
|
|
188
|
+
warnings.warn(
|
|
189
|
+
"Use default param of DefaultGroup or set_default_command() instead",
|
|
59
190
|
DeprecationWarning,
|
|
191
|
+
stacklevel=1,
|
|
60
192
|
)
|
|
61
193
|
|
|
62
|
-
def _decorator(f):
|
|
194
|
+
def _decorator(f: Callable) -> Command:
|
|
63
195
|
cmd = decorator(f)
|
|
64
196
|
self.set_default_command(cmd)
|
|
65
197
|
return cmd
|
manim/cli/init/commands.py
CHANGED
|
@@ -5,17 +5,19 @@ init``. Here you can specify options, subcommands, and subgroups for the init
|
|
|
5
5
|
group.
|
|
6
6
|
|
|
7
7
|
"""
|
|
8
|
+
|
|
8
9
|
from __future__ import annotations
|
|
9
10
|
|
|
10
11
|
import configparser
|
|
11
12
|
from pathlib import Path
|
|
13
|
+
from typing import Any
|
|
12
14
|
|
|
13
15
|
import click
|
|
14
16
|
import cloup
|
|
15
17
|
|
|
16
|
-
from
|
|
17
|
-
from
|
|
18
|
-
from
|
|
18
|
+
from manim._config import console
|
|
19
|
+
from manim.constants import CONTEXT_SETTINGS, EPILOG, QUALITIES
|
|
20
|
+
from manim.utils.file_ops import (
|
|
19
21
|
add_import_statement,
|
|
20
22
|
copy_template_files,
|
|
21
23
|
get_template_names,
|
|
@@ -30,16 +32,18 @@ CFG_DEFAULTS = {
|
|
|
30
32
|
"resolution": (854, 480),
|
|
31
33
|
}
|
|
32
34
|
|
|
35
|
+
__all__ = ["select_resolution", "update_cfg", "project", "scene"]
|
|
36
|
+
|
|
33
37
|
|
|
34
|
-
def select_resolution():
|
|
38
|
+
def select_resolution() -> tuple[int, int]:
|
|
35
39
|
"""Prompts input of type click.Choice from user. Presents options from QUALITIES constant.
|
|
36
40
|
|
|
37
41
|
Returns
|
|
38
42
|
-------
|
|
39
|
-
|
|
40
|
-
|
|
43
|
+
tuple[int, int]
|
|
44
|
+
Tuple containing height and width.
|
|
41
45
|
"""
|
|
42
|
-
resolution_options = []
|
|
46
|
+
resolution_options: list[tuple[int, int]] = []
|
|
43
47
|
for quality in QUALITIES.items():
|
|
44
48
|
resolution_options.append(
|
|
45
49
|
(quality[1]["pixel_height"], quality[1]["pixel_width"]),
|
|
@@ -47,22 +51,25 @@ def select_resolution():
|
|
|
47
51
|
resolution_options.pop()
|
|
48
52
|
choice = click.prompt(
|
|
49
53
|
"\nSelect resolution:\n",
|
|
50
|
-
type=
|
|
54
|
+
type=cloup.Choice([f"{i[0]}p" for i in resolution_options]),
|
|
51
55
|
show_default=False,
|
|
52
56
|
default="480p",
|
|
53
57
|
)
|
|
54
|
-
|
|
58
|
+
matches = [res for res in resolution_options if f"{res[0]}p" == choice]
|
|
59
|
+
return matches[0]
|
|
55
60
|
|
|
56
61
|
|
|
57
|
-
def update_cfg(cfg_dict: dict, project_cfg_path: Path):
|
|
58
|
-
"""
|
|
62
|
+
def update_cfg(cfg_dict: dict[str, Any], project_cfg_path: Path) -> None:
|
|
63
|
+
"""Update the ``manim.cfg`` file after reading it from the specified
|
|
64
|
+
``project_cfg_path``.
|
|
59
65
|
|
|
60
66
|
Parameters
|
|
61
67
|
----------
|
|
62
68
|
cfg_dict
|
|
63
|
-
|
|
69
|
+
Values used to update ``manim.cfg`` which is found in
|
|
70
|
+
``project_cfg_path``.
|
|
64
71
|
project_cfg_path
|
|
65
|
-
Path of manim.cfg file.
|
|
72
|
+
Path of the ``manim.cfg`` file.
|
|
66
73
|
"""
|
|
67
74
|
config = configparser.ConfigParser()
|
|
68
75
|
config.read(project_cfg_path)
|
|
@@ -82,7 +89,7 @@ def update_cfg(cfg_dict: dict, project_cfg_path: Path):
|
|
|
82
89
|
context_settings=CONTEXT_SETTINGS,
|
|
83
90
|
epilog=EPILOG,
|
|
84
91
|
)
|
|
85
|
-
@cloup.argument("project_name", type=Path, required=False)
|
|
92
|
+
@cloup.argument("project_name", type=cloup.Path(path_type=Path), required=False)
|
|
86
93
|
@cloup.option(
|
|
87
94
|
"-d",
|
|
88
95
|
"--default",
|
|
@@ -91,13 +98,14 @@ def update_cfg(cfg_dict: dict, project_cfg_path: Path):
|
|
|
91
98
|
help="Default settings for project creation.",
|
|
92
99
|
nargs=1,
|
|
93
100
|
)
|
|
94
|
-
def project(default_settings, **
|
|
101
|
+
def project(default_settings: bool, **kwargs: Any) -> None:
|
|
95
102
|
"""Creates a new project.
|
|
96
103
|
|
|
97
104
|
PROJECT_NAME is the name of the folder in which the new project will be initialized.
|
|
98
105
|
"""
|
|
99
|
-
|
|
100
|
-
|
|
106
|
+
project_name: Path
|
|
107
|
+
if kwargs["project_name"]:
|
|
108
|
+
project_name = kwargs["project_name"]
|
|
101
109
|
else:
|
|
102
110
|
project_name = click.prompt("Project Name", type=Path)
|
|
103
111
|
|
|
@@ -114,7 +122,7 @@ def project(default_settings, **args):
|
|
|
114
122
|
)
|
|
115
123
|
else:
|
|
116
124
|
project_name.mkdir()
|
|
117
|
-
new_cfg = {}
|
|
125
|
+
new_cfg: dict[str, Any] = {}
|
|
118
126
|
new_cfg_path = Path.resolve(project_name / "manim.cfg")
|
|
119
127
|
|
|
120
128
|
if not default_settings:
|
|
@@ -142,23 +150,23 @@ def project(default_settings, **args):
|
|
|
142
150
|
)
|
|
143
151
|
@cloup.argument("scene_name", type=str, required=True)
|
|
144
152
|
@cloup.argument("file_name", type=str, required=False)
|
|
145
|
-
def scene(**
|
|
153
|
+
def scene(**kwargs: Any) -> None:
|
|
146
154
|
"""Inserts a SCENE to an existing FILE or creates a new FILE.
|
|
147
155
|
|
|
148
156
|
SCENE is the name of the scene that will be inserted.
|
|
149
157
|
|
|
150
158
|
FILE is the name of file in which the SCENE will be inserted.
|
|
151
159
|
"""
|
|
152
|
-
template_name = click.prompt(
|
|
160
|
+
template_name: str = click.prompt(
|
|
153
161
|
"template",
|
|
154
162
|
type=click.Choice(get_template_names(), False),
|
|
155
163
|
default="Default",
|
|
156
164
|
)
|
|
157
165
|
scene = (get_template_path() / f"{template_name}.mtp").resolve().read_text()
|
|
158
|
-
scene = scene.replace(template_name + "Template",
|
|
166
|
+
scene = scene.replace(template_name + "Template", kwargs["scene_name"], 1)
|
|
159
167
|
|
|
160
|
-
if
|
|
161
|
-
file_name = Path(
|
|
168
|
+
if kwargs["file_name"]:
|
|
169
|
+
file_name = Path(kwargs["file_name"])
|
|
162
170
|
|
|
163
171
|
if file_name.suffix != ".py":
|
|
164
172
|
file_name = file_name.with_suffix(file_name.suffix + ".py")
|
|
@@ -187,7 +195,7 @@ def scene(**args):
|
|
|
187
195
|
help="Create a new project or insert a new scene.",
|
|
188
196
|
)
|
|
189
197
|
@cloup.pass_context
|
|
190
|
-
def init(ctx):
|
|
198
|
+
def init(ctx: cloup.Context) -> None:
|
|
191
199
|
pass
|
|
192
200
|
|
|
193
201
|
|
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
|
),
|