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.
Files changed (163) hide show
  1. manim/__init__.py +11 -6
  2. manim/__main__.py +62 -19
  3. manim/_config/__init__.py +10 -9
  4. manim/_config/cli_colors.py +26 -9
  5. manim/_config/default.cfg +1 -3
  6. manim/_config/logger_utils.py +23 -13
  7. manim/_config/utils.py +662 -468
  8. manim/animation/animation.py +164 -18
  9. manim/animation/changing.py +34 -23
  10. manim/animation/composition.py +265 -67
  11. manim/animation/creation.py +208 -26
  12. manim/animation/fading.py +16 -18
  13. manim/animation/growing.py +35 -15
  14. manim/animation/indication.py +150 -76
  15. manim/animation/movement.py +56 -22
  16. manim/animation/numbers.py +64 -6
  17. manim/animation/rotation.py +78 -7
  18. manim/animation/specialized.py +6 -7
  19. manim/animation/speedmodifier.py +13 -10
  20. manim/animation/transform.py +14 -11
  21. manim/animation/transform_matching_parts.py +3 -4
  22. manim/animation/updaters/mobject_update_utils.py +152 -30
  23. manim/animation/updaters/update.py +10 -7
  24. manim/camera/camera.py +182 -118
  25. manim/camera/mapping_camera.py +34 -3
  26. manim/camera/moving_camera.py +95 -74
  27. manim/camera/multi_camera.py +23 -15
  28. manim/camera/three_d_camera.py +70 -52
  29. manim/cli/__init__.py +17 -0
  30. manim/cli/cfg/group.py +76 -44
  31. manim/cli/checkhealth/checks.py +192 -0
  32. manim/cli/checkhealth/commands.py +90 -0
  33. manim/cli/default_group.py +158 -25
  34. manim/cli/init/commands.py +33 -25
  35. manim/cli/plugins/commands.py +16 -3
  36. manim/cli/render/commands.py +72 -60
  37. manim/cli/render/ease_of_access_options.py +4 -3
  38. manim/cli/render/global_options.py +59 -17
  39. manim/cli/render/output_options.py +6 -5
  40. manim/cli/render/render_options.py +98 -33
  41. manim/constants.py +109 -59
  42. manim/data_structures.py +31 -0
  43. manim/mobject/frame.py +8 -5
  44. manim/mobject/geometry/__init__.py +1 -0
  45. manim/mobject/geometry/arc.py +277 -135
  46. manim/mobject/geometry/boolean_ops.py +32 -31
  47. manim/mobject/geometry/labeled.py +376 -0
  48. manim/mobject/geometry/line.py +192 -87
  49. manim/mobject/geometry/polygram.py +224 -58
  50. manim/mobject/geometry/shape_matchers.py +61 -25
  51. manim/mobject/geometry/tips.py +122 -48
  52. manim/mobject/graph.py +1027 -419
  53. manim/mobject/graphing/coordinate_systems.py +533 -278
  54. manim/mobject/graphing/functions.py +53 -32
  55. manim/mobject/graphing/number_line.py +123 -65
  56. manim/mobject/graphing/probability.py +88 -62
  57. manim/mobject/graphing/scale.py +33 -19
  58. manim/mobject/logo.py +118 -28
  59. manim/mobject/matrix.py +87 -83
  60. manim/mobject/mobject.py +912 -442
  61. manim/mobject/opengl/dot_cloud.py +16 -5
  62. manim/mobject/opengl/opengl_compatibility.py +4 -2
  63. manim/mobject/opengl/opengl_geometry.py +254 -153
  64. manim/mobject/opengl/opengl_image_mobject.py +3 -1
  65. manim/mobject/opengl/opengl_mobject.py +779 -482
  66. manim/mobject/opengl/opengl_point_cloud_mobject.py +41 -14
  67. manim/mobject/opengl/opengl_surface.py +14 -92
  68. manim/mobject/opengl/opengl_three_dimensions.py +12 -8
  69. manim/mobject/opengl/opengl_vectorized_mobject.py +98 -100
  70. manim/mobject/svg/brace.py +173 -41
  71. manim/mobject/svg/svg_mobject.py +139 -53
  72. manim/mobject/table.py +61 -68
  73. manim/mobject/text/code_mobject.py +193 -539
  74. manim/mobject/text/numbers.py +81 -34
  75. manim/mobject/text/tex_mobject.py +130 -78
  76. manim/mobject/text/text_mobject.py +288 -164
  77. manim/mobject/three_d/polyhedra.py +111 -13
  78. manim/mobject/three_d/three_d_utils.py +17 -8
  79. manim/mobject/three_d/three_dimensions.py +239 -106
  80. manim/mobject/types/image_mobject.py +50 -30
  81. manim/mobject/types/point_cloud_mobject.py +120 -75
  82. manim/mobject/types/vectorized_mobject.py +841 -408
  83. manim/mobject/value_tracker.py +105 -38
  84. manim/mobject/vector_field.py +50 -31
  85. manim/opengl/__init__.py +3 -3
  86. manim/plugins/__init__.py +14 -1
  87. manim/plugins/plugins_flags.py +10 -14
  88. manim/renderer/cairo_renderer.py +65 -50
  89. manim/renderer/opengl_renderer.py +89 -69
  90. manim/renderer/opengl_renderer_window.py +39 -18
  91. manim/renderer/shader.py +123 -87
  92. manim/renderer/shader_wrapper.py +44 -28
  93. manim/renderer/vectorized_mobject_rendering.py +38 -10
  94. manim/scene/moving_camera_scene.py +32 -3
  95. manim/scene/scene.py +507 -242
  96. manim/scene/scene_file_writer.py +371 -220
  97. manim/scene/section.py +20 -16
  98. manim/scene/three_d_scene.py +14 -22
  99. manim/scene/vector_space_scene.py +223 -129
  100. manim/scene/zoomed_scene.py +46 -41
  101. manim/typing.py +990 -0
  102. manim/utils/bezier.py +1823 -371
  103. manim/utils/caching.py +12 -5
  104. manim/utils/color/AS2700.py +236 -0
  105. manim/utils/color/BS381.py +318 -0
  106. manim/utils/color/DVIPSNAMES.py +96 -0
  107. manim/utils/color/SVGNAMES.py +179 -0
  108. manim/utils/color/X11.py +533 -0
  109. manim/utils/color/XKCD.py +952 -0
  110. manim/utils/color/__init__.py +61 -0
  111. manim/utils/color/core.py +1667 -0
  112. manim/utils/color/manim_colors.py +218 -0
  113. manim/utils/commands.py +48 -20
  114. manim/utils/config_ops.py +39 -19
  115. manim/utils/debug.py +8 -7
  116. manim/utils/deprecation.py +86 -39
  117. manim/utils/docbuild/__init__.py +17 -0
  118. manim/utils/docbuild/autoaliasattr_directive.py +236 -0
  119. manim/utils/docbuild/autocolor_directive.py +99 -0
  120. manim/utils/docbuild/manim_directive.py +94 -41
  121. manim/utils/docbuild/module_parsing.py +245 -0
  122. manim/utils/exceptions.py +6 -0
  123. manim/utils/family.py +5 -3
  124. manim/utils/family_ops.py +17 -4
  125. manim/utils/file_ops.py +27 -17
  126. manim/utils/hashing.py +55 -45
  127. manim/utils/images.py +13 -7
  128. manim/utils/ipython_magic.py +13 -7
  129. manim/utils/iterables.py +163 -120
  130. manim/utils/module_ops.py +66 -24
  131. manim/utils/opengl.py +77 -24
  132. manim/utils/parameter_parsing.py +32 -0
  133. manim/utils/paths.py +30 -33
  134. manim/utils/polylabel.py +235 -0
  135. manim/utils/qhull.py +218 -0
  136. manim/utils/rate_functions.py +98 -32
  137. manim/utils/simple_functions.py +25 -33
  138. manim/utils/sounds.py +7 -1
  139. manim/utils/space_ops.py +188 -115
  140. manim/utils/testing/__init__.py +17 -0
  141. manim/utils/testing/_frames_testers.py +13 -8
  142. manim/utils/testing/_show_diff.py +5 -3
  143. manim/utils/testing/_test_class_makers.py +34 -18
  144. manim/utils/testing/frames_comparison.py +37 -19
  145. manim/utils/tex.py +130 -198
  146. manim/utils/tex_file_writing.py +77 -47
  147. manim/utils/tex_templates.py +2 -1
  148. manim/utils/unit.py +6 -5
  149. {manim-0.17.0.dist-info → manim-0.19.1.dist-info}/METADATA +64 -65
  150. manim-0.19.1.dist-info/RECORD +220 -0
  151. {manim-0.17.0.dist-info → manim-0.19.1.dist-info}/WHEEL +1 -1
  152. manim-0.19.1.dist-info/entry_points.txt +3 -0
  153. {manim-0.17.0.dist-info → manim-0.19.1.dist-info/licenses}/LICENSE.community +1 -1
  154. manim/cli/new/group.py +0 -189
  155. manim/communitycolors.py +0 -9
  156. manim/gui/__init__.py +0 -0
  157. manim/gui/gui.py +0 -82
  158. manim/plugins/import_plugins.py +0 -43
  159. manim/utils/color.py +0 -552
  160. manim-0.17.0.dist-info/RECORD +0 -206
  161. manim-0.17.0.dist-info/entry_points.txt +0 -4
  162. /manim/cli/{new → checkhealth}/__init__.py +0 -0
  163. {manim-0.17.0.dist-info → manim-0.19.1.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,218 @@
1
+ """Colors included in the global name space.
2
+
3
+ These colors form Manim's default color space.
4
+
5
+ .. manim:: ColorsOverview
6
+ :save_last_frame:
7
+ :hide_source:
8
+
9
+ import manim.utils.color.manim_colors as Colors
10
+
11
+ class ColorsOverview(Scene):
12
+ def construct(self):
13
+ def color_group(color):
14
+ group = VGroup(
15
+ *[
16
+ Line(ORIGIN, RIGHT * 1.5, stroke_width=35, color=getattr(Colors, name.upper()))
17
+ for name in subnames(color)
18
+ ]
19
+ ).arrange_submobjects(buff=0.4, direction=DOWN)
20
+
21
+ name = Text(color).scale(0.6).next_to(group, UP, buff=0.3)
22
+ if any(decender in color for decender in "gjpqy"):
23
+ name.shift(DOWN * 0.08)
24
+ group.add(name)
25
+ return group
26
+
27
+ def subnames(name):
28
+ return [name + "_" + char for char in "abcde"]
29
+
30
+ color_groups = VGroup(
31
+ *[
32
+ color_group(color)
33
+ for color in [
34
+ "blue",
35
+ "teal",
36
+ "green",
37
+ "yellow",
38
+ "gold",
39
+ "red",
40
+ "maroon",
41
+ "purple",
42
+ ]
43
+ ]
44
+ ).arrange_submobjects(buff=0.2, aligned_edge=DOWN)
45
+
46
+ for line, char in zip(color_groups[0], "abcde"):
47
+ color_groups.add(Text(char).scale(0.6).next_to(line, LEFT, buff=0.2))
48
+
49
+ def named_lines_group(length, color_names, labels, align_to_block):
50
+ colors = [getattr(Colors, color.upper()) for color in color_names]
51
+ lines = VGroup(
52
+ *[
53
+ Line(
54
+ ORIGIN,
55
+ RIGHT * length,
56
+ stroke_width=55,
57
+ color=color,
58
+ )
59
+ for color in colors
60
+ ]
61
+ ).arrange_submobjects(buff=0.6, direction=DOWN)
62
+
63
+ for line, name, color in zip(lines, labels, colors):
64
+ line.add(Text(name, color=color.contrasting()).scale(0.6).move_to(line))
65
+ lines.next_to(color_groups, DOWN, buff=0.5).align_to(
66
+ color_groups[align_to_block], LEFT
67
+ )
68
+ return lines
69
+
70
+ other_colors = (
71
+ "pink",
72
+ "light_pink",
73
+ "orange",
74
+ "light_brown",
75
+ "dark_brown",
76
+ "gray_brown",
77
+ )
78
+
79
+ other_lines = named_lines_group(
80
+ 3.2,
81
+ other_colors,
82
+ other_colors,
83
+ 0,
84
+ )
85
+
86
+ gray_lines = named_lines_group(
87
+ 6.6,
88
+ ["white"] + subnames("gray") + ["black"],
89
+ [
90
+ "white",
91
+ "lighter_gray / gray_a",
92
+ "light_gray / gray_b",
93
+ "gray / gray_c",
94
+ "dark_gray / gray_d",
95
+ "darker_gray / gray_e",
96
+ "black",
97
+ ],
98
+ 2,
99
+ )
100
+
101
+ pure_colors = (
102
+ "pure_red",
103
+ "pure_green",
104
+ "pure_blue",
105
+ )
106
+
107
+ pure_lines = named_lines_group(
108
+ 3.2,
109
+ pure_colors,
110
+ pure_colors,
111
+ 6,
112
+ )
113
+
114
+ self.add(color_groups, other_lines, gray_lines, pure_lines)
115
+
116
+ VGroup(*self.mobjects).move_to(ORIGIN)
117
+
118
+ .. automanimcolormodule:: manim.utils.color.manim_colors
119
+
120
+ """
121
+
122
+ from __future__ import annotations
123
+
124
+ from .core import ManimColor
125
+
126
+ WHITE = ManimColor("#FFFFFF")
127
+ GRAY_A = ManimColor("#DDDDDD")
128
+ GREY_A = ManimColor("#DDDDDD")
129
+ GRAY_B = ManimColor("#BBBBBB")
130
+ GREY_B = ManimColor("#BBBBBB")
131
+ GRAY_C = ManimColor("#888888")
132
+ GREY_C = ManimColor("#888888")
133
+ GRAY_D = ManimColor("#444444")
134
+ GREY_D = ManimColor("#444444")
135
+ GRAY_E = ManimColor("#222222")
136
+ GREY_E = ManimColor("#222222")
137
+ BLACK = ManimColor("#000000")
138
+ LIGHTER_GRAY = ManimColor("#DDDDDD")
139
+ LIGHTER_GREY = ManimColor("#DDDDDD")
140
+ LIGHT_GRAY = ManimColor("#BBBBBB")
141
+ LIGHT_GREY = ManimColor("#BBBBBB")
142
+ GRAY = ManimColor("#888888")
143
+ GREY = ManimColor("#888888")
144
+ DARK_GRAY = ManimColor("#444444")
145
+ DARK_GREY = ManimColor("#444444")
146
+ DARKER_GRAY = ManimColor("#222222")
147
+ DARKER_GREY = ManimColor("#222222")
148
+ BLUE_A = ManimColor("#C7E9F1")
149
+ BLUE_B = ManimColor("#9CDCEB")
150
+ BLUE_C = ManimColor("#58C4DD")
151
+ BLUE_D = ManimColor("#29ABCA")
152
+ BLUE_E = ManimColor("#236B8E")
153
+ PURE_BLUE = ManimColor("#0000FF")
154
+ BLUE = ManimColor("#58C4DD")
155
+ DARK_BLUE = ManimColor("#236B8E")
156
+ TEAL_A = ManimColor("#ACEAD7")
157
+ TEAL_B = ManimColor("#76DDC0")
158
+ TEAL_C = ManimColor("#5CD0B3")
159
+ TEAL_D = ManimColor("#55C1A7")
160
+ TEAL_E = ManimColor("#49A88F")
161
+ TEAL = ManimColor("#5CD0B3")
162
+ GREEN_A = ManimColor("#C9E2AE")
163
+ GREEN_B = ManimColor("#A6CF8C")
164
+ GREEN_C = ManimColor("#83C167")
165
+ GREEN_D = ManimColor("#77B05D")
166
+ GREEN_E = ManimColor("#699C52")
167
+ PURE_GREEN = ManimColor("#00FF00")
168
+ GREEN = ManimColor("#83C167")
169
+ YELLOW_A = ManimColor("#FFF1B6")
170
+ YELLOW_B = ManimColor("#FFEA94")
171
+ YELLOW_C = ManimColor("#FFFF00")
172
+ YELLOW_D = ManimColor("#F4D345")
173
+ YELLOW_E = ManimColor("#E8C11C")
174
+ YELLOW = ManimColor("#FFFF00")
175
+ GOLD_A = ManimColor("#F7C797")
176
+ GOLD_B = ManimColor("#F9B775")
177
+ GOLD_C = ManimColor("#F0AC5F")
178
+ GOLD_D = ManimColor("#E1A158")
179
+ GOLD_E = ManimColor("#C78D46")
180
+ GOLD = ManimColor("#F0AC5F")
181
+ RED_A = ManimColor("#F7A1A3")
182
+ RED_B = ManimColor("#FF8080")
183
+ RED_C = ManimColor("#FC6255")
184
+ RED_D = ManimColor("#E65A4C")
185
+ RED_E = ManimColor("#CF5044")
186
+ PURE_RED = ManimColor("#FF0000")
187
+ RED = ManimColor("#FC6255")
188
+ MAROON_A = ManimColor("#ECABC1")
189
+ MAROON_B = ManimColor("#EC92AB")
190
+ MAROON_C = ManimColor("#C55F73")
191
+ MAROON_D = ManimColor("#A24D61")
192
+ MAROON_E = ManimColor("#94424F")
193
+ MAROON = ManimColor("#C55F73")
194
+ PURPLE_A = ManimColor("#CAA3E8")
195
+ PURPLE_B = ManimColor("#B189C6")
196
+ PURPLE_C = ManimColor("#9A72AC")
197
+ PURPLE_D = ManimColor("#715582")
198
+ PURPLE_E = ManimColor("#644172")
199
+ PURPLE = ManimColor("#9A72AC")
200
+ PINK = ManimColor("#D147BD")
201
+ LIGHT_PINK = ManimColor("#DC75CD")
202
+ ORANGE = ManimColor("#FF862F")
203
+ LIGHT_BROWN = ManimColor("#CD853F")
204
+ DARK_BROWN = ManimColor("#8B4513")
205
+ GRAY_BROWN = ManimColor("#736357")
206
+ GREY_BROWN = ManimColor("#736357")
207
+
208
+ # Colors used for Manim Community's logo and banner
209
+
210
+ LOGO_WHITE = ManimColor("#ECE7E2")
211
+ LOGO_GREEN = ManimColor("#87C2A5")
212
+ LOGO_BLUE = ManimColor("#525893")
213
+ LOGO_RED = ManimColor("#E07A5F")
214
+ LOGO_BLACK = ManimColor("#343434")
215
+
216
+ _all_manim_colors: list[ManimColor] = [
217
+ x for x in globals().values() if isinstance(x, ManimColor)
218
+ ]
manim/utils/commands.py CHANGED
@@ -1,10 +1,14 @@
1
1
  from __future__ import annotations
2
2
 
3
- import json
4
3
  import os
4
+ from collections.abc import Generator
5
5
  from pathlib import Path
6
6
  from subprocess import run
7
- from typing import Generator
7
+ from typing import TypedDict
8
+
9
+ import av
10
+
11
+ from manim.typing import StrOrBytesPath
8
12
 
9
13
  __all__ = [
10
14
  "capture",
@@ -13,28 +17,52 @@ __all__ = [
13
17
  ]
14
18
 
15
19
 
16
- def capture(command, cwd=None, command_input=None):
17
- p = run(command, cwd=cwd, input=command_input, capture_output=True, text=True)
20
+ def capture(
21
+ command: str, cwd: StrOrBytesPath | None = None, command_input: str | None = None
22
+ ) -> tuple[str, str, int]:
23
+ p = run(
24
+ command,
25
+ cwd=cwd,
26
+ input=command_input,
27
+ capture_output=True,
28
+ text=True,
29
+ encoding="utf-8",
30
+ )
18
31
  out, err = p.stdout, p.stderr
19
32
  return out, err, p.returncode
20
33
 
21
34
 
22
- def get_video_metadata(path_to_video: str | os.PathLike) -> dict[str]:
23
- command = [
24
- "ffprobe",
25
- "-v",
26
- "error",
27
- "-select_streams",
28
- "v:0",
29
- "-show_entries",
30
- "stream=width,height,nb_frames,duration,avg_frame_rate,codec_name",
31
- "-print_format",
32
- "json",
33
- str(path_to_video),
34
- ]
35
- config, err, exitcode = capture(command)
36
- assert exitcode == 0, f"FFprobe error: {err}"
37
- return json.loads(config)["streams"][0]
35
+ class VideoMetadata(TypedDict):
36
+ width: int
37
+ height: int
38
+ nb_frames: str
39
+ duration: str
40
+ avg_frame_rate: str
41
+ codec_name: str
42
+ pix_fmt: str
43
+
44
+
45
+ def get_video_metadata(path_to_video: str | os.PathLike) -> VideoMetadata:
46
+ with av.open(str(path_to_video)) as container:
47
+ stream = container.streams.video[0]
48
+ ctxt = stream.codec_context
49
+ rate = stream.average_rate
50
+ if stream.duration is not None:
51
+ duration = float(stream.duration * stream.time_base)
52
+ num_frames = stream.frames
53
+ else:
54
+ num_frames = sum(1 for _ in container.decode(video=0))
55
+ duration = float(num_frames / stream.base_rate)
56
+
57
+ return {
58
+ "width": ctxt.width,
59
+ "height": ctxt.height,
60
+ "nb_frames": str(num_frames),
61
+ "duration": f"{duration:.6f}",
62
+ "avg_frame_rate": f"{rate.numerator}/{rate.denominator}", # Can be a Fraction
63
+ "codec_name": stream.codec_context.name,
64
+ "pix_fmt": stream.codec_context.pix_fmt,
65
+ }
38
66
 
39
67
 
40
68
  def get_dir_layout(dirpath: Path) -> Generator[str, None, None]:
manim/utils/config_ops.py CHANGED
@@ -10,11 +10,13 @@ __all__ = [
10
10
 
11
11
 
12
12
  import itertools as it
13
+ from typing import Any, Generic, Protocol, cast
13
14
 
14
- import numpy as np
15
+ import numpy.typing as npt
16
+ from typing_extensions import TypeVar
15
17
 
16
18
 
17
- def merge_dicts_recursively(*dicts):
19
+ def merge_dicts_recursively(*dicts: dict[Any, Any]) -> dict[Any, Any]:
18
20
  """
19
21
  Creates a dict whose keyset is the union of all the
20
22
  input dictionaries. The value for each key is based
@@ -24,7 +26,7 @@ def merge_dicts_recursively(*dicts):
24
26
 
25
27
  When values are dictionaries, it is applied recursively
26
28
  """
27
- result = {}
29
+ result: dict = {}
28
30
  all_items = it.chain(*(d.items() for d in dicts))
29
31
  for key, value in all_items:
30
32
  if key in result and isinstance(result[key], dict) and isinstance(value, dict):
@@ -34,7 +36,9 @@ def merge_dicts_recursively(*dicts):
34
36
  return result
35
37
 
36
38
 
37
- def update_dict_recursively(current_dict, *others):
39
+ def update_dict_recursively(
40
+ current_dict: dict[Any, Any], *others: dict[Any, Any]
41
+ ) -> None:
38
42
  updated_dict = merge_dicts_recursively(current_dict, *others)
39
43
  current_dict.update(updated_dict)
40
44
 
@@ -44,35 +48,51 @@ def update_dict_recursively(current_dict, *others):
44
48
 
45
49
 
46
50
  class DictAsObject:
47
- def __init__(self, dictin):
51
+ def __init__(self, dictin: dict[str, Any]):
48
52
  self.__dict__ = dictin
49
53
 
50
54
 
51
- class _Data:
55
+ _Data_T = TypeVar("_Data_T", bound="npt.NDArray[Any]", default="npt.NDArray[Any]")
56
+
57
+
58
+ class _HasData(Protocol):
59
+ data: dict[str, npt.NDArray[Any]]
60
+
61
+
62
+ class _Data(Generic[_Data_T]):
52
63
  """Descriptor that allows _Data variables to be grouped and accessed from self.data["attr"] via self.attr.
53
64
  self.data attributes must be arrays.
54
65
  """
55
66
 
56
- def __set_name__(self, obj, name):
57
- self.name = name
67
+ def __set_name__(self, obj: _HasData, name: str) -> None:
68
+ self.name: str = name
58
69
 
59
- def __get__(self, obj, owner):
60
- return obj.data[self.name]
70
+ def __get__(self, obj: _HasData, owner: Any) -> _Data_T:
71
+ value = cast(_Data_T, obj.data[self.name])
72
+ return value
61
73
 
62
- def __set__(self, obj, array: np.ndarray):
74
+ def __set__(self, obj: _HasData, array: _Data_T) -> None:
63
75
  obj.data[self.name] = array
64
76
 
65
77
 
66
- class _Uniforms:
78
+ _Uniforms_T = TypeVar("_Uniforms_T", bound="float | tuple[float, ...]", default=float)
79
+
80
+
81
+ class _HasUniforms(Protocol):
82
+ uniforms: dict[str, float | tuple[float, ...]]
83
+
84
+
85
+ class _Uniforms(Generic[_Uniforms_T]):
67
86
  """Descriptor that allows _Uniforms variables to be grouped from self.uniforms["attr"] via self.attr.
68
- self.uniforms attributes must be floats.
87
+ self.uniforms attributes must be floats or tuples of floats.
69
88
  """
70
89
 
71
- def __set_name__(self, obj, name):
72
- self.name = name
90
+ def __set_name__(self, obj: _HasUniforms, name: str) -> None:
91
+ self.name: str = name
73
92
 
74
- def __get__(self, obj, owner):
75
- return obj.__dict__["uniforms"][self.name]
93
+ def __get__(self, obj: _HasUniforms, owner: Any) -> _Uniforms_T:
94
+ val = cast(_Uniforms_T, obj.uniforms[self.name])
95
+ return val
76
96
 
77
- def __set__(self, obj, num: float):
78
- obj.__dict__["uniforms"][self.name] = num
97
+ def __set__(self, obj: _HasUniforms, num: _Uniforms_T) -> None:
98
+ obj.uniforms[self.name] = num
manim/utils/debug.py CHANGED
@@ -1,19 +1,21 @@
1
1
  """Debugging utilities."""
2
2
 
3
-
4
3
  from __future__ import annotations
5
4
 
6
5
  __all__ = ["print_family", "index_labels"]
7
6
 
8
7
 
8
+ from typing import Any
9
+
9
10
  from manim.mobject.mobject import Mobject
10
11
  from manim.mobject.text.numbers import Integer
12
+ from manim.utils.color import ManimColor
11
13
 
12
14
  from ..mobject.types.vectorized_mobject import VGroup
13
15
  from .color import BLACK
14
16
 
15
17
 
16
- def print_family(mobject, n_tabs=0):
18
+ def print_family(mobject: Mobject, n_tabs: int = 0) -> None:
17
19
  """For debugging purposes"""
18
20
  print("\t" * n_tabs, mobject, id(mobject))
19
21
  for submob in mobject.submobjects:
@@ -23,10 +25,10 @@ def print_family(mobject, n_tabs=0):
23
25
  def index_labels(
24
26
  mobject: Mobject,
25
27
  label_height: float = 0.15,
26
- background_stroke_width=5,
27
- background_stroke_color=BLACK,
28
- **kwargs,
29
- ):
28
+ background_stroke_width: float = 5,
29
+ background_stroke_color: ManimColor = BLACK,
30
+ **kwargs: Any,
31
+ ) -> VGroup:
30
32
  r"""Returns a :class:`~.VGroup` of :class:`~.Integer` mobjects
31
33
  that shows the index of each submobject.
32
34
 
@@ -68,7 +70,6 @@ def index_labels(
68
70
 
69
71
  self.add(text, indices)
70
72
  """
71
-
72
73
  labels = VGroup()
73
74
  for n, submob in enumerate(mobject):
74
75
  label = Integer(n, **kwargs)