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

Files changed (129) hide show
  1. manim/__main__.py +45 -12
  2. manim/_config/__init__.py +2 -2
  3. manim/_config/cli_colors.py +8 -4
  4. manim/_config/default.cfg +0 -2
  5. manim/_config/logger_utils.py +5 -0
  6. manim/_config/utils.py +29 -38
  7. manim/animation/animation.py +148 -8
  8. manim/animation/composition.py +16 -13
  9. manim/animation/creation.py +184 -8
  10. manim/animation/fading.py +5 -8
  11. manim/animation/indication.py +93 -26
  12. manim/animation/movement.py +21 -3
  13. manim/animation/rotation.py +2 -1
  14. manim/animation/specialized.py +3 -5
  15. manim/animation/speedmodifier.py +3 -3
  16. manim/animation/transform.py +4 -5
  17. manim/animation/updaters/mobject_update_utils.py +17 -14
  18. manim/camera/camera.py +2 -2
  19. manim/cli/__init__.py +17 -0
  20. manim/cli/cfg/group.py +52 -36
  21. manim/cli/checkhealth/checks.py +92 -76
  22. manim/cli/checkhealth/commands.py +12 -5
  23. manim/cli/default_group.py +148 -24
  24. manim/cli/init/commands.py +28 -23
  25. manim/cli/plugins/commands.py +13 -3
  26. manim/cli/render/commands.py +47 -42
  27. manim/cli/render/global_options.py +43 -9
  28. manim/cli/render/render_options.py +84 -19
  29. manim/constants.py +11 -4
  30. manim/mobject/frame.py +0 -1
  31. manim/mobject/geometry/arc.py +109 -75
  32. manim/mobject/geometry/boolean_ops.py +20 -17
  33. manim/mobject/geometry/labeled.py +300 -77
  34. manim/mobject/geometry/line.py +120 -60
  35. manim/mobject/geometry/polygram.py +109 -25
  36. manim/mobject/geometry/shape_matchers.py +35 -15
  37. manim/mobject/geometry/tips.py +36 -27
  38. manim/mobject/graph.py +48 -40
  39. manim/mobject/graphing/coordinate_systems.py +110 -45
  40. manim/mobject/graphing/functions.py +16 -10
  41. manim/mobject/graphing/number_line.py +23 -9
  42. manim/mobject/graphing/probability.py +2 -10
  43. manim/mobject/graphing/scale.py +6 -5
  44. manim/mobject/matrix.py +17 -19
  45. manim/mobject/mobject.py +149 -103
  46. manim/mobject/opengl/opengl_geometry.py +4 -8
  47. manim/mobject/opengl/opengl_mobject.py +506 -343
  48. manim/mobject/opengl/opengl_point_cloud_mobject.py +3 -7
  49. manim/mobject/opengl/opengl_surface.py +1 -2
  50. manim/mobject/opengl/opengl_vectorized_mobject.py +27 -65
  51. manim/mobject/svg/brace.py +61 -13
  52. manim/mobject/svg/svg_mobject.py +2 -1
  53. manim/mobject/table.py +11 -12
  54. manim/mobject/text/code_mobject.py +186 -550
  55. manim/mobject/text/numbers.py +7 -7
  56. manim/mobject/text/tex_mobject.py +22 -13
  57. manim/mobject/text/text_mobject.py +29 -20
  58. manim/mobject/three_d/polyhedra.py +98 -1
  59. manim/mobject/three_d/three_dimensions.py +59 -31
  60. manim/mobject/types/image_mobject.py +37 -23
  61. manim/mobject/types/point_cloud_mobject.py +103 -67
  62. manim/mobject/types/vectorized_mobject.py +387 -214
  63. manim/mobject/value_tracker.py +2 -1
  64. manim/mobject/vector_field.py +2 -4
  65. manim/opengl/__init__.py +3 -3
  66. manim/plugins/__init__.py +2 -3
  67. manim/plugins/plugins_flags.py +3 -3
  68. manim/renderer/cairo_renderer.py +11 -11
  69. manim/renderer/opengl_renderer.py +19 -20
  70. manim/renderer/shader.py +2 -3
  71. manim/renderer/shader_wrapper.py +3 -2
  72. manim/scene/moving_camera_scene.py +23 -0
  73. manim/scene/scene.py +72 -41
  74. manim/scene/scene_file_writer.py +313 -164
  75. manim/scene/section.py +15 -15
  76. manim/scene/three_d_scene.py +8 -15
  77. manim/scene/vector_space_scene.py +3 -6
  78. manim/typing.py +326 -66
  79. manim/utils/bezier.py +1658 -381
  80. manim/utils/caching.py +11 -5
  81. manim/utils/color/AS2700.py +2 -0
  82. manim/utils/color/BS381.py +2 -0
  83. manim/utils/color/DVIPSNAMES.py +96 -0
  84. manim/utils/color/SVGNAMES.py +179 -0
  85. manim/utils/color/X11.py +3 -0
  86. manim/utils/color/XKCD.py +2 -0
  87. manim/utils/color/__init__.py +8 -5
  88. manim/utils/color/core.py +818 -301
  89. manim/utils/color/manim_colors.py +7 -9
  90. manim/utils/commands.py +40 -19
  91. manim/utils/config_ops.py +18 -13
  92. manim/utils/debug.py +8 -6
  93. manim/utils/deprecation.py +92 -43
  94. manim/utils/docbuild/autoaliasattr_directive.py +45 -8
  95. manim/utils/docbuild/autocolor_directive.py +12 -13
  96. manim/utils/docbuild/manim_directive.py +35 -29
  97. manim/utils/docbuild/module_parsing.py +74 -27
  98. manim/utils/family.py +3 -3
  99. manim/utils/family_ops.py +12 -4
  100. manim/utils/file_ops.py +22 -16
  101. manim/utils/hashing.py +7 -7
  102. manim/utils/images.py +10 -4
  103. manim/utils/ipython_magic.py +12 -8
  104. manim/utils/iterables.py +161 -119
  105. manim/utils/module_ops.py +55 -19
  106. manim/utils/opengl.py +68 -23
  107. manim/utils/parameter_parsing.py +3 -2
  108. manim/utils/paths.py +11 -5
  109. manim/utils/polylabel.py +168 -0
  110. manim/utils/qhull.py +218 -0
  111. manim/utils/rate_functions.py +69 -32
  112. manim/utils/simple_functions.py +24 -15
  113. manim/utils/sounds.py +7 -1
  114. manim/utils/space_ops.py +48 -37
  115. manim/utils/testing/_frames_testers.py +13 -8
  116. manim/utils/testing/_show_diff.py +5 -3
  117. manim/utils/testing/_test_class_makers.py +33 -18
  118. manim/utils/testing/frames_comparison.py +20 -14
  119. manim/utils/tex.py +4 -2
  120. manim/utils/tex_file_writing.py +45 -45
  121. manim/utils/tex_templates.py +1 -1
  122. manim/utils/unit.py +6 -5
  123. {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/METADATA +16 -9
  124. manim-0.19.0.dist-info/RECORD +221 -0
  125. {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/WHEEL +1 -1
  126. manim-0.18.1.dist-info/RECORD +0 -217
  127. {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/LICENSE +0 -0
  128. {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/LICENSE.community +0 -0
  129. {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/entry_points.txt +0 -0
@@ -1,9 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Callable
3
+ from typing import Any, Callable
4
4
 
5
+ from manim.renderer.cairo_renderer import CairoRenderer
6
+ from manim.renderer.opengl_renderer import OpenGLRenderer
5
7
  from manim.scene.scene import Scene
6
8
  from manim.scene.scene_file_writer import SceneFileWriter
9
+ from manim.typing import PixelArray, StrPath
7
10
 
8
11
  from ._frames_testers import _FramesTester
9
12
 
@@ -11,13 +14,14 @@ from ._frames_testers import _FramesTester
11
14
  def _make_test_scene_class(
12
15
  base_scene: type[Scene],
13
16
  construct_test: Callable[[Scene], None],
14
- test_renderer,
17
+ test_renderer: CairoRenderer | OpenGLRenderer | None,
15
18
  ) -> type[Scene]:
16
- class _TestedScene(base_scene):
17
- def __init__(self, *args, **kwargs):
18
- super().__init__(renderer=test_renderer, *args, **kwargs)
19
+ # TODO: Get the type annotation right for the base_scene argument.
20
+ class _TestedScene(base_scene): # type: ignore[valid-type, misc]
21
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
22
+ super().__init__(*args, renderer=test_renderer, **kwargs)
19
23
 
20
- def construct(self):
24
+ def construct(self) -> None:
21
25
  construct_test(self)
22
26
 
23
27
  # Manim hack to render the very last frame (normally the last frame is not the very end of the animation)
@@ -28,7 +32,7 @@ def _make_test_scene_class(
28
32
  return _TestedScene
29
33
 
30
34
 
31
- def _make_test_renderer_class(from_renderer):
35
+ def _make_test_renderer_class(from_renderer: type) -> Any:
32
36
  # Just for inheritance.
33
37
  class _TestRenderer(from_renderer):
34
38
  pass
@@ -39,39 +43,50 @@ def _make_test_renderer_class(from_renderer):
39
43
  class DummySceneFileWriter(SceneFileWriter):
40
44
  """Delegate of SceneFileWriter used to test the frames."""
41
45
 
42
- def __init__(self, renderer, scene_name, **kwargs):
46
+ def __init__(
47
+ self,
48
+ renderer: CairoRenderer | OpenGLRenderer,
49
+ scene_name: StrPath,
50
+ **kwargs: Any,
51
+ ) -> None:
43
52
  super().__init__(renderer, scene_name, **kwargs)
44
53
  self.i = 0
45
54
 
46
- def init_output_directories(self, scene_name):
55
+ def init_output_directories(self, scene_name: StrPath) -> None:
47
56
  pass
48
57
 
49
- def add_partial_movie_file(self, hash_animation):
58
+ def add_partial_movie_file(self, hash_animation: str) -> None:
50
59
  pass
51
60
 
52
- def begin_animation(self, allow_write=True):
61
+ def begin_animation(
62
+ self, allow_write: bool = True, file_path: StrPath | None = None
63
+ ) -> Any:
53
64
  pass
54
65
 
55
- def end_animation(self, allow_write):
66
+ def end_animation(self, allow_write: bool = False) -> None:
56
67
  pass
57
68
 
58
- def combine_to_movie(self):
69
+ def combine_to_movie(self) -> None:
59
70
  pass
60
71
 
61
- def combine_to_section_videos(self):
72
+ def combine_to_section_videos(self) -> None:
62
73
  pass
63
74
 
64
- def clean_cache(self):
75
+ def clean_cache(self) -> None:
65
76
  pass
66
77
 
67
- def write_frame(self, frame_or_renderer):
78
+ def write_frame(
79
+ self, frame_or_renderer: PixelArray | OpenGLRenderer, num_frames: int = 1
80
+ ) -> None:
68
81
  self.i += 1
69
82
 
70
83
 
71
84
  def _make_scene_file_writer_class(tester: _FramesTester) -> type[SceneFileWriter]:
72
85
  class TestSceneFileWriter(DummySceneFileWriter):
73
- def write_frame(self, frame_or_renderer):
86
+ def write_frame(
87
+ self, frame_or_renderer: PixelArray | OpenGLRenderer, num_frames: int = 1
88
+ ) -> None:
74
89
  tester.check_frame(self.i, frame_or_renderer)
75
- super().write_frame(frame_or_renderer)
90
+ super().write_frame(frame_or_renderer, num_frames=num_frames)
76
91
 
77
92
  return TestSceneFileWriter
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  import functools
4
4
  import inspect
5
5
  from pathlib import Path
6
- from typing import Callable
6
+ from typing import Any, Callable
7
7
 
8
8
  import cairo
9
9
  import pytest
@@ -14,7 +14,9 @@ from manim._config import tempconfig
14
14
  from manim._config.utils import ManimConfig
15
15
  from manim.camera.three_d_camera import ThreeDCamera
16
16
  from manim.renderer.cairo_renderer import CairoRenderer
17
+ from manim.renderer.opengl_renderer import OpenGLRenderer
17
18
  from manim.scene.three_d_scene import ThreeDScene
19
+ from manim.typing import StrPath
18
20
 
19
21
  from ._frames_testers import _ControlDataWriter, _FramesTester
20
22
  from ._test_class_makers import (
@@ -31,13 +33,13 @@ MIN_CAIRO_VERSION = 11800
31
33
 
32
34
 
33
35
  def frames_comparison(
34
- func=None,
36
+ func: Callable | None = None,
35
37
  *,
36
38
  last_frame: bool = True,
37
- renderer_class=CairoRenderer,
38
- base_scene=Scene,
39
- **custom_config,
40
- ):
39
+ renderer_class: type[CairoRenderer | OpenGLRenderer] = CairoRenderer,
40
+ base_scene: type[Scene] = Scene,
41
+ **custom_config: Any,
42
+ ) -> Callable:
41
43
  """Compares the frames generated by the test with control frames previously registered.
42
44
 
43
45
  If there is no control frames for this test, the test will fail. To generate
@@ -60,7 +62,7 @@ def frames_comparison(
60
62
  If the scene has a moving animation, then the test must set last_frame to False.
61
63
  """
62
64
 
63
- def decorator_maker(tested_scene_construct):
65
+ def decorator_maker(tested_scene_construct: Callable) -> Callable:
64
66
  if (
65
67
  SCENE_PARAMETER_NAME
66
68
  not in inspect.getfullargspec(tested_scene_construct).args
@@ -79,11 +81,14 @@ def frames_comparison(
79
81
  "There is no module test name indicated for the graphical unit test. You have to declare __module_test__ in the test file.",
80
82
  )
81
83
  module_name = tested_scene_construct.__globals__.get("__module_test__")
84
+ assert isinstance(module_name, str)
82
85
  test_name = tested_scene_construct.__name__[len("test_") :]
83
86
 
84
87
  @functools.wraps(tested_scene_construct)
85
88
  # The "request" parameter is meant to be used as a fixture by pytest. See below.
86
- def wrapper(*args, request: FixtureRequest, tmp_path, **kwargs):
89
+ def wrapper(
90
+ *args: Any, request: FixtureRequest, tmp_path: StrPath, **kwargs: Any
91
+ ) -> None:
87
92
  # check for cairo version
88
93
  if (
89
94
  renderer_class is CairoRenderer
@@ -146,13 +151,13 @@ def frames_comparison(
146
151
  inspect.Parameter("tmp_path", inspect.Parameter.KEYWORD_ONLY),
147
152
  ]
148
153
  new_sig = old_sig.replace(parameters=parameters)
149
- wrapper.__signature__ = new_sig
154
+ wrapper.__signature__ = new_sig # type: ignore[attr-defined]
150
155
 
151
156
  # Reach a bit into pytest internals to hoist the marks from our wrapped
152
157
  # function.
153
- setattr(wrapper, "pytestmark", [])
158
+ wrapper.pytestmark = [] # type: ignore[attr-defined]
154
159
  new_marks = getattr(tested_scene_construct, "pytestmark", [])
155
- wrapper.pytestmark = new_marks
160
+ wrapper.pytestmark = new_marks # type: ignore[attr-defined]
156
161
  return wrapper
157
162
 
158
163
  # Case where the decorator is called with and without parentheses.
@@ -192,9 +197,10 @@ def _make_test_comparing_frames(
192
197
  Callable[[], None]
193
198
  The pytest test.
194
199
  """
195
-
196
200
  if is_set_test_data_test:
197
- frames_tester = _ControlDataWriter(file_path, size_frame=size_frame)
201
+ frames_tester: _FramesTester = _ControlDataWriter(
202
+ file_path, size_frame=size_frame
203
+ )
198
204
  else:
199
205
  frames_tester = _FramesTester(file_path, show_diff=show_diff)
200
206
 
@@ -205,7 +211,7 @@ def _make_test_comparing_frames(
205
211
  )
206
212
  testRenderer = _make_test_renderer_class(renderer_class)
207
213
 
208
- def real_test():
214
+ def real_test() -> None:
209
215
  with frames_tester.testing():
210
216
  sceneTested = _make_test_scene_class(
211
217
  base_scene=base_scene,
manim/utils/tex.py CHANGED
@@ -36,6 +36,9 @@ class TexTemplate:
36
36
  tex_compiler: str = "latex"
37
37
  """The TeX compiler to be used, e.g. ``latex``, ``pdflatex`` or ``lualatex``."""
38
38
 
39
+ description: str = ""
40
+ """A description of the template"""
41
+
39
42
  output_format: str = ".dvi"
40
43
  """The output format resulting from compilation, e.g. ``.dvi`` or ``.pdf``."""
41
44
 
@@ -181,7 +184,6 @@ def _texcode_for_environment(environment: str) -> tuple[str, str]:
181
184
  A pair of strings representing the opening and closing of the tex environment, e.g.
182
185
  ``\begin{tabular}{cccl}`` and ``\end{tabular}``
183
186
  """
184
-
185
187
  environment.removeprefix(r"\begin").removeprefix("{")
186
188
 
187
189
  # The \begin command takes everything and closes with a brace
@@ -191,7 +193,7 @@ def _texcode_for_environment(environment: str) -> tuple[str, str]:
191
193
  begin += "}"
192
194
 
193
195
  # While the \end command terminates at the first closing brace
194
- split_at_brace = re.split("}", environment, 1)
196
+ split_at_brace = re.split("}", environment, maxsplit=1)
195
197
  end = r"\end{" + split_at_brace[0] + "}"
196
198
 
197
199
  return begin, end
@@ -9,11 +9,13 @@
9
9
  from __future__ import annotations
10
10
 
11
11
  import hashlib
12
- import os
13
12
  import re
13
+ import subprocess
14
14
  import unicodedata
15
+ from collections.abc import Generator, Iterable, Sequence
15
16
  from pathlib import Path
16
- from typing import Iterable
17
+ from re import Match
18
+ from typing import Any
17
19
 
18
20
  from manim.utils.tex import TexTemplate
19
21
 
@@ -22,7 +24,7 @@ from .. import config, logger
22
24
  __all__ = ["tex_to_svg_file"]
23
25
 
24
26
 
25
- def tex_hash(expression):
27
+ def tex_hash(expression: Any) -> str:
26
28
  id_str = str(expression)
27
29
  hasher = hashlib.sha256()
28
30
  hasher.update(id_str.encode())
@@ -34,8 +36,8 @@ def tex_to_svg_file(
34
36
  expression: str,
35
37
  environment: str | None = None,
36
38
  tex_template: TexTemplate | None = None,
37
- ):
38
- """Takes a tex expression and returns the svg version of the compiled tex
39
+ ) -> Path:
40
+ r"""Takes a tex expression and returns the svg version of the compiled tex
39
41
 
40
42
  Parameters
41
43
  ----------
@@ -76,7 +78,7 @@ def generate_tex_file(
76
78
  environment: str | None = None,
77
79
  tex_template: TexTemplate | None = None,
78
80
  ) -> Path:
79
- """Takes a tex expression (and an optional tex environment),
81
+ r"""Takes a tex expression (and an optional tex environment),
80
82
  and returns a fully formed tex file ready for compilation.
81
83
 
82
84
  Parameters
@@ -114,10 +116,11 @@ def generate_tex_file(
114
116
  return result
115
117
 
116
118
 
117
- def tex_compilation_command(
119
+ def make_tex_compilation_command(
118
120
  tex_compiler: str, output_format: str, tex_file: Path, tex_dir: Path
119
- ) -> str:
120
- """Prepares the tex compilation command with all necessary cli flags
121
+ ) -> list[str]:
122
+ """Prepares the TeX compilation command, i.e. the TeX compiler name
123
+ and all necessary CLI flags.
121
124
 
122
125
  Parameters
123
126
  ----------
@@ -132,50 +135,46 @@ def tex_compilation_command(
132
135
 
133
136
  Returns
134
137
  -------
135
- :class:`str`
138
+ :class:`list[str]`
136
139
  Compilation command according to given parameters
137
140
  """
138
141
  if tex_compiler in {"latex", "pdflatex", "luatex", "lualatex"}:
139
- commands = [
142
+ command = [
140
143
  tex_compiler,
141
144
  "-interaction=batchmode",
142
- f'-output-format="{output_format[1:]}"',
145
+ f"-output-format={output_format[1:]}",
143
146
  "-halt-on-error",
144
- f'-output-directory="{tex_dir.as_posix()}"',
145
- f'"{tex_file.as_posix()}"',
146
- ">",
147
- os.devnull,
147
+ f"-output-directory={tex_dir.as_posix()}",
148
+ f"{tex_file.as_posix()}",
148
149
  ]
149
150
  elif tex_compiler == "xelatex":
150
151
  if output_format == ".xdv":
151
- outflag = "-no-pdf"
152
+ outflag = ["-no-pdf"]
152
153
  elif output_format == ".pdf":
153
- outflag = ""
154
+ outflag = []
154
155
  else:
155
156
  raise ValueError("xelatex output is either pdf or xdv")
156
- commands = [
157
+ command = [
157
158
  "xelatex",
158
- outflag,
159
+ *outflag,
159
160
  "-interaction=batchmode",
160
161
  "-halt-on-error",
161
- f'-output-directory="{tex_dir.as_posix()}"',
162
- f'"{tex_file.as_posix()}"',
163
- ">",
164
- os.devnull,
162
+ f"-output-directory={tex_dir.as_posix()}",
163
+ f"{tex_file.as_posix()}",
165
164
  ]
166
165
  else:
167
166
  raise ValueError(f"Tex compiler {tex_compiler} unknown.")
168
- return " ".join(commands)
167
+ return command
169
168
 
170
169
 
171
- def insight_inputenc_error(matching):
170
+ def insight_inputenc_error(matching: Match[str]) -> Generator[str]:
172
171
  code_point = chr(int(matching[1], 16))
173
172
  name = unicodedata.name(code_point)
174
173
  yield f"TexTemplate does not support character '{name}' (U+{matching[1]})."
175
174
  yield "See the documentation for manim.mobject.svg.tex_mobject for details on using a custom TexTemplate."
176
175
 
177
176
 
178
- def insight_package_not_found_error(matching):
177
+ def insight_package_not_found_error(matching: Match[str]) -> Generator[str]:
179
178
  yield f"You do not have package {matching[1]} installed."
180
179
  yield f"Install {matching[1]} it using your LaTeX package manager, or check for typos."
181
180
 
@@ -200,14 +199,14 @@ def compile_tex(tex_file: Path, tex_compiler: str, output_format: str) -> Path:
200
199
  result = tex_file.with_suffix(output_format)
201
200
  tex_dir = config.get_dir("tex_dir")
202
201
  if not result.exists():
203
- command = tex_compilation_command(
202
+ command = make_tex_compilation_command(
204
203
  tex_compiler,
205
204
  output_format,
206
205
  tex_file,
207
206
  tex_dir,
208
207
  )
209
- exit_code = os.system(command)
210
- if exit_code != 0:
208
+ cp = subprocess.run(command, stdout=subprocess.DEVNULL)
209
+ if cp.returncode != 0:
211
210
  log_file = tex_file.with_suffix(".log")
212
211
  print_all_tex_errors(log_file, tex_compiler, tex_file)
213
212
  raise ValueError(
@@ -218,7 +217,7 @@ def compile_tex(tex_file: Path, tex_compiler: str, output_format: str) -> Path:
218
217
  return result
219
218
 
220
219
 
221
- def convert_to_svg(dvi_file: Path, extension: str, page: int = 1):
220
+ def convert_to_svg(dvi_file: Path, extension: str, page: int = 1) -> Path:
222
221
  """Converts a .dvi, .xdv, or .pdf file into an svg using dvisvgm.
223
222
 
224
223
  Parameters
@@ -237,18 +236,16 @@ def convert_to_svg(dvi_file: Path, extension: str, page: int = 1):
237
236
  """
238
237
  result = dvi_file.with_suffix(".svg")
239
238
  if not result.exists():
240
- commands = [
239
+ command = [
241
240
  "dvisvgm",
242
- "--pdf" if extension == ".pdf" else "",
243
- "-p " + str(page),
244
- f'"{dvi_file.as_posix()}"',
245
- "-n",
246
- "-v 0",
247
- "-o " + f'"{result.as_posix()}"',
248
- ">",
249
- os.devnull,
241
+ *(["--pdf"] if extension == ".pdf" else []),
242
+ f"--page={page}",
243
+ "--no-fonts",
244
+ "--verbosity=0",
245
+ f"--output={result.as_posix()}",
246
+ f"{dvi_file.as_posix()}",
250
247
  ]
251
- os.system(" ".join(commands))
248
+ subprocess.run(command, stdout=subprocess.DEVNULL)
252
249
 
253
250
  # if the file does not exist now, this means conversion failed
254
251
  if not result.exists():
@@ -271,7 +268,6 @@ def delete_nonsvg_files(additional_endings: Iterable[str] = ()) -> None:
271
268
  additional_endings
272
269
  Additional endings to whitelist
273
270
  """
274
-
275
271
  tex_dir = config.get_dir("tex_dir")
276
272
  file_suffix_whitelist = {".svg", ".tex", *additional_endings}
277
273
 
@@ -310,7 +306,11 @@ LATEX_ERROR_INSIGHTS = [
310
306
  ]
311
307
 
312
308
 
313
- def print_tex_error(tex_compilation_log, error_start_index, tex_source):
309
+ def print_tex_error(
310
+ tex_compilation_log: Sequence[str],
311
+ error_start_index: int,
312
+ tex_source: Sequence[str],
313
+ ) -> None:
314
314
  logger.error(
315
315
  f"LaTeX compilation error: {tex_compilation_log[error_start_index][2:]}",
316
316
  )
@@ -344,8 +344,8 @@ def print_tex_error(tex_compilation_log, error_start_index, tex_source):
344
344
  context += tex_source[line_of_tex_error - 3 : line_of_tex_error + 3]
345
345
  context[-4] = "-> " + context[-4]
346
346
 
347
- context = "".join(context)
348
- logger.error(context)
347
+ context_joined = "".join(context)
348
+ logger.error(context_joined)
349
349
 
350
350
  for insights in LATEX_ERROR_INSIGHTS:
351
351
  prob, get_insight = insights
@@ -12,7 +12,7 @@ from .tex import *
12
12
  # This file makes TexTemplateLibrary and TexFontTemplates available for use in manim Tex and MathTex objects.
13
13
 
14
14
 
15
- def _new_ams_template():
15
+ def _new_ams_template() -> TexTemplate:
16
16
  """Returns a simple Tex Template with only basic AMS packages"""
17
17
  preamble = r"""
18
18
  \usepackage[english]{babel}
manim/utils/unit.py CHANGED
@@ -5,20 +5,21 @@ from __future__ import annotations
5
5
  import numpy as np
6
6
 
7
7
  from .. import config, constants
8
+ from ..typing import Vector3D
8
9
 
9
10
  __all__ = ["Pixels", "Degrees", "Munits", "Percent"]
10
11
 
11
12
 
12
13
  class _PixelUnits:
13
- def __mul__(self, val):
14
+ def __mul__(self, val: float) -> float:
14
15
  return val * config.frame_width / config.pixel_width
15
16
 
16
- def __rmul__(self, val):
17
+ def __rmul__(self, val: float) -> float:
17
18
  return val * config.frame_width / config.pixel_width
18
19
 
19
20
 
20
21
  class Percent:
21
- def __init__(self, axis):
22
+ def __init__(self, axis: Vector3D) -> None:
22
23
  if np.array_equal(axis, constants.X_AXIS):
23
24
  self.length = config.frame_width
24
25
  if np.array_equal(axis, constants.Y_AXIS):
@@ -26,10 +27,10 @@ class Percent:
26
27
  if np.array_equal(axis, constants.Z_AXIS):
27
28
  raise NotImplementedError("length of Z axis is undefined")
28
29
 
29
- def __mul__(self, val):
30
+ def __mul__(self, val: float) -> float:
30
31
  return val / 100 * self.length
31
32
 
32
- def __rmul__(self, val):
33
+ def __rmul__(self, val: float) -> float:
33
34
  return val / 100 * self.length
34
35
 
35
36
 
@@ -1,12 +1,11 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: manim
3
- Version: 0.18.1
3
+ Version: 0.19.0
4
4
  Summary: Animation engine for explanatory math videos.
5
- Home-page: https://www.manim.community/
6
5
  License: MIT
7
6
  Author: The Manim Community Developers
8
7
  Author-email: contact@manim.community
9
- Requires-Python: >=3.9,<3.13
8
+ Requires-Python: >=3.9
10
9
  Classifier: Development Status :: 4 - Beta
11
10
  Classifier: License :: OSI Approved :: MIT License
12
11
  Classifier: Natural Language :: English
@@ -15,7 +14,7 @@ Classifier: Programming Language :: Python :: 3.9
15
14
  Classifier: Programming Language :: Python :: 3.10
16
15
  Classifier: Programming Language :: Python :: 3.11
17
16
  Classifier: Programming Language :: Python :: 3.12
18
- Classifier: Programming Language :: Python :: 3.8
17
+ Classifier: Programming Language :: Python :: 3.13
19
18
  Classifier: Topic :: Multimedia :: Graphics
20
19
  Classifier: Topic :: Multimedia :: Video
21
20
  Classifier: Topic :: Scientific/Engineering
@@ -23,6 +22,9 @@ Provides-Extra: gui
23
22
  Provides-Extra: jupyterlab
24
23
  Requires-Dist: Pillow (>=9.1)
25
24
  Requires-Dist: Pygments (>=2.0.0)
25
+ Requires-Dist: audioop-lts (>=0.2.0) ; python_version >= "3.13"
26
+ Requires-Dist: av (>=9.0.0,<14.0.0)
27
+ Requires-Dist: beautifulsoup4 (>=4.12)
26
28
  Requires-Dist: click (>=8.0)
27
29
  Requires-Dist: cloup (>=2.0.0)
28
30
  Requires-Dist: dearpygui (>=1.0.0) ; extra == "gui"
@@ -36,11 +38,13 @@ Requires-Dist: moderngl (>=5.0.0,<6.0.0)
36
38
  Requires-Dist: moderngl-window (>=2.0.0)
37
39
  Requires-Dist: networkx (>=2.6)
38
40
  Requires-Dist: notebook (>=6.0.0) ; extra == "jupyterlab"
39
- Requires-Dist: numpy (>=1.26)
41
+ Requires-Dist: numpy (>=2.0) ; python_version < "3.10"
42
+ Requires-Dist: numpy (>=2.1) ; python_version >= "3.10"
40
43
  Requires-Dist: pycairo (>=1.13,<2.0.0)
41
44
  Requires-Dist: pydub (>=0.20.0)
42
45
  Requires-Dist: rich (>=12.0.0)
43
- Requires-Dist: scipy (>=1.6.0)
46
+ Requires-Dist: scipy (>=1.13.0) ; python_version < "3.13"
47
+ Requires-Dist: scipy (>=1.14.0) ; python_version >= "3.13"
44
48
  Requires-Dist: screeninfo (>=0.7)
45
49
  Requires-Dist: skia-pathops (>=0.7.0)
46
50
  Requires-Dist: srt (>=3.0.0)
@@ -52,6 +56,7 @@ Project-URL: Bug Tracker, https://github.com/ManimCommunity/manim/issues
52
56
  Project-URL: Changelog, https://docs.manim.community/en/stable/changelog.html
53
57
  Project-URL: Documentation, https://docs.manim.community/
54
58
  Project-URL: Discord, https://www.manim.community/discord/
59
+ Project-URL: Homepage, https://www.manim.community/
55
60
  Project-URL: Repository, https://github.com/manimcommunity/manim
56
61
  Project-URL: Twitter, https://twitter.com/manim_community
57
62
  Description-Content-Type: text/markdown
@@ -79,7 +84,8 @@ Description-Content-Type: text/markdown
79
84
 
80
85
  Manim is an animation engine for explanatory math videos. It's used to create precise animations programmatically, as demonstrated in the videos of [3Blue1Brown](https://www.3blue1brown.com/).
81
86
 
82
- > NOTE: This repository is maintained by the Manim Community and is not associated with Grant Sanderson or 3Blue1Brown in any way (although we are definitely indebted to him for providing his work to the world). If you would like to study how Grant makes his videos, head over to his repository ([3b1b/manim](https://github.com/3b1b/manim)). This fork is updated more frequently than his, and it's recommended to use this fork if you'd like to use Manim for your own projects.
87
+ > [!NOTE]
88
+ > The community edition of Manim has been forked from 3b1b/manim, a tool originally created and open-sourced by Grant Sanderson, also creator of the 3Blue1Brown educational math videos. While Grant Sanderson’s repository continues to be maintained separately by him, he is not among the maintainers of the community edition. We recommend this version for its continued development, improved features, enhanced documentation, and more active community-driven maintenance. If you would like to study how Grant makes his videos, head over to his repository ([3b1b/manim](https://github.com/3b1b/manim)).
83
89
 
84
90
  ## Table of Contents:
85
91
 
@@ -93,7 +99,8 @@ Manim is an animation engine for explanatory math videos. It's used to create pr
93
99
 
94
100
  ## Installation
95
101
 
96
- > **WARNING:** These instructions are for the community version _only_. Trying to use these instructions to install [3b1b/manim](https://github.com/3b1b/manim) or instructions there to install this version will cause problems. Read [this](https://docs.manim.community/en/stable/faq/installation.html#why-are-there-different-versions-of-manim) and decide which version you wish to install, then only follow the instructions for your desired version.
102
+ > [!CAUTION]
103
+ > These instructions are for the community version _only_. Trying to use these instructions to install [3b1b/manim](https://github.com/3b1b/manim) or instructions there to install this version will cause problems. Read [this](https://docs.manim.community/en/stable/faq/installation.html#why-are-there-different-versions-of-manim) and decide which version you wish to install, then only follow the instructions for your desired version.
97
104
 
98
105
  Manim requires a few dependencies that must be installed prior to using it. If you
99
106
  want to try it out first before installing it locally, you can do so