manim 0.18.0.post0__py3-none-any.whl → 0.18.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.
Potentially problematic release.
This version of manim might be problematic. Click here for more details.
- manim/__init__.py +3 -6
- manim/__main__.py +18 -10
- manim/_config/__init__.py +5 -2
- manim/_config/cli_colors.py +12 -8
- manim/_config/default.cfg +1 -1
- manim/_config/logger_utils.py +9 -8
- manim/_config/utils.py +637 -449
- manim/animation/animation.py +9 -2
- manim/animation/composition.py +78 -40
- manim/animation/creation.py +12 -6
- manim/animation/fading.py +0 -1
- manim/animation/indication.py +10 -21
- manim/animation/movement.py +1 -2
- manim/animation/rotation.py +1 -1
- manim/animation/specialized.py +1 -1
- manim/animation/speedmodifier.py +7 -2
- manim/animation/transform_matching_parts.py +1 -1
- manim/camera/camera.py +13 -4
- manim/cli/cfg/group.py +18 -8
- manim/cli/checkhealth/checks.py +2 -0
- manim/cli/checkhealth/commands.py +2 -0
- manim/cli/default_group.py +13 -5
- manim/cli/init/commands.py +4 -1
- manim/cli/plugins/commands.py +3 -0
- manim/cli/render/commands.py +27 -20
- manim/cli/render/ease_of_access_options.py +4 -3
- manim/cli/render/global_options.py +9 -7
- manim/cli/render/output_options.py +6 -5
- manim/cli/render/render_options.py +13 -13
- manim/constants.py +54 -15
- manim/gui/gui.py +2 -0
- manim/mobject/geometry/arc.py +4 -4
- manim/mobject/geometry/boolean_ops.py +13 -9
- manim/mobject/geometry/line.py +16 -8
- manim/mobject/geometry/polygram.py +17 -5
- manim/mobject/geometry/tips.py +2 -2
- manim/mobject/graph.py +379 -106
- manim/mobject/graphing/coordinate_systems.py +17 -20
- manim/mobject/graphing/functions.py +14 -10
- manim/mobject/graphing/number_line.py +1 -1
- manim/mobject/mobject.py +175 -72
- manim/mobject/opengl/opengl_compatibility.py +2 -0
- manim/mobject/opengl/opengl_geometry.py +26 -1
- manim/mobject/opengl/opengl_image_mobject.py +2 -0
- manim/mobject/opengl/opengl_mobject.py +3 -0
- manim/mobject/opengl/opengl_point_cloud_mobject.py +2 -0
- manim/mobject/opengl/opengl_surface.py +2 -0
- manim/mobject/opengl/opengl_three_dimensions.py +2 -0
- manim/mobject/opengl/opengl_vectorized_mobject.py +19 -14
- manim/mobject/svg/brace.py +2 -0
- manim/mobject/svg/svg_mobject.py +2 -2
- manim/mobject/table.py +0 -1
- manim/mobject/text/code_mobject.py +2 -0
- manim/mobject/text/numbers.py +2 -0
- manim/mobject/text/tex_mobject.py +1 -1
- manim/mobject/text/text_mobject.py +43 -6
- manim/mobject/three_d/three_d_utils.py +4 -4
- manim/mobject/three_d/three_dimensions.py +4 -4
- manim/mobject/types/image_mobject.py +5 -1
- manim/mobject/types/point_cloud_mobject.py +2 -0
- manim/mobject/types/vectorized_mobject.py +124 -29
- manim/mobject/value_tracker.py +3 -3
- manim/mobject/vector_field.py +3 -1
- manim/plugins/__init__.py +15 -1
- manim/plugins/plugins_flags.py +11 -5
- manim/renderer/cairo_renderer.py +12 -2
- manim/renderer/opengl_renderer.py +2 -3
- manim/renderer/opengl_renderer_window.py +2 -0
- manim/renderer/shader_wrapper.py +2 -0
- manim/renderer/vectorized_mobject_rendering.py +5 -0
- manim/scene/scene.py +22 -6
- manim/scene/scene_file_writer.py +3 -1
- manim/scene/section.py +2 -0
- manim/scene/three_d_scene.py +5 -6
- manim/scene/vector_space_scene.py +21 -5
- manim/typing.py +567 -67
- manim/utils/bezier.py +9 -18
- manim/utils/caching.py +2 -0
- manim/utils/color/BS381.py +1 -0
- manim/utils/color/XKCD.py +1 -0
- manim/utils/color/core.py +31 -13
- manim/utils/commands.py +8 -1
- manim/utils/debug.py +0 -1
- manim/utils/deprecation.py +3 -2
- manim/utils/docbuild/__init__.py +17 -0
- manim/utils/docbuild/autoaliasattr_directive.py +197 -0
- manim/utils/docbuild/autocolor_directive.py +9 -4
- manim/utils/docbuild/manim_directive.py +18 -9
- manim/utils/docbuild/module_parsing.py +198 -0
- manim/utils/exceptions.py +6 -0
- manim/utils/family.py +2 -0
- manim/utils/family_ops.py +5 -0
- manim/utils/file_ops.py +6 -2
- manim/utils/hashing.py +2 -0
- manim/utils/ipython_magic.py +2 -0
- manim/utils/module_ops.py +2 -0
- manim/utils/opengl.py +14 -0
- manim/utils/parameter_parsing.py +31 -0
- manim/utils/paths.py +12 -20
- manim/utils/rate_functions.py +6 -8
- manim/utils/space_ops.py +81 -36
- manim/utils/testing/__init__.py +17 -0
- manim/utils/testing/frames_comparison.py +7 -5
- manim/utils/tex.py +124 -196
- manim/utils/tex_file_writing.py +2 -0
- manim/utils/tex_templates.py +1 -0
- {manim-0.18.0.post0.dist-info → manim-0.18.1.dist-info}/LICENSE.community +1 -1
- {manim-0.18.0.post0.dist-info → manim-0.18.1.dist-info}/METADATA +29 -35
- manim-0.18.1.dist-info/RECORD +217 -0
- 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.18.1.dist-info}/LICENSE +0 -0
- {manim-0.18.0.post0.dist-info → manim-0.18.1.dist-info}/WHEEL +0 -0
- {manim-0.18.0.post0.dist-info → manim-0.18.1.dist-info}/entry_points.txt +0 -0
manim/utils/bezier.py
CHANGED
|
@@ -261,13 +261,11 @@ def quadratic_bezier_remap(
|
|
|
261
261
|
|
|
262
262
|
|
|
263
263
|
@overload
|
|
264
|
-
def interpolate(start: float, end: float, alpha: float) -> float:
|
|
265
|
-
...
|
|
264
|
+
def interpolate(start: float, end: float, alpha: float) -> float: ...
|
|
266
265
|
|
|
267
266
|
|
|
268
267
|
@overload
|
|
269
|
-
def interpolate(start: Point3D, end: Point3D, alpha: float) -> Point3D:
|
|
270
|
-
...
|
|
268
|
+
def interpolate(start: Point3D, end: Point3D, alpha: float) -> Point3D: ...
|
|
271
269
|
|
|
272
270
|
|
|
273
271
|
def interpolate(
|
|
@@ -321,13 +319,11 @@ def integer_interpolate(
|
|
|
321
319
|
|
|
322
320
|
|
|
323
321
|
@overload
|
|
324
|
-
def mid(start: float, end: float) -> float:
|
|
325
|
-
...
|
|
322
|
+
def mid(start: float, end: float) -> float: ...
|
|
326
323
|
|
|
327
324
|
|
|
328
325
|
@overload
|
|
329
|
-
def mid(start: Point3D, end: Point3D) -> Point3D:
|
|
330
|
-
...
|
|
326
|
+
def mid(start: Point3D, end: Point3D) -> Point3D: ...
|
|
331
327
|
|
|
332
328
|
|
|
333
329
|
def mid(start: float | Point3D, end: float | Point3D) -> float | Point3D:
|
|
@@ -348,18 +344,15 @@ def mid(start: float | Point3D, end: float | Point3D) -> float | Point3D:
|
|
|
348
344
|
|
|
349
345
|
|
|
350
346
|
@overload
|
|
351
|
-
def inverse_interpolate(start: float, end: float, value: float) -> float:
|
|
352
|
-
...
|
|
347
|
+
def inverse_interpolate(start: float, end: float, value: float) -> float: ...
|
|
353
348
|
|
|
354
349
|
|
|
355
350
|
@overload
|
|
356
|
-
def inverse_interpolate(start: float, end: float, value: Point3D) -> Point3D:
|
|
357
|
-
...
|
|
351
|
+
def inverse_interpolate(start: float, end: float, value: Point3D) -> Point3D: ...
|
|
358
352
|
|
|
359
353
|
|
|
360
354
|
@overload
|
|
361
|
-
def inverse_interpolate(start: Point3D, end: Point3D, value: Point3D) -> Point3D:
|
|
362
|
-
...
|
|
355
|
+
def inverse_interpolate(start: Point3D, end: Point3D, value: Point3D) -> Point3D: ...
|
|
363
356
|
|
|
364
357
|
|
|
365
358
|
def inverse_interpolate(
|
|
@@ -408,8 +401,7 @@ def match_interpolate(
|
|
|
408
401
|
old_start: float,
|
|
409
402
|
old_end: float,
|
|
410
403
|
old_value: float,
|
|
411
|
-
) -> float:
|
|
412
|
-
...
|
|
404
|
+
) -> float: ...
|
|
413
405
|
|
|
414
406
|
|
|
415
407
|
@overload
|
|
@@ -419,8 +411,7 @@ def match_interpolate(
|
|
|
419
411
|
old_start: float,
|
|
420
412
|
old_end: float,
|
|
421
413
|
old_value: Point3D,
|
|
422
|
-
) -> Point3D:
|
|
423
|
-
...
|
|
414
|
+
) -> Point3D: ...
|
|
424
415
|
|
|
425
416
|
|
|
426
417
|
def match_interpolate(
|
manim/utils/caching.py
CHANGED
|
@@ -5,6 +5,8 @@ from typing import Callable
|
|
|
5
5
|
from .. import config, logger
|
|
6
6
|
from ..utils.hashing import get_hash_from_play_call
|
|
7
7
|
|
|
8
|
+
__all__ = ["handle_caching_play"]
|
|
9
|
+
|
|
8
10
|
|
|
9
11
|
def handle_caching_play(func: Callable[..., None]):
|
|
10
12
|
"""Decorator that returns a wrapped version of func that will compute
|
manim/utils/color/BS381.py
CHANGED
manim/utils/color/XKCD.py
CHANGED
manim/utils/color/core.py
CHANGED
|
@@ -52,7 +52,6 @@ from ...utils.space_ops import normalize
|
|
|
52
52
|
|
|
53
53
|
# import manim._config as _config
|
|
54
54
|
|
|
55
|
-
|
|
56
55
|
re_hex = re.compile("((?<=#)|(?<=0x))[A-F0-9]{6,8}", re.IGNORECASE)
|
|
57
56
|
|
|
58
57
|
|
|
@@ -63,7 +62,7 @@ class ManimColor:
|
|
|
63
62
|
It's internal representation is a 4 element array of floats corresponding
|
|
64
63
|
to a [r,g,b,a] value where r,g,b,a can be between 0 to 1.
|
|
65
64
|
|
|
66
|
-
This is done in order to reduce the amount of color
|
|
65
|
+
This is done in order to reduce the amount of color inconsistencies by constantly
|
|
67
66
|
casting between integers and floats which introduces errors.
|
|
68
67
|
|
|
69
68
|
The class can accept any value of type :class:`ParsableManimColor` i.e.
|
|
@@ -75,19 +74,33 @@ class ManimColor:
|
|
|
75
74
|
Be careful when passing strings to ManimColor it can create a big overhead for the color processing.
|
|
76
75
|
|
|
77
76
|
If you want to parse a list of colors use the function :meth:`parse` in :class:`ManimColor` which assumes that
|
|
78
|
-
you are going to pass a list of color so arrays will not
|
|
77
|
+
you are going to pass a list of color so arrays will not be interpreted as a single color.
|
|
79
78
|
|
|
80
79
|
.. warning::
|
|
81
80
|
If you pass an array of numbers to :meth:`parse` it will interpret the r,g,b,a numbers in that array as colors
|
|
82
81
|
so instead of the expect singular color you get and array with 4 colors.
|
|
83
82
|
|
|
84
|
-
For conversion behaviors see the _internal functions for further documentation
|
|
83
|
+
For conversion behaviors see the ``_internal`` functions for further documentation
|
|
84
|
+
|
|
85
|
+
You can create a ``ManimColor`` instance via its classmethods. See the respective methods for more info.
|
|
86
|
+
|
|
87
|
+
.. code-block:: python
|
|
88
|
+
|
|
89
|
+
mycolor = ManimColor.from_rgb((0, 1, 0.4, 0.5))
|
|
90
|
+
myothercolor = ManimColor.from_rgb((153, 255, 255))
|
|
91
|
+
|
|
92
|
+
You can also convert between different color spaces:
|
|
93
|
+
|
|
94
|
+
.. code-block:: python
|
|
95
|
+
|
|
96
|
+
mycolor_hex = mycolor.to_hex()
|
|
97
|
+
myoriginalcolor = ManimColor.from_hex(mycolor_hex).to_hsv()
|
|
85
98
|
|
|
86
99
|
Parameters
|
|
87
100
|
----------
|
|
88
101
|
value
|
|
89
102
|
Some representation of a color (e.g., a string or
|
|
90
|
-
a suitable tuple).
|
|
103
|
+
a suitable tuple). The default ``None`` is ``BLACK``.
|
|
91
104
|
alpha
|
|
92
105
|
The opacity of the color. By default, colors are
|
|
93
106
|
fully opaque (value 1.0).
|
|
@@ -460,9 +473,13 @@ class ManimColor:
|
|
|
460
473
|
str
|
|
461
474
|
A hex string starting with a # with either 6 or 8 nibbles depending on your input, by default 6 i.e #XXXXXX
|
|
462
475
|
"""
|
|
463
|
-
tmp =
|
|
476
|
+
tmp = (
|
|
477
|
+
f"#{int(self._internal_value[0] * 255):02X}"
|
|
478
|
+
f"{int(self._internal_value[1] * 255):02X}"
|
|
479
|
+
f"{int(self._internal_value[2] * 255):02X}"
|
|
480
|
+
)
|
|
464
481
|
if with_alpha:
|
|
465
|
-
tmp += f"{int(self._internal_value[3]*255):02X}"
|
|
482
|
+
tmp += f"{int(self._internal_value[3] * 255):02X}"
|
|
466
483
|
return tmp
|
|
467
484
|
|
|
468
485
|
def to_hsv(self) -> HSV_Array_Float:
|
|
@@ -615,8 +632,7 @@ class ManimColor:
|
|
|
615
632
|
cls,
|
|
616
633
|
color: ParsableManimColor | None,
|
|
617
634
|
alpha: float = ...,
|
|
618
|
-
) -> Self:
|
|
619
|
-
...
|
|
635
|
+
) -> Self: ...
|
|
620
636
|
|
|
621
637
|
@overload
|
|
622
638
|
@classmethod
|
|
@@ -624,8 +640,7 @@ class ManimColor:
|
|
|
624
640
|
cls,
|
|
625
641
|
color: Sequence[ParsableManimColor],
|
|
626
642
|
alpha: float = ...,
|
|
627
|
-
) -> list[Self]:
|
|
628
|
-
...
|
|
643
|
+
) -> list[Self]: ...
|
|
629
644
|
|
|
630
645
|
@classmethod
|
|
631
646
|
def parse(
|
|
@@ -715,14 +730,17 @@ ParsableManimColor: TypeAlias = Union[
|
|
|
715
730
|
RGBA_Array_Int,
|
|
716
731
|
RGBA_Array_Float,
|
|
717
732
|
]
|
|
718
|
-
"""ParsableManimColor
|
|
733
|
+
"""`ParsableManimColor` represents all the types which can be parsed
|
|
734
|
+
to a color in Manim.
|
|
735
|
+
"""
|
|
719
736
|
|
|
720
737
|
|
|
721
738
|
ManimColorT = TypeVar("ManimColorT", bound=ManimColor)
|
|
722
739
|
|
|
723
740
|
|
|
724
741
|
def color_to_rgb(color: ParsableManimColor) -> RGB_Array_Float:
|
|
725
|
-
"""Helper function for use in functional style programming
|
|
742
|
+
"""Helper function for use in functional style programming.
|
|
743
|
+
Refer to :meth:`to_rgb` in :class:`ManimColor`.
|
|
726
744
|
|
|
727
745
|
Parameters
|
|
728
746
|
----------
|
manim/utils/commands.py
CHANGED
|
@@ -14,7 +14,14 @@ __all__ = [
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
def capture(command, cwd=None, command_input=None):
|
|
17
|
-
p = run(
|
|
17
|
+
p = run(
|
|
18
|
+
command,
|
|
19
|
+
cwd=cwd,
|
|
20
|
+
input=command_input,
|
|
21
|
+
capture_output=True,
|
|
22
|
+
text=True,
|
|
23
|
+
encoding="utf-8",
|
|
24
|
+
)
|
|
18
25
|
out, err = p.stdout, p.stderr
|
|
19
26
|
return out, err, p.returncode
|
|
20
27
|
|
manim/utils/debug.py
CHANGED
manim/utils/deprecation.py
CHANGED
|
@@ -233,8 +233,9 @@ def deprecated_params(
|
|
|
233
233
|
since: str | None = None,
|
|
234
234
|
until: str | None = None,
|
|
235
235
|
message: str | None = "",
|
|
236
|
-
redirections: None
|
|
237
|
-
|
|
236
|
+
redirections: None | (
|
|
237
|
+
Iterable[tuple[str, str] | Callable[..., dict[str, Any]]]
|
|
238
|
+
) = None,
|
|
238
239
|
) -> Callable:
|
|
239
240
|
"""Decorator to mark parameters of a callable as deprecated.
|
|
240
241
|
|
manim/utils/docbuild/__init__.py
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Utilities for building the Manim documentation.
|
|
2
|
+
|
|
3
|
+
For more information about the Manim documentation building, see:
|
|
4
|
+
|
|
5
|
+
- :doc:`/contributing/development`, specifically the ``Documentation``
|
|
6
|
+
bullet point under :ref:`polishing-changes-and-submitting-a-pull-request`
|
|
7
|
+
- :doc:`/contributing/docs`
|
|
8
|
+
|
|
9
|
+
.. autosummary::
|
|
10
|
+
:toctree: ../reference
|
|
11
|
+
|
|
12
|
+
autoaliasattr_directive
|
|
13
|
+
autocolor_directive
|
|
14
|
+
manim_directive
|
|
15
|
+
module_parsing
|
|
16
|
+
|
|
17
|
+
"""
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"""A directive for documenting type aliases and other module-level attributes."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from docutils import nodes
|
|
8
|
+
from docutils.parsers.rst import Directive
|
|
9
|
+
from docutils.statemachine import ViewList
|
|
10
|
+
|
|
11
|
+
from manim.utils.docbuild.module_parsing import parse_module_attributes
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from sphinx.application import Sphinx
|
|
15
|
+
from typing_extensions import TypeAlias
|
|
16
|
+
|
|
17
|
+
__all__ = ["AliasAttrDocumenter"]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
ALIAS_DOCS_DICT, DATA_DICT = parse_module_attributes()
|
|
21
|
+
ALIAS_LIST = [
|
|
22
|
+
alias_name
|
|
23
|
+
for module_dict in ALIAS_DOCS_DICT.values()
|
|
24
|
+
for category_dict in module_dict.values()
|
|
25
|
+
for alias_name in category_dict.keys()
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def smart_replace(base: str, alias: str, substitution: str) -> str:
|
|
30
|
+
"""Auxiliary function for substituting type aliases into a base
|
|
31
|
+
string, when there are overlaps between the aliases themselves.
|
|
32
|
+
|
|
33
|
+
Parameters
|
|
34
|
+
----------
|
|
35
|
+
base
|
|
36
|
+
The string in which the type aliases will be located and
|
|
37
|
+
replaced.
|
|
38
|
+
alias
|
|
39
|
+
The substring to be substituted.
|
|
40
|
+
substitution
|
|
41
|
+
The string which will replace every occurrence of ``alias``.
|
|
42
|
+
|
|
43
|
+
Returns
|
|
44
|
+
-------
|
|
45
|
+
str
|
|
46
|
+
The new string after the alias substitution.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
occurrences = []
|
|
50
|
+
len_alias = len(alias)
|
|
51
|
+
len_base = len(base)
|
|
52
|
+
condition = lambda char: (not char.isalnum()) and char != "_"
|
|
53
|
+
|
|
54
|
+
start = 0
|
|
55
|
+
i = 0
|
|
56
|
+
while True:
|
|
57
|
+
i = base.find(alias, start)
|
|
58
|
+
if i == -1:
|
|
59
|
+
break
|
|
60
|
+
if (i == 0 or condition(base[i - 1])) and (
|
|
61
|
+
i + len_alias == len_base or condition(base[i + len_alias])
|
|
62
|
+
):
|
|
63
|
+
occurrences.append(i)
|
|
64
|
+
start = i + len_alias
|
|
65
|
+
|
|
66
|
+
for o in occurrences[::-1]:
|
|
67
|
+
base = base[:o] + substitution + base[o + len_alias :]
|
|
68
|
+
|
|
69
|
+
return base
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def setup(app: Sphinx) -> None:
|
|
73
|
+
app.add_directive("autoaliasattr", AliasAttrDocumenter)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class AliasAttrDocumenter(Directive):
|
|
77
|
+
"""Directive which replaces Sphinx's Autosummary for module-level
|
|
78
|
+
attributes: instead, it manually crafts a new "Type Aliases"
|
|
79
|
+
section, where all the module-level attributes which are explicitly
|
|
80
|
+
annotated as :class:`TypeAlias` are considered as such, for their
|
|
81
|
+
use all around the Manim docs.
|
|
82
|
+
|
|
83
|
+
These type aliases are separated from the "regular" module-level
|
|
84
|
+
attributes, which get their traditional "Module Attributes"
|
|
85
|
+
section autogenerated with Sphinx's Autosummary under "Type
|
|
86
|
+
Aliases".
|
|
87
|
+
|
|
88
|
+
See ``docs/source/_templates/autosummary/module.rst`` to watch
|
|
89
|
+
this directive in action.
|
|
90
|
+
|
|
91
|
+
See :func:`~.parse_module_attributes` for more information on how
|
|
92
|
+
the modules are parsed to obtain the :class:`TypeAlias` information
|
|
93
|
+
and separate it from the other attributes.
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
objtype = "autoaliasattr"
|
|
97
|
+
required_arguments = 1
|
|
98
|
+
has_content = True
|
|
99
|
+
|
|
100
|
+
def run(self) -> list[nodes.Element]:
|
|
101
|
+
module_name = self.arguments[0]
|
|
102
|
+
# Slice module_name[6:] to remove the "manim." prefix which is
|
|
103
|
+
# not present in the keys of the DICTs
|
|
104
|
+
module_alias_dict = ALIAS_DOCS_DICT.get(module_name[6:], None)
|
|
105
|
+
module_attrs_list = DATA_DICT.get(module_name[6:], None)
|
|
106
|
+
|
|
107
|
+
content = nodes.container()
|
|
108
|
+
|
|
109
|
+
# Add "Type Aliases" section
|
|
110
|
+
if module_alias_dict is not None:
|
|
111
|
+
module_alias_section = nodes.section(ids=[f"{module_name}.alias"])
|
|
112
|
+
content += module_alias_section
|
|
113
|
+
|
|
114
|
+
# Use a rubric (title-like), just like in `module.rst`
|
|
115
|
+
module_alias_section += nodes.rubric(text="Type Aliases")
|
|
116
|
+
|
|
117
|
+
# category_name: str
|
|
118
|
+
# category_dict: AliasCategoryDict = dict[str, AliasInfo]
|
|
119
|
+
for category_name, category_dict in module_alias_dict.items():
|
|
120
|
+
category_section = nodes.section(
|
|
121
|
+
ids=[category_name.lower().replace(" ", "_")]
|
|
122
|
+
)
|
|
123
|
+
module_alias_section += category_section
|
|
124
|
+
# category_name can be possibly "" for uncategorized aliases
|
|
125
|
+
if category_name:
|
|
126
|
+
category_section += nodes.title(text=category_name)
|
|
127
|
+
|
|
128
|
+
category_alias_container = nodes.container()
|
|
129
|
+
category_section += category_alias_container
|
|
130
|
+
|
|
131
|
+
# alias_name: str
|
|
132
|
+
# alias_info: AliasInfo = dict[str, str]
|
|
133
|
+
# Contains "definition": str
|
|
134
|
+
# Can possibly contain "doc": str
|
|
135
|
+
for alias_name, alias_info in category_dict.items():
|
|
136
|
+
# Replace all occurrences of type aliases in the
|
|
137
|
+
# definition for automatic cross-referencing!
|
|
138
|
+
alias_def = alias_info["definition"]
|
|
139
|
+
for A in ALIAS_LIST:
|
|
140
|
+
alias_def = smart_replace(alias_def, A, f":class:`~.{A}`")
|
|
141
|
+
|
|
142
|
+
# Using the `.. class::` directive is CRUCIAL, since
|
|
143
|
+
# function/method parameters are always annotated via
|
|
144
|
+
# classes - therefore Sphinx expects a class
|
|
145
|
+
unparsed = ViewList(
|
|
146
|
+
[
|
|
147
|
+
f".. class:: {alias_name}",
|
|
148
|
+
"",
|
|
149
|
+
" .. parsed-literal::",
|
|
150
|
+
"",
|
|
151
|
+
f" {alias_def}",
|
|
152
|
+
"",
|
|
153
|
+
]
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
if "doc" in alias_info:
|
|
157
|
+
# Replace all occurrences of type aliases in
|
|
158
|
+
# the docs for automatic cross-referencing!
|
|
159
|
+
alias_doc = alias_info["doc"]
|
|
160
|
+
for A in ALIAS_LIST:
|
|
161
|
+
alias_doc = alias_doc.replace(f"`{A}`", f":class:`~.{A}`")
|
|
162
|
+
|
|
163
|
+
# Add all the lines with 4 spaces behind, to consider all the
|
|
164
|
+
# documentation as a paragraph INSIDE the `.. class::` block
|
|
165
|
+
doc_lines = alias_doc.split("\n")
|
|
166
|
+
unparsed.extend(ViewList([f" {line}" for line in doc_lines]))
|
|
167
|
+
|
|
168
|
+
# Parse the reST text into a fresh container
|
|
169
|
+
# https://www.sphinx-doc.org/en/master/extdev/markupapi.html#parsing-directive-content-as-rest
|
|
170
|
+
alias_container = nodes.container()
|
|
171
|
+
self.state.nested_parse(unparsed, 0, alias_container)
|
|
172
|
+
category_alias_container += alias_container
|
|
173
|
+
|
|
174
|
+
# Then, add the traditional "Module Attributes" section
|
|
175
|
+
if module_attrs_list is not None:
|
|
176
|
+
module_attrs_section = nodes.section(ids=[f"{module_name}.data"])
|
|
177
|
+
content += module_attrs_section
|
|
178
|
+
|
|
179
|
+
# Use the same rubric (title-like) as in `module.rst`
|
|
180
|
+
module_attrs_section += nodes.rubric(text="Module Attributes")
|
|
181
|
+
# Let Sphinx Autosummary do its thing as always
|
|
182
|
+
# Add all the attribute names with 4 spaces behind, so that
|
|
183
|
+
# they're considered as INSIDE the `.. autosummary::` block
|
|
184
|
+
unparsed = ViewList(
|
|
185
|
+
[
|
|
186
|
+
".. autosummary::",
|
|
187
|
+
*(f" {attr}" for attr in module_attrs_list),
|
|
188
|
+
]
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
# Parse the reST text into a fresh container
|
|
192
|
+
# https://www.sphinx-doc.org/en/master/extdev/markupapi.html#parsing-directive-content-as-rest
|
|
193
|
+
data_container = nodes.container()
|
|
194
|
+
self.state.nested_parse(unparsed, 0, data_container)
|
|
195
|
+
module_attrs_section += data_container
|
|
196
|
+
|
|
197
|
+
return [content]
|
|
@@ -1,13 +1,20 @@
|
|
|
1
|
+
"""A directive for documenting colors in Manim."""
|
|
2
|
+
|
|
1
3
|
from __future__ import annotations
|
|
2
4
|
|
|
3
5
|
import inspect
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
4
7
|
|
|
5
8
|
from docutils import nodes
|
|
6
9
|
from docutils.parsers.rst import Directive
|
|
7
|
-
from sphinx.application import Sphinx
|
|
8
10
|
|
|
9
11
|
from manim import ManimColor
|
|
10
12
|
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from sphinx.application import Sphinx
|
|
15
|
+
|
|
16
|
+
__all__ = ["ManimColorModuleDocumenter"]
|
|
17
|
+
|
|
11
18
|
|
|
12
19
|
def setup(app: Sphinx) -> None:
|
|
13
20
|
app.add_directive("automanimcolormodule", ManimColorModuleDocumenter)
|
|
@@ -21,9 +28,7 @@ class ManimColorModuleDocumenter(Directive):
|
|
|
21
28
|
def add_directive_header(self, sig: str) -> None:
|
|
22
29
|
super().add_directive_header(sig)
|
|
23
30
|
|
|
24
|
-
def run(
|
|
25
|
-
self,
|
|
26
|
-
) -> None:
|
|
31
|
+
def run(self) -> list[nodes.Element]:
|
|
27
32
|
module_name = self.arguments[0]
|
|
28
33
|
try:
|
|
29
34
|
import importlib
|
|
@@ -77,6 +77,7 @@ directive:
|
|
|
77
77
|
that is rendered in a reference block after the source code.
|
|
78
78
|
|
|
79
79
|
"""
|
|
80
|
+
|
|
80
81
|
from __future__ import annotations
|
|
81
82
|
|
|
82
83
|
import csv
|
|
@@ -88,6 +89,7 @@ import sys
|
|
|
88
89
|
import textwrap
|
|
89
90
|
from pathlib import Path
|
|
90
91
|
from timeit import timeit
|
|
92
|
+
from typing import TYPE_CHECKING, Any
|
|
91
93
|
|
|
92
94
|
import jinja2
|
|
93
95
|
from docutils import nodes
|
|
@@ -97,7 +99,13 @@ from docutils.statemachine import StringList
|
|
|
97
99
|
from manim import QUALITIES
|
|
98
100
|
from manim import __version__ as manim_version
|
|
99
101
|
|
|
100
|
-
|
|
102
|
+
if TYPE_CHECKING:
|
|
103
|
+
from sphinx.application import Sphinx
|
|
104
|
+
|
|
105
|
+
__all__ = ["ManimDirective"]
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
classnamedict: dict[str, int] = {}
|
|
101
109
|
|
|
102
110
|
|
|
103
111
|
class SkipManimNode(nodes.Admonition, nodes.Element):
|
|
@@ -110,13 +118,13 @@ class SkipManimNode(nodes.Admonition, nodes.Element):
|
|
|
110
118
|
pass
|
|
111
119
|
|
|
112
120
|
|
|
113
|
-
def visit(self, node, name=""):
|
|
121
|
+
def visit(self: SkipManimNode, node: nodes.Element, name: str = "") -> None:
|
|
114
122
|
self.visit_admonition(node, name)
|
|
115
123
|
if not isinstance(node[0], nodes.title):
|
|
116
124
|
node.insert(0, nodes.title("skip-manim", "Example Placeholder"))
|
|
117
125
|
|
|
118
126
|
|
|
119
|
-
def depart(self, node):
|
|
127
|
+
def depart(self: SkipManimNode, node: nodes.Element) -> None:
|
|
120
128
|
self.depart_admonition(node)
|
|
121
129
|
|
|
122
130
|
|
|
@@ -143,6 +151,7 @@ class ManimDirective(Directive):
|
|
|
143
151
|
|
|
144
152
|
See the module docstring for documentation.
|
|
145
153
|
"""
|
|
154
|
+
|
|
146
155
|
has_content = True
|
|
147
156
|
required_arguments = 1
|
|
148
157
|
optional_arguments = 0
|
|
@@ -162,7 +171,7 @@ class ManimDirective(Directive):
|
|
|
162
171
|
}
|
|
163
172
|
final_argument_whitespace = True
|
|
164
173
|
|
|
165
|
-
def run(self):
|
|
174
|
+
def run(self) -> list[nodes.Element]:
|
|
166
175
|
# Rendering is skipped if the tag skip-manim is present,
|
|
167
176
|
# or if we are making the pot-files
|
|
168
177
|
should_skip = (
|
|
@@ -341,7 +350,7 @@ class ManimDirective(Directive):
|
|
|
341
350
|
rendering_times_file_path = Path("../rendering_times.csv")
|
|
342
351
|
|
|
343
352
|
|
|
344
|
-
def _write_rendering_stats(scene_name, run_time, file_name):
|
|
353
|
+
def _write_rendering_stats(scene_name: str, run_time: str, file_name: str) -> None:
|
|
345
354
|
with rendering_times_file_path.open("a") as file:
|
|
346
355
|
csv.writer(file).writerow(
|
|
347
356
|
[
|
|
@@ -352,7 +361,7 @@ def _write_rendering_stats(scene_name, run_time, file_name):
|
|
|
352
361
|
)
|
|
353
362
|
|
|
354
363
|
|
|
355
|
-
def _log_rendering_times(*args):
|
|
364
|
+
def _log_rendering_times(*args: tuple[Any]) -> None:
|
|
356
365
|
if rendering_times_file_path.exists():
|
|
357
366
|
with rendering_times_file_path.open() as file:
|
|
358
367
|
data = list(csv.reader(file))
|
|
@@ -377,16 +386,16 @@ def _log_rendering_times(*args):
|
|
|
377
386
|
f"{key}{f'{time_sum:.3f}'.rjust(7, '.')}s => {len(group)} EXAMPLES",
|
|
378
387
|
)
|
|
379
388
|
for row in group:
|
|
380
|
-
print(f"{' '*
|
|
389
|
+
print(f"{' ' * max_file_length} {row[2].rjust(7)}s {row[1]}")
|
|
381
390
|
print("")
|
|
382
391
|
|
|
383
392
|
|
|
384
|
-
def _delete_rendering_times(*args):
|
|
393
|
+
def _delete_rendering_times(*args: tuple[Any]) -> None:
|
|
385
394
|
if rendering_times_file_path.exists():
|
|
386
395
|
rendering_times_file_path.unlink()
|
|
387
396
|
|
|
388
397
|
|
|
389
|
-
def setup(app):
|
|
398
|
+
def setup(app: Sphinx) -> dict[str, Any]:
|
|
390
399
|
app.add_node(SkipManimNode, html=(visit, depart))
|
|
391
400
|
|
|
392
401
|
setup.app = app
|