manim 0.18.0__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.

Files changed (115) hide show
  1. manim/__init__.py +3 -6
  2. manim/__main__.py +18 -10
  3. manim/_config/__init__.py +5 -2
  4. manim/_config/cli_colors.py +12 -8
  5. manim/_config/default.cfg +1 -1
  6. manim/_config/logger_utils.py +9 -8
  7. manim/_config/utils.py +637 -449
  8. manim/animation/animation.py +9 -2
  9. manim/animation/composition.py +78 -40
  10. manim/animation/creation.py +12 -6
  11. manim/animation/fading.py +0 -1
  12. manim/animation/indication.py +10 -21
  13. manim/animation/movement.py +1 -2
  14. manim/animation/rotation.py +1 -1
  15. manim/animation/specialized.py +1 -1
  16. manim/animation/speedmodifier.py +7 -2
  17. manim/animation/transform_matching_parts.py +1 -1
  18. manim/camera/camera.py +13 -4
  19. manim/cli/cfg/group.py +18 -8
  20. manim/cli/checkhealth/checks.py +2 -0
  21. manim/cli/checkhealth/commands.py +2 -0
  22. manim/cli/default_group.py +13 -5
  23. manim/cli/init/commands.py +4 -1
  24. manim/cli/plugins/commands.py +3 -0
  25. manim/cli/render/commands.py +27 -20
  26. manim/cli/render/ease_of_access_options.py +4 -3
  27. manim/cli/render/global_options.py +9 -7
  28. manim/cli/render/output_options.py +6 -5
  29. manim/cli/render/render_options.py +13 -13
  30. manim/constants.py +54 -15
  31. manim/gui/gui.py +2 -0
  32. manim/mobject/geometry/arc.py +4 -4
  33. manim/mobject/geometry/boolean_ops.py +13 -9
  34. manim/mobject/geometry/line.py +16 -8
  35. manim/mobject/geometry/polygram.py +17 -5
  36. manim/mobject/geometry/tips.py +2 -2
  37. manim/mobject/graph.py +379 -106
  38. manim/mobject/graphing/coordinate_systems.py +17 -20
  39. manim/mobject/graphing/functions.py +14 -10
  40. manim/mobject/graphing/number_line.py +1 -1
  41. manim/mobject/mobject.py +175 -72
  42. manim/mobject/opengl/opengl_compatibility.py +2 -0
  43. manim/mobject/opengl/opengl_geometry.py +26 -1
  44. manim/mobject/opengl/opengl_image_mobject.py +2 -0
  45. manim/mobject/opengl/opengl_mobject.py +3 -0
  46. manim/mobject/opengl/opengl_point_cloud_mobject.py +2 -0
  47. manim/mobject/opengl/opengl_surface.py +2 -0
  48. manim/mobject/opengl/opengl_three_dimensions.py +2 -0
  49. manim/mobject/opengl/opengl_vectorized_mobject.py +19 -14
  50. manim/mobject/svg/brace.py +2 -0
  51. manim/mobject/svg/svg_mobject.py +10 -12
  52. manim/mobject/table.py +0 -1
  53. manim/mobject/text/code_mobject.py +2 -0
  54. manim/mobject/text/numbers.py +2 -0
  55. manim/mobject/text/tex_mobject.py +1 -1
  56. manim/mobject/text/text_mobject.py +43 -6
  57. manim/mobject/three_d/three_d_utils.py +4 -4
  58. manim/mobject/three_d/three_dimensions.py +4 -4
  59. manim/mobject/types/image_mobject.py +5 -1
  60. manim/mobject/types/point_cloud_mobject.py +2 -0
  61. manim/mobject/types/vectorized_mobject.py +124 -29
  62. manim/mobject/value_tracker.py +3 -3
  63. manim/mobject/vector_field.py +3 -1
  64. manim/plugins/__init__.py +15 -1
  65. manim/plugins/plugins_flags.py +11 -5
  66. manim/renderer/cairo_renderer.py +12 -2
  67. manim/renderer/opengl_renderer.py +2 -3
  68. manim/renderer/opengl_renderer_window.py +2 -0
  69. manim/renderer/shader_wrapper.py +2 -0
  70. manim/renderer/vectorized_mobject_rendering.py +5 -0
  71. manim/scene/scene.py +22 -6
  72. manim/scene/scene_file_writer.py +3 -1
  73. manim/scene/section.py +2 -0
  74. manim/scene/three_d_scene.py +5 -6
  75. manim/scene/vector_space_scene.py +21 -5
  76. manim/typing.py +567 -67
  77. manim/utils/bezier.py +9 -18
  78. manim/utils/caching.py +2 -0
  79. manim/utils/color/BS381.py +1 -0
  80. manim/utils/color/XKCD.py +1 -0
  81. manim/utils/color/core.py +31 -13
  82. manim/utils/commands.py +8 -1
  83. manim/utils/debug.py +0 -1
  84. manim/utils/deprecation.py +3 -2
  85. manim/utils/docbuild/__init__.py +17 -0
  86. manim/utils/docbuild/autoaliasattr_directive.py +197 -0
  87. manim/utils/docbuild/autocolor_directive.py +9 -4
  88. manim/utils/docbuild/manim_directive.py +18 -9
  89. manim/utils/docbuild/module_parsing.py +198 -0
  90. manim/utils/exceptions.py +6 -0
  91. manim/utils/family.py +2 -0
  92. manim/utils/family_ops.py +5 -0
  93. manim/utils/file_ops.py +6 -2
  94. manim/utils/hashing.py +2 -0
  95. manim/utils/ipython_magic.py +2 -0
  96. manim/utils/module_ops.py +2 -0
  97. manim/utils/opengl.py +14 -0
  98. manim/utils/parameter_parsing.py +31 -0
  99. manim/utils/paths.py +12 -20
  100. manim/utils/rate_functions.py +6 -8
  101. manim/utils/space_ops.py +81 -36
  102. manim/utils/testing/__init__.py +17 -0
  103. manim/utils/testing/frames_comparison.py +7 -5
  104. manim/utils/tex.py +124 -196
  105. manim/utils/tex_file_writing.py +2 -0
  106. manim/utils/tex_templates.py +1 -0
  107. {manim-0.18.0.dist-info → manim-0.18.1.dist-info}/LICENSE.community +1 -1
  108. {manim-0.18.0.dist-info → manim-0.18.1.dist-info}/METADATA +29 -35
  109. {manim-0.18.0.dist-info → manim-0.18.1.dist-info}/RECORD +112 -112
  110. {manim-0.18.0.dist-info → manim-0.18.1.dist-info}/WHEEL +1 -1
  111. manim/cli/new/__init__.py +0 -0
  112. manim/cli/new/group.py +0 -189
  113. manim/plugins/import_plugins.py +0 -43
  114. {manim-0.18.0.dist-info → manim-0.18.1.dist-info}/LICENSE +0 -0
  115. {manim-0.18.0.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
@@ -24,6 +24,7 @@ in the standard:
24
24
  .. automanimcolormodule:: manim.utils.color.BS381
25
25
 
26
26
  """
27
+
27
28
  from .core import ManimColor
28
29
 
29
30
  BS381_101 = ManimColor("#94BFAC")
manim/utils/color/XKCD.py CHANGED
@@ -23,6 +23,7 @@ taken from https://www.w3schools.com/colors/colors_xkcd.asp.
23
23
  .. automanimcolormodule:: manim.utils.color.XKCD
24
24
 
25
25
  """
26
+
26
27
  from .core import ManimColor
27
28
 
28
29
  ACIDGREEN = ManimColor("#8FFE09")
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 inconsitencies by constantly
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 bei interpreted as a single color.
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 = f"#{int(self._internal_value[0]*255):02X}{int(self._internal_value[1]*255):02X}{int(self._internal_value[2]*255):02X}"
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 is the representation for all types that are parsable to a color in manim"""
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 refer to :meth:`to_rgb` in :class:`ManimColor`
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(command, cwd=cwd, input=command_input, capture_output=True, text=True)
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
@@ -1,6 +1,5 @@
1
1
  """Debugging utilities."""
2
2
 
3
-
4
3
  from __future__ import annotations
5
4
 
6
5
  __all__ = ["print_family", "index_labels"]
@@ -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
- | (Iterable[tuple[str, str] | Callable[..., dict[str, Any]]]) = None,
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
 
@@ -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
- classnamedict = {}
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"{' '*(max_file_length)} {row[2].rjust(7)}s {row[1]}")
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