From ba5c73a939ca76d309dafe71cc336adf6dc96577 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Fri, 18 Oct 2024 16:13:53 +0200 Subject: [PATCH 01/45] Removed typing errors in mobject/geometry/shape_matchers.py --- manim/mobject/geometry/shape_matchers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manim/mobject/geometry/shape_matchers.py b/manim/mobject/geometry/shape_matchers.py index b546dfb4f3..07354f5310 100644 --- a/manim/mobject/geometry/shape_matchers.py +++ b/manim/mobject/geometry/shape_matchers.py @@ -113,7 +113,7 @@ def pointwise_become_partial(self, mobject: Mobject, a: Any, b: float) -> Self: self.set_fill(opacity=b * self.original_fill_opacity) return self - def set_style(self, fill_opacity: float, **kwargs: Any) -> Self: # type: ignore[override] + def set_style(self, fill_opacity: float, **kwargs: Any) -> Self: # Unchangeable style, except for fill_opacity # All other style arguments are ignored super().set_style( From c6e071f409034e43beaaf60cc7514154cdce7e3b Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Fri, 18 Oct 2024 20:00:17 +0200 Subject: [PATCH 02/45] Added type annotations fo mobject/types/image_mobject.py and a few other files --- manim/mobject/types/image_mobject.py | 1 + 1 file changed, 1 insertion(+) diff --git a/manim/mobject/types/image_mobject.py b/manim/mobject/types/image_mobject.py index 56029f941e..4c6ee82af0 100644 --- a/manim/mobject/types/image_mobject.py +++ b/manim/mobject/types/image_mobject.py @@ -14,6 +14,7 @@ from manim.mobject.geometry.shape_matchers import SurroundingRectangle from ... import config +from ...camera.camera import Camera from ...constants import * from ...mobject.mobject import Mobject from ...utils.bezier import interpolate From 758e1990e2707472d4494e537d57a60f645837d8 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Fri, 18 Oct 2024 20:49:48 +0200 Subject: [PATCH 03/45] Adding type annotations to types/point_cloud_mobject.py --- manim/mobject/types/point_cloud_mobject.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manim/mobject/types/point_cloud_mobject.py b/manim/mobject/types/point_cloud_mobject.py index c9f54e6ed2..6f9c79ac48 100644 --- a/manim/mobject/types/point_cloud_mobject.py +++ b/manim/mobject/types/point_cloud_mobject.py @@ -206,11 +206,11 @@ def point_from_proportion(self, alpha: float) -> Any: return self.points[np.floor(index)] @staticmethod - def get_mobject_type_class() -> type[PMobject]: + def get_mobject_type_class() -> PMobject: return PMobject # Alignment - def align_points_with_larger(self, larger_mobject: Mobject) -> None: + def align_points_with_larger(self, larger_mobject: PMobject) -> None: assert isinstance(larger_mobject, PMobject) self.apply_over_attr_arrays( lambda a: stretch_array_to_length(a, larger_mobject.get_num_points()), From b54a624938c0def7f9a78444b4d61bb0ae5af5af Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Fri, 18 Oct 2024 21:17:23 +0200 Subject: [PATCH 04/45] Fixing issues revealed by type annotations in types/point_cloud_mobject.py --- manim/mobject/types/point_cloud_mobject.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manim/mobject/types/point_cloud_mobject.py b/manim/mobject/types/point_cloud_mobject.py index 6f9c79ac48..c9f54e6ed2 100644 --- a/manim/mobject/types/point_cloud_mobject.py +++ b/manim/mobject/types/point_cloud_mobject.py @@ -206,11 +206,11 @@ def point_from_proportion(self, alpha: float) -> Any: return self.points[np.floor(index)] @staticmethod - def get_mobject_type_class() -> PMobject: + def get_mobject_type_class() -> type[PMobject]: return PMobject # Alignment - def align_points_with_larger(self, larger_mobject: PMobject) -> None: + def align_points_with_larger(self, larger_mobject: Mobject) -> None: assert isinstance(larger_mobject, PMobject) self.apply_over_attr_arrays( lambda a: stretch_array_to_length(a, larger_mobject.get_num_points()), From bdf00494c12201f49720c31cf375f2f8259c99d9 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Fri, 18 Oct 2024 21:21:13 +0200 Subject: [PATCH 05/45] Fix issue in the CI step related to the Camera class. --- manim/mobject/types/image_mobject.py | 1 - 1 file changed, 1 deletion(-) diff --git a/manim/mobject/types/image_mobject.py b/manim/mobject/types/image_mobject.py index 4c6ee82af0..56029f941e 100644 --- a/manim/mobject/types/image_mobject.py +++ b/manim/mobject/types/image_mobject.py @@ -14,7 +14,6 @@ from manim.mobject.geometry.shape_matchers import SurroundingRectangle from ... import config -from ...camera.camera import Camera from ...constants import * from ...mobject.mobject import Mobject from ...utils.bezier import interpolate From 1962c7320caac246cddd849e549276153d0aefdc Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Fri, 18 Oct 2024 23:02:20 +0200 Subject: [PATCH 06/45] Adding type annotations to geometry/line.py --- manim/mobject/geometry/line.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manim/mobject/geometry/line.py b/manim/mobject/geometry/line.py index ef0e4aa1ff..50e5327458 100644 --- a/manim/mobject/geometry/line.py +++ b/manim/mobject/geometry/line.py @@ -556,7 +556,7 @@ def __init__( self.add_tip(tip_shape=tip_shape) self._set_stroke_width_from_length() - def scale(self, factor: float, scale_tips: bool = False, **kwargs: Any) -> Self: # type: ignore[override] + def scale(self, factor: float, scale_tips: bool = False, **kwargs: Any) -> Self: r"""Scale an arrow, but keep stroke width and arrow tip size fixed. From 92d99088e9a39bbc6e863154ba1e19e777d039be Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Sat, 19 Oct 2024 21:00:23 +0200 Subject: [PATCH 07/45] Ignore type errors related to super and sub class in line.py and shape_matchers.py --- manim/mobject/geometry/line.py | 2 +- manim/mobject/geometry/shape_matchers.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/manim/mobject/geometry/line.py b/manim/mobject/geometry/line.py index 50e5327458..ef0e4aa1ff 100644 --- a/manim/mobject/geometry/line.py +++ b/manim/mobject/geometry/line.py @@ -556,7 +556,7 @@ def __init__( self.add_tip(tip_shape=tip_shape) self._set_stroke_width_from_length() - def scale(self, factor: float, scale_tips: bool = False, **kwargs: Any) -> Self: + def scale(self, factor: float, scale_tips: bool = False, **kwargs: Any) -> Self: # type: ignore[override] r"""Scale an arrow, but keep stroke width and arrow tip size fixed. diff --git a/manim/mobject/geometry/shape_matchers.py b/manim/mobject/geometry/shape_matchers.py index 07354f5310..b546dfb4f3 100644 --- a/manim/mobject/geometry/shape_matchers.py +++ b/manim/mobject/geometry/shape_matchers.py @@ -113,7 +113,7 @@ def pointwise_become_partial(self, mobject: Mobject, a: Any, b: float) -> Self: self.set_fill(opacity=b * self.original_fill_opacity) return self - def set_style(self, fill_opacity: float, **kwargs: Any) -> Self: + def set_style(self, fill_opacity: float, **kwargs: Any) -> Self: # type: ignore[override] # Unchangeable style, except for fill_opacity # All other style arguments are ignored super().set_style( From bd4f02aeb9437bbfb9c014f8c53ed76dd87b6090 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Sat, 19 Oct 2024 21:53:41 +0200 Subject: [PATCH 08/45] Dealing with some issues and ignoring others identified by type checking --- manim/mobject/geometry/boolean_ops.py | 4 ++-- manim/mobject/geometry/line.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/manim/mobject/geometry/boolean_ops.py b/manim/mobject/geometry/boolean_ops.py index a34d6fc7c4..dfd5b04654 100644 --- a/manim/mobject/geometry/boolean_ops.py +++ b/manim/mobject/geometry/boolean_ops.py @@ -5,7 +5,7 @@ from typing import TYPE_CHECKING import numpy as np -from pathops import Path as SkiaPath +from pathops import Path as SkiaPath # type: ignore[import-untyped] from pathops import PathVerb, difference, intersection, union, xor from manim import config @@ -106,7 +106,7 @@ def _convert_vmobject_to_skia_path(self, vmobject: VMobject) -> SkiaPath: for _p0, p1, p2, p3 in quads: path.cubicTo(*p1[:2], *p2[:2], *p3[:2]) - if vmobject.consider_points_equals_2d(subpath[0], subpath[-1]): + if vmobject.consider_points_equals_2d(subpath[0], subpath[-1]): # type: ignore[arg-type] path.close() return path diff --git a/manim/mobject/geometry/line.py b/manim/mobject/geometry/line.py index ef0e4aa1ff..931373eae2 100644 --- a/manim/mobject/geometry/line.py +++ b/manim/mobject/geometry/line.py @@ -145,9 +145,9 @@ def _pointify( if isinstance(mob_or_point, (Mobject, OpenGLMobject)): mob = mob_or_point if direction is None: - return mob.get_center() + return mob.get_center() # type: ignore[return-value] else: - return mob.get_boundary_point(direction) + return mob.get_boundary_point(direction) # type: ignore[return-value] return np.array(mob_or_point) def set_path_arc(self, new_value: float) -> None: @@ -309,7 +309,7 @@ def get_start(self) -> InternalPoint3D: array([-1., 0., 0.]) """ if len(self.submobjects) > 0: - return self.submobjects[0].get_start() + return self.submobjects[0].get_start() # type: ignore[return-value] else: return super().get_start() @@ -324,7 +324,7 @@ def get_end(self) -> InternalPoint3D: array([1., 0., 0.]) """ if len(self.submobjects) > 0: - return self.submobjects[-1].get_end() + return self.submobjects[-1].get_end() # type: ignore[return-value] else: return super().get_end() From a4bda5dbc21a6779544964d77b3c1c9cce06cdd9 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Sun, 20 Oct 2024 20:16:27 +0200 Subject: [PATCH 09/45] Ignored a number of type issues related to float and floating[Any]. --- manim/mobject/geometry/arc.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/manim/mobject/geometry/arc.py b/manim/mobject/geometry/arc.py index c211deae01..70cdf57f47 100644 --- a/manim/mobject/geometry/arc.py +++ b/manim/mobject/geometry/arc.py @@ -280,15 +280,15 @@ def get_last_handle(self) -> InternalPoint3D: def get_end(self) -> InternalPoint3D: if self.has_tip(): - return self.tip.get_start() + return self.tip.get_start() # type: ignore[return-value] else: - return super().get_end() + return super().get_end() # type: ignore[return-value] def get_start(self) -> InternalPoint3D: if self.has_start_tip(): - return self.start_tip.get_start() + return self.start_tip.get_start() # type: ignore[return-value] else: - return super().get_start() + return super().get_start() # type: ignore[return-value] def get_length(self) -> float: start, end = self.get_start_and_end() From 45e18e84228176d2d75a226cbe948912bdc2a8ba Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Sun, 20 Oct 2024 20:17:51 +0200 Subject: [PATCH 10/45] Help mypy to determine types. --- manim/mobject/geometry/arc.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/manim/mobject/geometry/arc.py b/manim/mobject/geometry/arc.py index 70cdf57f47..6b04d989c2 100644 --- a/manim/mobject/geometry/arc.py +++ b/manim/mobject/geometry/arc.py @@ -322,10 +322,10 @@ def __init__( if radius is None: # apparently None is passed by ArcBetweenPoints radius = 1.0 self.radius = radius - self.num_components = num_components - self.arc_center = arc_center - self.start_angle = start_angle - self.angle = angle + self.num_components: int = num_components + self.arc_center: InternalPoint3D = arc_center + self.start_angle: float = start_angle + self.angle: float = angle self._failed_to_get_center: bool = False super().__init__(**kwargs) From c29a38e2b93422c1d6b9c3be0a5c3df53c5a3cc1 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Mon, 21 Oct 2024 23:00:49 +0200 Subject: [PATCH 11/45] More work on addressing typing issues. --- manim/mobject/geometry/polygram.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manim/mobject/geometry/polygram.py b/manim/mobject/geometry/polygram.py index bfb9f00ab7..b79368bd55 100644 --- a/manim/mobject/geometry/polygram.py +++ b/manim/mobject/geometry/polygram.py @@ -322,7 +322,7 @@ def construct(self): """ def __init__(self, *vertices: InternalPoint3D, **kwargs: Any) -> None: - super().__init__(vertices, **kwargs) + super().__init__(np.array(vertices), **kwargs) class RegularPolygram(Polygram): @@ -413,7 +413,7 @@ def gen_polygon_vertices(start_angle: float | None) -> tuple[list[Any], float]: vertex_groups.append(group) - super().__init__(*vertex_groups, **kwargs) + super().__init__(np.array(*vertex_groups), **kwargs) class RegularPolygon(RegularPolygram): From 11e6ffacb0d49de576e20cf5c26de851621d1f6b Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Mon, 21 Oct 2024 23:14:23 +0200 Subject: [PATCH 12/45] Reverting two changes that triggers an error in the automatic testing. --- manim/mobject/geometry/polygram.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manim/mobject/geometry/polygram.py b/manim/mobject/geometry/polygram.py index b79368bd55..bfb9f00ab7 100644 --- a/manim/mobject/geometry/polygram.py +++ b/manim/mobject/geometry/polygram.py @@ -322,7 +322,7 @@ def construct(self): """ def __init__(self, *vertices: InternalPoint3D, **kwargs: Any) -> None: - super().__init__(np.array(vertices), **kwargs) + super().__init__(vertices, **kwargs) class RegularPolygram(Polygram): @@ -413,7 +413,7 @@ def gen_polygon_vertices(start_angle: float | None) -> tuple[list[Any], float]: vertex_groups.append(group) - super().__init__(np.array(*vertex_groups), **kwargs) + super().__init__(*vertex_groups, **kwargs) class RegularPolygon(RegularPolygram): From 935fd0c1ad668d83b9dfb39dc1be50d178c7e8e8 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Mon, 21 Oct 2024 23:22:56 +0200 Subject: [PATCH 13/45] Further work on type hinting. --- manim/mobject/geometry/polygram.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manim/mobject/geometry/polygram.py b/manim/mobject/geometry/polygram.py index bfb9f00ab7..bac34e497a 100644 --- a/manim/mobject/geometry/polygram.py +++ b/manim/mobject/geometry/polygram.py @@ -322,7 +322,7 @@ def construct(self): """ def __init__(self, *vertices: InternalPoint3D, **kwargs: Any) -> None: - super().__init__(vertices, **kwargs) + super().__init__(vertices, **kwargs) # type: ignore[arg-type] class RegularPolygram(Polygram): @@ -413,7 +413,7 @@ def gen_polygon_vertices(start_angle: float | None) -> tuple[list[Any], float]: vertex_groups.append(group) - super().__init__(*vertex_groups, **kwargs) + super().__init__(*vertex_groups, **kwargs) # type: ignore[arg-type] class RegularPolygon(RegularPolygram): From 00f546d5d85eec9a56a9168fa96cf1ab432239cc Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Tue, 22 Oct 2024 09:03:11 +0200 Subject: [PATCH 14/45] Avoid forwarding positional arguments from Arrow to Line in the constructor. --- manim/mobject/geometry/line.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/manim/mobject/geometry/line.py b/manim/mobject/geometry/line.py index 931373eae2..8968d267a7 100644 --- a/manim/mobject/geometry/line.py +++ b/manim/mobject/geometry/line.py @@ -549,7 +549,10 @@ def __init__( self.max_tip_length_to_length_ratio = max_tip_length_to_length_ratio self.max_stroke_width_to_length_ratio = max_stroke_width_to_length_ratio tip_shape = kwargs.pop("tip_shape", ArrowTriangleFilledTip) - super().__init__(*args, buff=buff, stroke_width=stroke_width, **kwargs) # type: ignore[misc] + # The args argument have not been forwarded to the super() object, + # as that object do not accept any positional arguments. + # mobject/geometry/line.py#L44 + super().__init__(buff=buff, stroke_width=stroke_width, **kwargs) # TODO, should this be affected when # Arrow.set_stroke is called? self.initial_stroke_width = self.stroke_width From 020a7773f5ccbfab0fe794c201d595938e0b639e Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Tue, 22 Oct 2024 13:22:45 +0200 Subject: [PATCH 15/45] Revert "Avoid forwarding positional arguments from Arrow to Line in the constructor." This reverts commit 80ae8576c164f394c3c3c82dc0c30336b72e53a3. --- manim/mobject/geometry/line.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/manim/mobject/geometry/line.py b/manim/mobject/geometry/line.py index 8968d267a7..50c9ee9692 100644 --- a/manim/mobject/geometry/line.py +++ b/manim/mobject/geometry/line.py @@ -549,10 +549,7 @@ def __init__( self.max_tip_length_to_length_ratio = max_tip_length_to_length_ratio self.max_stroke_width_to_length_ratio = max_stroke_width_to_length_ratio tip_shape = kwargs.pop("tip_shape", ArrowTriangleFilledTip) - # The args argument have not been forwarded to the super() object, - # as that object do not accept any positional arguments. - # mobject/geometry/line.py#L44 - super().__init__(buff=buff, stroke_width=stroke_width, **kwargs) + super().__init__(*args, buff=buff, stroke_width=stroke_width, **kwargs) # TODO, should this be affected when # Arrow.set_stroke is called? self.initial_stroke_width = self.stroke_width From ef6158af007aedc168e96b90e43cada7861ba618 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Tue, 22 Oct 2024 14:07:36 +0200 Subject: [PATCH 16/45] Removed several type ignore statements and addressed comments from JasonGrace2282 --- manim/mobject/geometry/arc.py | 8 ++++---- manim/mobject/geometry/boolean_ops.py | 4 ++-- manim/mobject/geometry/line.py | 13 +++++++------ manim/mobject/geometry/polygram.py | 4 ++-- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/manim/mobject/geometry/arc.py b/manim/mobject/geometry/arc.py index 6b04d989c2..e746b96eb1 100644 --- a/manim/mobject/geometry/arc.py +++ b/manim/mobject/geometry/arc.py @@ -280,15 +280,15 @@ def get_last_handle(self) -> InternalPoint3D: def get_end(self) -> InternalPoint3D: if self.has_tip(): - return self.tip.get_start() # type: ignore[return-value] + return self.tip.get_start() else: - return super().get_end() # type: ignore[return-value] + return super().get_end() def get_start(self) -> InternalPoint3D: if self.has_start_tip(): - return self.start_tip.get_start() # type: ignore[return-value] + return self.start_tip.get_start() else: - return super().get_start() # type: ignore[return-value] + return super().get_start() def get_length(self) -> float: start, end = self.get_start_and_end() diff --git a/manim/mobject/geometry/boolean_ops.py b/manim/mobject/geometry/boolean_ops.py index dfd5b04654..a34d6fc7c4 100644 --- a/manim/mobject/geometry/boolean_ops.py +++ b/manim/mobject/geometry/boolean_ops.py @@ -5,7 +5,7 @@ from typing import TYPE_CHECKING import numpy as np -from pathops import Path as SkiaPath # type: ignore[import-untyped] +from pathops import Path as SkiaPath from pathops import PathVerb, difference, intersection, union, xor from manim import config @@ -106,7 +106,7 @@ def _convert_vmobject_to_skia_path(self, vmobject: VMobject) -> SkiaPath: for _p0, p1, p2, p3 in quads: path.cubicTo(*p1[:2], *p2[:2], *p3[:2]) - if vmobject.consider_points_equals_2d(subpath[0], subpath[-1]): # type: ignore[arg-type] + if vmobject.consider_points_equals_2d(subpath[0], subpath[-1]): path.close() return path diff --git a/manim/mobject/geometry/line.py b/manim/mobject/geometry/line.py index 50c9ee9692..3e6a6d3c2f 100644 --- a/manim/mobject/geometry/line.py +++ b/manim/mobject/geometry/line.py @@ -145,9 +145,9 @@ def _pointify( if isinstance(mob_or_point, (Mobject, OpenGLMobject)): mob = mob_or_point if direction is None: - return mob.get_center() # type: ignore[return-value] + return mob.get_center() else: - return mob.get_boundary_point(direction) # type: ignore[return-value] + return mob.get_boundary_point(direction) return np.array(mob_or_point) def set_path_arc(self, new_value: float) -> None: @@ -309,7 +309,7 @@ def get_start(self) -> InternalPoint3D: array([-1., 0., 0.]) """ if len(self.submobjects) > 0: - return self.submobjects[0].get_start() # type: ignore[return-value] + return self.submobjects[0].get_start() else: return super().get_start() @@ -324,7 +324,7 @@ def get_end(self) -> InternalPoint3D: array([1., 0., 0.]) """ if len(self.submobjects) > 0: - return self.submobjects[-1].get_end() # type: ignore[return-value] + return self.submobjects[-1].get_end() else: return super().get_end() @@ -549,7 +549,7 @@ def __init__( self.max_tip_length_to_length_ratio = max_tip_length_to_length_ratio self.max_stroke_width_to_length_ratio = max_stroke_width_to_length_ratio tip_shape = kwargs.pop("tip_shape", ArrowTriangleFilledTip) - super().__init__(*args, buff=buff, stroke_width=stroke_width, **kwargs) + super().__init__(*args, buff=buff, stroke_width=stroke_width, **kwargs) # type: ignore[misc] # TODO, should this be affected when # Arrow.set_stroke is called? self.initial_stroke_width = self.stroke_width @@ -1073,7 +1073,8 @@ def construct(self): self.add(line1, line2, angle, value) """ - return self.angle_value / DEGREES if degrees else self.angle_value + temp_angle: float = self.angle_value / DEGREES if degrees else self.angle_value + return temp_angle @staticmethod def from_three_points(A: Point3D, B: Point3D, C: Point3D, **kwargs: Any) -> Angle: diff --git a/manim/mobject/geometry/polygram.py b/manim/mobject/geometry/polygram.py index bac34e497a..bfb9f00ab7 100644 --- a/manim/mobject/geometry/polygram.py +++ b/manim/mobject/geometry/polygram.py @@ -322,7 +322,7 @@ def construct(self): """ def __init__(self, *vertices: InternalPoint3D, **kwargs: Any) -> None: - super().__init__(vertices, **kwargs) # type: ignore[arg-type] + super().__init__(vertices, **kwargs) class RegularPolygram(Polygram): @@ -413,7 +413,7 @@ def gen_polygon_vertices(start_angle: float | None) -> tuple[list[Any], float]: vertex_groups.append(group) - super().__init__(*vertex_groups, **kwargs) # type: ignore[arg-type] + super().__init__(*vertex_groups, **kwargs) class RegularPolygon(RegularPolygram): From e79fd755e38e76087a6d35c2c817fe73c9121996 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Tue, 22 Oct 2024 14:15:31 +0200 Subject: [PATCH 17/45] Revert "Activate mypy check of mobject.geometry.*" This reverts commit d477c9a99493a85f683a5ee0cb6098835bc6b42e. --- mypy.ini | 3 --- 1 file changed, 3 deletions(-) diff --git a/mypy.ini b/mypy.ini index 12c0a1dd69..956b44ae21 100644 --- a/mypy.ini +++ b/mypy.ini @@ -70,9 +70,6 @@ ignore_errors = True [mypy-manim.mobject.*] ignore_errors = True -[mypy-manim.mobject.geometry.*] -ignore_errors = False - [mypy-manim.plugins.*] ignore_errors = True From c85a19dd081806440458c82c32b6199fd9164cce Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Tue, 22 Oct 2024 14:16:04 +0200 Subject: [PATCH 18/45] Revert "Removed several type ignore statements and addressed comments from JasonGrace2282" This reverts commit 07bbe3f2200d42fe1a575ad7362163538a07ec84. --- manim/mobject/geometry/arc.py | 16 ++++++++-------- manim/mobject/geometry/boolean_ops.py | 4 ++-- manim/mobject/geometry/line.py | 15 +++++++-------- manim/mobject/geometry/polygram.py | 6 +++--- manim/mobject/geometry/tips.py | 2 +- 5 files changed, 21 insertions(+), 22 deletions(-) diff --git a/manim/mobject/geometry/arc.py b/manim/mobject/geometry/arc.py index e746b96eb1..abf03c9c7b 100644 --- a/manim/mobject/geometry/arc.py +++ b/manim/mobject/geometry/arc.py @@ -273,22 +273,22 @@ def get_first_handle(self) -> InternalPoint3D: # Type inference of extracting an element from a list, is not # supported by numpy, see this numpy issue # https://github.com/numpy/numpy/issues/16544 - return self.points[1] + return self.points[1] # type: ignore[no-any-return] def get_last_handle(self) -> InternalPoint3D: - return self.points[-2] + return self.points[-2] # type: ignore[no-any-return] def get_end(self) -> InternalPoint3D: if self.has_tip(): - return self.tip.get_start() + return self.tip.get_start() # type: ignore[return-value] else: - return super().get_end() + return super().get_end() # type: ignore[return-value] def get_start(self) -> InternalPoint3D: if self.has_start_tip(): - return self.start_tip.get_start() + return self.start_tip.get_start() # type: ignore[return-value] else: - return super().get_start() + return super().get_start() # type: ignore[return-value] def get_length(self) -> float: start, end = self.get_start_and_end() @@ -484,7 +484,7 @@ def __init__( if radius is None: center = self.get_arc_center(warning=False) if not self._failed_to_get_center: - temp_radius: float = np.linalg.norm(np.array(start) - np.array(center)) + temp_radius: float = np.linalg.norm(np.array(start) - np.array(center)) # type: ignore[assignment] self.radius = temp_radius else: self.radius = np.inf @@ -661,7 +661,7 @@ def construct(self): perpendicular_bisector([np.asarray(p1), np.asarray(p2)]), perpendicular_bisector([np.asarray(p2), np.asarray(p3)]), ) - radius: float = np.linalg.norm(p1 - center) + radius: float = np.linalg.norm(p1 - center) # type: ignore[assignment] return Circle(radius=radius, **kwargs).shift(center) diff --git a/manim/mobject/geometry/boolean_ops.py b/manim/mobject/geometry/boolean_ops.py index a34d6fc7c4..dfd5b04654 100644 --- a/manim/mobject/geometry/boolean_ops.py +++ b/manim/mobject/geometry/boolean_ops.py @@ -5,7 +5,7 @@ from typing import TYPE_CHECKING import numpy as np -from pathops import Path as SkiaPath +from pathops import Path as SkiaPath # type: ignore[import-untyped] from pathops import PathVerb, difference, intersection, union, xor from manim import config @@ -106,7 +106,7 @@ def _convert_vmobject_to_skia_path(self, vmobject: VMobject) -> SkiaPath: for _p0, p1, p2, p3 in quads: path.cubicTo(*p1[:2], *p2[:2], *p3[:2]) - if vmobject.consider_points_equals_2d(subpath[0], subpath[-1]): + if vmobject.consider_points_equals_2d(subpath[0], subpath[-1]): # type: ignore[arg-type] path.close() return path diff --git a/manim/mobject/geometry/line.py b/manim/mobject/geometry/line.py index 3e6a6d3c2f..eb83ff253c 100644 --- a/manim/mobject/geometry/line.py +++ b/manim/mobject/geometry/line.py @@ -145,9 +145,9 @@ def _pointify( if isinstance(mob_or_point, (Mobject, OpenGLMobject)): mob = mob_or_point if direction is None: - return mob.get_center() + return mob.get_center() # type: ignore[return-value] else: - return mob.get_boundary_point(direction) + return mob.get_boundary_point(direction) # type: ignore[return-value] return np.array(mob_or_point) def set_path_arc(self, new_value: float) -> None: @@ -156,8 +156,8 @@ def set_path_arc(self, new_value: float) -> None: def put_start_and_end_on( self, - start: InternalPoint3D, - end: InternalPoint3D, + start: InternalPoint3D, # type: ignore[override] + end: InternalPoint3D, # type: ignore[override] ) -> Self: """Sets starts and end coordinates of a line. @@ -309,7 +309,7 @@ def get_start(self) -> InternalPoint3D: array([-1., 0., 0.]) """ if len(self.submobjects) > 0: - return self.submobjects[0].get_start() + return self.submobjects[0].get_start() # type: ignore[return-value] else: return super().get_start() @@ -324,7 +324,7 @@ def get_end(self) -> InternalPoint3D: array([1., 0., 0.]) """ if len(self.submobjects) > 0: - return self.submobjects[-1].get_end() + return self.submobjects[-1].get_end() # type: ignore[return-value] else: return super().get_end() @@ -1073,8 +1073,7 @@ def construct(self): self.add(line1, line2, angle, value) """ - temp_angle: float = self.angle_value / DEGREES if degrees else self.angle_value - return temp_angle + return self.angle_value / DEGREES if degrees else self.angle_value @staticmethod def from_three_points(A: Point3D, B: Point3D, C: Point3D, **kwargs: Any) -> Angle: diff --git a/manim/mobject/geometry/polygram.py b/manim/mobject/geometry/polygram.py index bfb9f00ab7..f2e0c5cdd8 100644 --- a/manim/mobject/geometry/polygram.py +++ b/manim/mobject/geometry/polygram.py @@ -89,7 +89,7 @@ def __init__( for vertices in vertex_groups: # The inferred type for *vertices is Any, but it should be # InternalPoint3D_Array - first_vertex, *vertices = vertices + first_vertex, *vertices = vertices # type: ignore[assignment] first_vertex = np.array(first_vertex) self.start_new_path(first_vertex) @@ -322,7 +322,7 @@ def construct(self): """ def __init__(self, *vertices: InternalPoint3D, **kwargs: Any) -> None: - super().__init__(vertices, **kwargs) + super().__init__(vertices, **kwargs) # type: ignore[arg-type] class RegularPolygram(Polygram): @@ -413,7 +413,7 @@ def gen_polygon_vertices(start_angle: float | None) -> tuple[list[Any], float]: vertex_groups.append(group) - super().__init__(*vertex_groups, **kwargs) + super().__init__(*vertex_groups, **kwargs) # type: ignore[arg-type] class RegularPolygon(RegularPolygram): diff --git a/manim/mobject/geometry/tips.py b/manim/mobject/geometry/tips.py index e137016a88..6c54a1da64 100644 --- a/manim/mobject/geometry/tips.py +++ b/manim/mobject/geometry/tips.py @@ -152,7 +152,7 @@ def tip_point(self) -> InternalPoint3D: # Type inference of extracting an element from a list, is not # supported by numpy, see this numpy issue # https://github.com/numpy/numpy/issues/16544 - return self.points[0] + return self.points[0] # type: ignore[no-any-return] @property def vector(self) -> Vector3D: From 62439901e7ac949aacff8dd0edb1c15cb269b0d3 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Tue, 22 Oct 2024 22:51:23 +0200 Subject: [PATCH 19/45] Added type annotations to zoomed_scene.py Error count: 308 -> 303 --- manim/scene/zoomed_scene.py | 48 +++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/manim/scene/zoomed_scene.py b/manim/scene/zoomed_scene.py index 361c4eaf55..685d4d4c35 100644 --- a/manim/scene/zoomed_scene.py +++ b/manim/scene/zoomed_scene.py @@ -50,6 +50,10 @@ def construct(self): __all__ = ["ZoomedScene"] +# Note, any scenes from old videos using ZoomedScene will almost certainly +# break, as it was restructured. +from typing import TYPE_CHECKING + from ..animation.transform import ApplyMethod from ..camera.moving_camera import MovingCamera from ..camera.multi_camera import MultiCamera @@ -57,8 +61,10 @@ def construct(self): from ..mobject.types.image_mobject import ImageMobjectFromCamera from ..scene.moving_camera_scene import MovingCameraScene -# Note, any scenes from old videos using ZoomedScene will almost certainly -# break, as it was restructured. +if TYPE_CHECKING: + from typing import Any + + from manim.typing import Vector3D class ZoomedScene(MovingCameraScene): @@ -70,23 +76,23 @@ class ZoomedScene(MovingCameraScene): def __init__( self, - camera_class=MultiCamera, - zoomed_display_height=3, - zoomed_display_width=3, - zoomed_display_center=None, - zoomed_display_corner=UP + RIGHT, - zoomed_display_corner_buff=DEFAULT_MOBJECT_TO_EDGE_BUFFER, - zoomed_camera_config={ + camera_class: type[MultiCamera] = MultiCamera, + zoomed_display_height: float = 3, + zoomed_display_width: float = 3, + zoomed_display_center: Any = None, + zoomed_display_corner: Vector3D = UP + RIGHT, + zoomed_display_corner_buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER, + zoomed_camera_config: dict[str, Any] = { "default_frame_stroke_width": 2, "background_opacity": 1, }, - zoomed_camera_image_mobject_config={}, - zoomed_camera_frame_starting_position=ORIGIN, - zoom_factor=0.15, - image_frame_stroke_width=3, - zoom_activated=False, - **kwargs, - ): + zoomed_camera_image_mobject_config: dict = {}, + zoomed_camera_frame_starting_position: Vector3D = ORIGIN, + zoom_factor: float = 0.15, + image_frame_stroke_width: int = 3, + zoom_activated: bool = False, + **kwargs: Any, + ) -> None: self.zoomed_display_height = zoomed_display_height self.zoomed_display_width = zoomed_display_width self.zoomed_display_center = zoomed_display_center @@ -102,7 +108,7 @@ def __init__( self.zoom_activated = zoom_activated super().__init__(camera_class=camera_class, **kwargs) - def setup(self): + def setup(self) -> None: """ This method is used internally by Manim to setup the scene for proper use. @@ -132,7 +138,7 @@ def setup(self): self.zoomed_camera = zoomed_camera self.zoomed_display = zoomed_display - def activate_zooming(self, animate: bool = False): + def activate_zooming(self, animate: bool = False) -> None: """ This method is used to activate the zooming for the zoomed_camera. @@ -153,7 +159,7 @@ def activate_zooming(self, animate: bool = False): self.zoomed_display, ) - def get_zoom_in_animation(self, run_time: float = 2, **kwargs): + def get_zoom_in_animation(self, run_time: float = 2, **kwargs: Any) -> Any: """ Returns the animation of camera zooming in. @@ -179,7 +185,7 @@ def get_zoom_in_animation(self, run_time: float = 2, **kwargs): frame.set_stroke(width=0) return ApplyMethod(frame.restore, run_time=run_time, **kwargs) - def get_zoomed_display_pop_out_animation(self, **kwargs): + def get_zoomed_display_pop_out_animation(self, **kwargs: Any) -> Any: """ This is the animation of the popping out of the mini-display that shows the content of the zoomed @@ -195,7 +201,7 @@ def get_zoomed_display_pop_out_animation(self, **kwargs): display.replace(self.zoomed_camera.frame, stretch=True) return ApplyMethod(display.restore) - def get_zoom_factor(self): + def get_zoom_factor(self) -> float: """ Returns the Zoom factor of the Zoomed camera. Defined as the ratio between the height of the From ae06d899275fb34c3b962fba143e8d211c9480f3 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Tue, 22 Oct 2024 23:16:05 +0200 Subject: [PATCH 20/45] Adding type annotations to all methods in vector_space_scene.py Error count: 303 -> 272 --- manim/scene/vector_space_scene.py | 141 ++++++++++++++++++------------ 1 file changed, 83 insertions(+), 58 deletions(-) diff --git a/manim/scene/vector_space_scene.py b/manim/scene/vector_space_scene.py index be75151471..bf79d5c4c5 100644 --- a/manim/scene/vector_space_scene.py +++ b/manim/scene/vector_space_scene.py @@ -4,7 +4,7 @@ __all__ = ["VectorScene", "LinearTransformationScene"] -from typing import Callable +from typing import TYPE_CHECKING, Callable import numpy as np @@ -41,6 +41,14 @@ from ..utils.rate_functions import rush_from, rush_into from ..utils.space_ops import angle_of_vector +if TYPE_CHECKING: + from typing import Any + + from typing_extensions import Self + + from manim.typing import InternalPoint3D + + X_COLOR = GREEN_C Y_COLOR = RED_C Z_COLOR = BLUE_D @@ -53,11 +61,11 @@ # Also, methods I would have thought of as getters, like coords_to_vector, are # actually doing a lot of animating. class VectorScene(Scene): - def __init__(self, basis_vector_stroke_width=6, **kwargs): + def __init__(self, basis_vector_stroke_width: int = 6, **kwargs: Any) -> None: super().__init__(**kwargs) self.basis_vector_stroke_width = basis_vector_stroke_width - def add_plane(self, animate: bool = False, **kwargs): + def add_plane(self, animate: bool = False, **kwargs: Any) -> NumberPlane: """ Adds a NumberPlane object to the background. @@ -79,7 +87,9 @@ def add_plane(self, animate: bool = False, **kwargs): self.add(plane) return plane - def add_axes(self, animate: bool = False, color: bool = WHITE, **kwargs): + def add_axes( + self, animate: bool = False, color: bool = WHITE, **kwargs: Any + ) -> Axes: """ Adds a pair of Axes to the Scene. @@ -96,7 +106,9 @@ def add_axes(self, animate: bool = False, color: bool = WHITE, **kwargs): self.add(axes) return axes - def lock_in_faded_grid(self, dimness: float = 0.7, axes_dimness: float = 0.5): + def lock_in_faded_grid( + self, dimness: float = 0.7, axes_dimness: float = 0.5 + ) -> None: """ This method freezes the NumberPlane and Axes that were already in the background, and adds new, manipulatable ones to the foreground. @@ -120,7 +132,9 @@ def lock_in_faded_grid(self, dimness: float = 0.7, axes_dimness: float = 0.5): self.renderer.camera = Camera(self.renderer.get_frame()) self.clear() - def get_vector(self, numerical_vector: np.ndarray | list | tuple, **kwargs): + def get_vector( + self, numerical_vector: np.ndarray | list | tuple, **kwargs: Any + ) -> Arrow: """ Returns an arrow on the Plane given an input numerical vector. @@ -148,8 +162,8 @@ def add_vector( vector: Arrow | list | tuple | np.ndarray, color: str = YELLOW, animate: bool = True, - **kwargs, - ): + **kwargs: Any, + ) -> Vector: """ Returns the Vector after adding it to the Plane. @@ -185,7 +199,7 @@ def add_vector( self.add(vector) return vector - def write_vector_coordinates(self, vector: Arrow, **kwargs): + def write_vector_coordinates(self, vector: Arrow, **kwargs: Any) -> Matrix: """ Returns a column matrix indicating the vector coordinates, after writing them to the screen. @@ -207,7 +221,9 @@ def write_vector_coordinates(self, vector: Arrow, **kwargs): self.play(Write(coords)) return coords - def get_basis_vectors(self, i_hat_color: str = X_COLOR, j_hat_color: str = Y_COLOR): + def get_basis_vectors( + self, i_hat_color: str = X_COLOR, j_hat_color: str = Y_COLOR + ) -> VGroup: """ Returns a VGroup of the Basis Vectors (1,0) and (0,1) @@ -231,7 +247,7 @@ def get_basis_vectors(self, i_hat_color: str = X_COLOR, j_hat_color: str = Y_COL ) ) - def get_basis_vector_labels(self, **kwargs): + def get_basis_vector_labels(self, **kwargs: Any) -> VGroup: """ Returns naming labels for the basis vectors. @@ -263,13 +279,13 @@ def get_basis_vector_labels(self, **kwargs): def get_vector_label( self, vector: Vector, - label, + label: Any, at_tip: bool = False, direction: str = "left", rotate: bool = False, color: str | None = None, label_scale_factor: float = LARGE_BUFF - 0.2, - ): + ) -> MathTex: """ Returns naming labels for the passed vector. @@ -322,8 +338,8 @@ def get_vector_label( return label def label_vector( - self, vector: Vector, label: MathTex | str, animate: bool = True, **kwargs - ): + self, vector: Vector, label: MathTex | str, animate: bool = True, **kwargs: Any + ) -> MathTex: """ Shortcut method for creating, and animating the addition of a label for the vector. @@ -355,20 +371,20 @@ def label_vector( def position_x_coordinate( self, - x_coord, - x_line, - vector, - ): # TODO Write DocStrings for this. + x_coord: Any, + x_line: Line, + vector: InternalPoint3D, + ) -> Any: # TODO Write DocStrings for this. x_coord.next_to(x_line, -np.sign(vector[1]) * UP) x_coord.set_color(X_COLOR) return x_coord def position_y_coordinate( self, - y_coord, - y_line, - vector, - ): # TODO Write DocStrings for this. + y_coord: Any, + y_line: Line, + vector: InternalPoint3D, + ) -> Any: # TODO Write DocStrings for this. y_coord.next_to(y_line, np.sign(vector[0]) * RIGHT) y_coord.set_color(Y_COLOR) return y_coord @@ -378,7 +394,7 @@ def coords_to_vector( vector: np.ndarray | list | tuple, coords_start: np.ndarray | list | tuple = 2 * RIGHT + 2 * UP, clean_up: bool = True, - ): + ) -> None: """ This method writes the vector as a column matrix (henceforth called the label), takes the values in it one by one, and form the corresponding @@ -441,7 +457,7 @@ def vector_to_coords( vector: np.ndarray | list | tuple, integer_labels: bool = True, clean_up: bool = True, - ): + ) -> tuple[Matrix, Line, Line]: """ This method displays vector as a Vector() based vector, and then shows the corresponding lines that make up the x and y components of the vector. @@ -499,7 +515,7 @@ def vector_to_coords( self.add(*starting_mobjects) return array, x_line, y_line - def show_ghost_movement(self, vector: Arrow | list | tuple | np.ndarray): + def show_ghost_movement(self, vector: Arrow | list | tuple | np.ndarray) -> None: """ This method plays an animation that partially shows the entire plane moving in the direction of a particular vector. This is useful when you wish to @@ -593,8 +609,8 @@ def __init__( i_hat_color: ParsableManimColor = X_COLOR, j_hat_color: ParsableManimColor = Y_COLOR, leave_ghost_vectors: bool = False, - **kwargs, - ): + **kwargs: Any, + ) -> None: super().__init__(**kwargs) self.include_background_plane = include_background_plane @@ -630,12 +646,12 @@ def __init__( ) @staticmethod - def update_default_configs(default_configs, passed_configs): + def update_default_configs(default_configs: Any, passed_configs: Any) -> None: for default_config, passed_config in zip(default_configs, passed_configs): if passed_config is not None: update_dict_recursively(default_config, passed_config) - def setup(self): + def setup(self) -> None: # The has_already_setup attr is to not break all the old Scenes if hasattr(self, "has_already_setup"): return @@ -665,7 +681,7 @@ def setup(self): self.i_hat, self.j_hat = self.basis_vectors self.add(self.basis_vectors) - def add_special_mobjects(self, mob_list: list, *mobs_to_add: Mobject): + def add_special_mobjects(self, mob_list: list, *mobs_to_add: Mobject) -> None: """ Adds mobjects to a separate list that can be tracked, if these mobjects have some extra importance. @@ -685,7 +701,7 @@ def add_special_mobjects(self, mob_list: list, *mobs_to_add: Mobject): mob_list.append(mobject) self.add(mobject) - def add_background_mobject(self, *mobjects: Mobject): + def add_background_mobject(self, *mobjects: Mobject) -> None: """ Adds the mobjects to the special list self.background_mobjects. @@ -698,7 +714,7 @@ def add_background_mobject(self, *mobjects: Mobject): self.add_special_mobjects(self.background_mobjects, *mobjects) # TODO, this conflicts with Scene.add_fore - def add_foreground_mobject(self, *mobjects: Mobject): + def add_foreground_mobject(self, *mobjects: Mobject) -> None: """ Adds the mobjects to the special list self.foreground_mobjects. @@ -710,7 +726,7 @@ def add_foreground_mobject(self, *mobjects: Mobject): """ self.add_special_mobjects(self.foreground_mobjects, *mobjects) - def add_transformable_mobject(self, *mobjects: Mobject): + def add_transformable_mobject(self, *mobjects: Mobject) -> None: """ Adds the mobjects to the special list self.transformable_mobjects. @@ -724,7 +740,7 @@ def add_transformable_mobject(self, *mobjects: Mobject): def add_moving_mobject( self, mobject: Mobject, target_mobject: Mobject | None = None - ): + ) -> None: """ Adds the mobject to the special list self.moving_mobject, and adds a property @@ -752,7 +768,7 @@ def get_ghost_vectors(self) -> VGroup: def get_unit_square( self, color: str = YELLOW, opacity: float = 0.3, stroke_width: float = 3 - ): + ) -> Rectangle: """ Returns a unit square for the current NumberPlane. @@ -783,7 +799,7 @@ def get_unit_square( square.move_to(self.plane.coords_to_point(0, 0), DL) return square - def add_unit_square(self, animate: bool = False, **kwargs): + def add_unit_square(self, animate: bool = False, **kwargs: Any) -> Self: """ Adds a unit square to the scene via self.get_unit_square. @@ -814,8 +830,11 @@ def add_unit_square(self, animate: bool = False, **kwargs): return self def add_vector( - self, vector: Arrow | list | tuple | np.ndarray, color: str = YELLOW, **kwargs - ): + self, + vector: Arrow | list | tuple | np.ndarray, + color: str = YELLOW, + **kwargs: Any, + ) -> Vector: """ Adds a vector to the scene, and puts it in the special list self.moving_vectors. @@ -843,7 +862,7 @@ def add_vector( self.moving_vectors.append(vector) return vector - def write_vector_coordinates(self, vector: Arrow, **kwargs): + def write_vector_coordinates(self, vector: Arrow, **kwargs: Any) -> Matrix: """ Returns a column matrix indicating the vector coordinates, after writing them to the screen, and adding them to the @@ -872,8 +891,8 @@ def add_transformable_label( label: MathTex | str, transformation_name: str | MathTex = "L", new_label: str | MathTex | None = None, - **kwargs, - ): + **kwargs: Any, + ) -> MathTex: """ Method for creating, and animating the addition of a transformable label for the vector. @@ -919,7 +938,7 @@ def add_title( title: str | MathTex | Tex, scale_factor: float = 1.5, animate: bool = False, - ): + ) -> Self: """ Adds a title, after scaling it, adding a background rectangle, moving it to the top and adding it to foreground_mobjects adding @@ -951,7 +970,7 @@ def add_title( self.title = title return self - def get_matrix_transformation(self, matrix: np.ndarray | list | tuple): + def get_matrix_transformation(self, matrix: np.ndarray | list | tuple) -> Any: """ Returns a function corresponding to the linear transformation represented by the matrix passed. @@ -965,7 +984,7 @@ def get_matrix_transformation(self, matrix: np.ndarray | list | tuple): def get_transposed_matrix_transformation( self, transposed_matrix: np.ndarray | list | tuple - ): + ) -> Callable: """ Returns a function corresponding to the linear transformation represented by the transposed @@ -985,7 +1004,7 @@ def get_transposed_matrix_transformation( raise ValueError("Matrix has bad dimensions") return lambda point: np.dot(point, transposed_matrix) - def get_piece_movement(self, pieces: list | tuple | np.ndarray): + def get_piece_movement(self, pieces: list | tuple | np.ndarray) -> Transform: """ This method returns an animation that moves an arbitrary mobject in "pieces" to its corresponding .target value. @@ -1013,7 +1032,9 @@ def get_piece_movement(self, pieces: list | tuple | np.ndarray): self.add(self.ghost_vectors[-1]) return Transform(start, target, lag_ratio=0) - def get_moving_mobject_movement(self, func: Callable[[np.ndarray], np.ndarray]): + def get_moving_mobject_movement( + self, func: Callable[[np.ndarray], np.ndarray] + ) -> Animation: """ This method returns an animation that moves a mobject in "self.moving_mobjects" to its corresponding .target value. @@ -1038,7 +1059,9 @@ def get_moving_mobject_movement(self, func: Callable[[np.ndarray], np.ndarray]): m.target.move_to(target_point) return self.get_piece_movement(self.moving_mobjects) - def get_vector_movement(self, func: Callable[[np.ndarray], np.ndarray]): + def get_vector_movement( + self, func: Callable[[np.ndarray], np.ndarray] + ) -> Animation: """ This method returns an animation that moves a mobject in "self.moving_vectors" to its corresponding .target value. @@ -1063,7 +1086,7 @@ def get_vector_movement(self, func: Callable[[np.ndarray], np.ndarray]): v.target.get_tip().scale(norm) return self.get_piece_movement(self.moving_vectors) - def get_transformable_label_movement(self): + def get_transformable_label_movement(self) -> Animation: """ This method returns an animation that moves all labels in "self.transformable_labels" to its corresponding .target . @@ -1079,7 +1102,7 @@ def get_transformable_label_movement(self): ) return self.get_piece_movement(self.transformable_labels) - def apply_matrix(self, matrix: np.ndarray | list | tuple, **kwargs): + def apply_matrix(self, matrix: np.ndarray | list | tuple, **kwargs: Any) -> None: """ Applies the transformation represented by the given matrix to the number plane, and each vector/similar @@ -1094,7 +1117,7 @@ def apply_matrix(self, matrix: np.ndarray | list | tuple, **kwargs): """ self.apply_transposed_matrix(np.array(matrix).T, **kwargs) - def apply_inverse(self, matrix: np.ndarray | list | tuple, **kwargs): + def apply_inverse(self, matrix: np.ndarray | list | tuple, **kwargs: Any) -> None: """ This method applies the linear transformation represented by the inverse of the passed matrix @@ -1110,8 +1133,8 @@ def apply_inverse(self, matrix: np.ndarray | list | tuple, **kwargs): self.apply_matrix(np.linalg.inv(matrix), **kwargs) def apply_transposed_matrix( - self, transposed_matrix: np.ndarray | list | tuple, **kwargs - ): + self, transposed_matrix: np.ndarray | list | tuple, **kwargs: Any + ) -> Any: """ Applies the transformation represented by the given transposed matrix to the number plane, @@ -1132,7 +1155,9 @@ def apply_transposed_matrix( kwargs["path_arc"] = net_rotation self.apply_function(func, **kwargs) - def apply_inverse_transpose(self, t_matrix: np.ndarray | list | tuple, **kwargs): + def apply_inverse_transpose( + self, t_matrix: np.ndarray | list | tuple, **kwargs: Any + ) -> None: """ Applies the inverse of the transformation represented by the given transposed matrix to the number plane and each @@ -1149,8 +1174,8 @@ def apply_inverse_transpose(self, t_matrix: np.ndarray | list | tuple, **kwargs) self.apply_transposed_matrix(t_inv, **kwargs) def apply_nonlinear_transformation( - self, function: Callable[[np.ndarray], np.ndarray], **kwargs - ): + self, function: Callable[[np.ndarray], np.ndarray], **kwargs: Any + ) -> None: """ Applies the non-linear transformation represented by the given function to the number plane and each @@ -1170,8 +1195,8 @@ def apply_function( self, function: Callable[[np.ndarray], np.ndarray], added_anims: list = [], - **kwargs, - ): + **kwargs: Any, + ) -> None: """ Applies the given function to each of the mobjects in self.transformable_mobjects, and plays the animation showing From 8d6d9c430d7eaae05c666f09e8bae281e2c74bd4 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Wed, 23 Oct 2024 08:10:41 +0200 Subject: [PATCH 21/45] Get rid of no-untyped-call errors from my in the vector_space_scene.py file Error count: 272 -> 343 --- manim/mobject/matrix.py | 6 +++--- manim/mobject/text/tex_mobject.py | 20 ++++++++++++++------ manim/scene/scene.py | 16 +++++++++------- manim/utils/config_ops.py | 2 +- 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/manim/mobject/matrix.py b/manim/mobject/matrix.py index e506bc4528..490818c28a 100644 --- a/manim/mobject/matrix.py +++ b/manim/mobject/matrix.py @@ -400,7 +400,7 @@ def add_background_to_entries(self): mob.add_background_rectangle() return self - def get_mob_matrix(self): + def get_mob_matrix(self) -> VGroup: """Return the underlying mob matrix mobjects. Returns @@ -410,7 +410,7 @@ def get_mob_matrix(self): """ return self.mob_matrix - def get_entries(self): + def get_entries(self) -> VGroup: """Return the individual entries of the matrix. Returns @@ -435,7 +435,7 @@ def construct(self): """ return self.elements - def get_brackets(self): + def get_brackets(self) -> VGroup: r"""Return the bracket mobjects. Returns diff --git a/manim/mobject/text/tex_mobject.py b/manim/mobject/text/tex_mobject.py index 26334a60d9..22a4811960 100644 --- a/manim/mobject/text/tex_mobject.py +++ b/manim/mobject/text/tex_mobject.py @@ -29,6 +29,7 @@ from collections.abc import Iterable from functools import reduce from textwrap import dedent +from typing import TYPE_CHECKING from manim import config, logger from manim.constants import * @@ -38,6 +39,9 @@ from manim.utils.tex import TexTemplate from manim.utils.tex_file_writing import tex_to_svg_file +if TYPE_CHECKING: + from typing_extensions import Any + tex_string_to_mob_map = {} @@ -206,7 +210,7 @@ def _organize_submobjects_left_to_right(self): self.sort(lambda p: p[0]) return self - def get_tex_string(self): + def get_tex_string(self) -> str: return self.tex_string def init_colors(self, propagate_colors=True): @@ -255,13 +259,13 @@ def construct(self): def __init__( self, - *tex_strings, + *tex_strings: str, arg_separator: str = " ", substrings_to_isolate: Iterable[str] | None = None, tex_to_color_map: dict[str, ManimColor] = None, tex_environment: str = "align*", - **kwargs, - ): + **kwargs: Any, + ) -> None: self.tex_template = kwargs.pop("tex_template", config["tex_template"]) self.arg_separator = arg_separator self.substrings_to_isolate = ( @@ -447,8 +451,12 @@ class Tex(MathTex): """ def __init__( - self, *tex_strings, arg_separator="", tex_environment="center", **kwargs - ): + self, + *tex_strings: str, + arg_separator: str = "", + tex_environment: str = "center", + **kwargs: Any, + ) -> None: super().__init__( *tex_strings, arg_separator=arg_separator, diff --git a/manim/scene/scene.py b/manim/scene/scene.py index 02c548cf7f..768cdcb945 100644 --- a/manim/scene/scene.py +++ b/manim/scene/scene.py @@ -55,6 +55,8 @@ from collections.abc import Iterable, Sequence from typing import Callable + from typing_extensions import Self + class RerunSceneHandler(FileSystemEventHandler): """A class to handle rerunning a Scene after the input file is modified.""" @@ -100,12 +102,12 @@ def construct(self): def __init__( self, - renderer=None, - camera_class=Camera, - always_update_mobjects=False, - random_seed=None, - skip_animations=False, - ): + renderer: bool = None, + camera_class: type[Camera] = Camera, + always_update_mobjects: bool = False, + random_seed: bool = None, + skip_animations: bool = False, + ) -> None: self.camera_class = camera_class self.always_update_mobjects = always_update_mobjects self.random_seed = random_seed @@ -806,7 +808,7 @@ def bring_to_back(self, *mobjects: Mobject): self.mobjects = list(mobjects) + self.mobjects return self - def clear(self): + def clear(self) -> Self: """ Removes all mobjects present in self.mobjects and self.foreground_mobjects from the scene. diff --git a/manim/utils/config_ops.py b/manim/utils/config_ops.py index 6e1f09990e..cdd9c8e9f5 100644 --- a/manim/utils/config_ops.py +++ b/manim/utils/config_ops.py @@ -34,7 +34,7 @@ def merge_dicts_recursively(*dicts): return result -def update_dict_recursively(current_dict, *others): +def update_dict_recursively(current_dict, *others: dict) -> None: updated_dict = merge_dicts_recursively(current_dict, *others) current_dict.update(updated_dict) From e2284b1cead80e6dff765befe77eadcb57083dc1 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Wed, 23 Oct 2024 08:38:28 +0200 Subject: [PATCH 22/45] Handle type issues related to ManimColor in vector_space_scene.py --- manim/scene/vector_space_scene.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/manim/scene/vector_space_scene.py b/manim/scene/vector_space_scene.py index bf79d5c4c5..5a24f817f8 100644 --- a/manim/scene/vector_space_scene.py +++ b/manim/scene/vector_space_scene.py @@ -88,7 +88,7 @@ def add_plane(self, animate: bool = False, **kwargs: Any) -> NumberPlane: return plane def add_axes( - self, animate: bool = False, color: bool = WHITE, **kwargs: Any + self, animate: bool = False, color: ParsableManimColor = WHITE, **kwargs: Any ) -> Axes: """ Adds a pair of Axes to the Scene. @@ -160,7 +160,7 @@ def get_vector( def add_vector( self, vector: Arrow | list | tuple | np.ndarray, - color: str = YELLOW, + color: ParsableManimColor = YELLOW, animate: bool = True, **kwargs: Any, ) -> Vector: @@ -222,7 +222,9 @@ def write_vector_coordinates(self, vector: Arrow, **kwargs: Any) -> Matrix: return coords def get_basis_vectors( - self, i_hat_color: str = X_COLOR, j_hat_color: str = Y_COLOR + self, + i_hat_color: ParsableManimColor = X_COLOR, + j_hat_color: ParsableManimColor = Y_COLOR, ) -> VGroup: """ Returns a VGroup of the Basis Vectors (1,0) and (0,1) @@ -283,7 +285,7 @@ def get_vector_label( at_tip: bool = False, direction: str = "left", rotate: bool = False, - color: str | None = None, + color: ParsableManimColor | None = None, label_scale_factor: float = LARGE_BUFF - 0.2, ) -> MathTex: """ @@ -767,7 +769,10 @@ def get_ghost_vectors(self) -> VGroup: return self.ghost_vectors def get_unit_square( - self, color: str = YELLOW, opacity: float = 0.3, stroke_width: float = 3 + self, + color: ParsableManimColor = YELLOW, + opacity: float = 0.3, + stroke_width: float = 3, ) -> Rectangle: """ Returns a unit square for the current NumberPlane. @@ -832,7 +837,7 @@ def add_unit_square(self, animate: bool = False, **kwargs: Any) -> Self: def add_vector( self, vector: Arrow | list | tuple | np.ndarray, - color: str = YELLOW, + color: ParsableManimColor = YELLOW, **kwargs: Any, ) -> Vector: """ From bfe61b03215d2065e458da80702fa16a071603ec Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Wed, 23 Oct 2024 20:23:36 +0200 Subject: [PATCH 23/45] Handle var-annotated issues in vector_space_scene.py Error count: 332 -> 330 --- manim/scene/vector_space_scene.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/manim/scene/vector_space_scene.py b/manim/scene/vector_space_scene.py index 5a24f817f8..4c9a3beab1 100644 --- a/manim/scene/vector_space_scene.py +++ b/manim/scene/vector_space_scene.py @@ -657,13 +657,13 @@ def setup(self) -> None: # The has_already_setup attr is to not break all the old Scenes if hasattr(self, "has_already_setup"): return - self.has_already_setup = True - self.background_mobjects = [] - self.foreground_mobjects = [] - self.transformable_mobjects = [] + self.has_already_setup: bool = True + self.background_mobjects: list[Mobject] = [] + self.foreground_mobjects: list[Mobject] = [] + self.transformable_mobjects: list[Mobject] = [] self.moving_vectors = [] - self.transformable_labels = [] - self.moving_mobjects = [] + self.transformable_labels: list[Mobject] = [] + self.moving_mobjects: list[Mobject] = [] self.background_plane = NumberPlane(**self.background_plane_kwargs) From eae22965d2b67a31f8b2c9f99e4255b229f79118 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Wed, 23 Oct 2024 20:39:53 +0200 Subject: [PATCH 24/45] Handling has-type type errors in vector_space_scene.py Error count: 330 -> 285 --- manim/scene/scene.py | 6 +++--- manim/scene/vector_space_scene.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/manim/scene/scene.py b/manim/scene/scene.py index 768cdcb945..58c4f42316 100644 --- a/manim/scene/scene.py +++ b/manim/scene/scene.py @@ -141,7 +141,7 @@ def __init__( renderer = OpenGLRenderer() if renderer is None: - self.renderer = CairoRenderer( + self.renderer: CairoRenderer | OpenGLRenderer = CairoRenderer( camera_class=self.camera_class, skip_animations=self.skip_animations, ) @@ -149,9 +149,9 @@ def __init__( self.renderer = renderer self.renderer.init_scene(self) - self.mobjects = [] + self.mobjects: list[Mobject] = [] # TODO, remove need for foreground mobjects - self.foreground_mobjects = [] + self.foreground_mobjects: list[Mobject] = [] if self.random_seed is not None: random.seed(self.random_seed) np.random.seed(self.random_seed) diff --git a/manim/scene/vector_space_scene.py b/manim/scene/vector_space_scene.py index 4c9a3beab1..7fc92d3b66 100644 --- a/manim/scene/vector_space_scene.py +++ b/manim/scene/vector_space_scene.py @@ -419,7 +419,7 @@ def coords_to_vector( this method did after it's done. """ - starting_mobjects = list(self.mobjects) + starting_mobjects: list[Mobject] = list(self.mobjects) array = Matrix(vector) array.shift(coords_start) arrow = Vector(vector) @@ -480,7 +480,7 @@ def vector_to_coords( this method did after it's done. """ - starting_mobjects = list(self.mobjects) + starting_mobjects: list[Mobject] = list(self.mobjects) show_creation = False if isinstance(vector, Arrow): arrow = vector From 9dd785a9f6292a2c753d528c0dce3024b23ffcd4 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Wed, 23 Oct 2024 21:10:40 +0200 Subject: [PATCH 25/45] Handled name-defined type issues in vector_space_scene.py Error count: 285 -> 282 --- manim/scene/vector_space_scene.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/manim/scene/vector_space_scene.py b/manim/scene/vector_space_scene.py index 7fc92d3b66..f5fb87a7b9 100644 --- a/manim/scene/vector_space_scene.py +++ b/manim/scene/vector_space_scene.py @@ -18,13 +18,14 @@ from .. import config from ..animation.animation import Animation -from ..animation.creation import Create, Write +from ..animation.creation import Create, DrawBorderThenFill, Write from ..animation.fading import FadeOut from ..animation.growing import GrowArrow from ..animation.transform import ApplyFunction, ApplyPointwiseFunction, Transform +from ..camera.camera import Camera from ..constants import * from ..mobject.matrix import Matrix -from ..mobject.mobject import Mobject +from ..mobject.mobject import Group, Mobject from ..mobject.types.vectorized_mobject import VGroup, VMobject from ..scene.scene import Scene from ..utils.color import ( @@ -419,7 +420,7 @@ def coords_to_vector( this method did after it's done. """ - starting_mobjects: list[Mobject] = list(self.mobjects) + starting_mobjects = list(self.mobjects) array = Matrix(vector) array.shift(coords_start) arrow = Vector(vector) @@ -480,7 +481,7 @@ def vector_to_coords( this method did after it's done. """ - starting_mobjects: list[Mobject] = list(self.mobjects) + starting_mobjects = list(self.mobjects) show_creation = False if isinstance(vector, Arrow): arrow = vector From 822dba222e5f6df39a3670f2dc53f46f76ff24f8 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Thu, 24 Oct 2024 08:51:01 +0200 Subject: [PATCH 26/45] Address type issue with calling an untyped method. Error count: 282 -> 281 --- manim/renderer/cairo_renderer.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/manim/renderer/cairo_renderer.py b/manim/renderer/cairo_renderer.py index b97fa50299..991e02f0e4 100644 --- a/manim/renderer/cairo_renderer.py +++ b/manim/renderer/cairo_renderer.py @@ -18,6 +18,8 @@ from collections.abc import Iterable from typing import Any + import numpy.typing as npt + from manim.animation.animation import Animation from manim.scene.scene import Scene @@ -119,12 +121,12 @@ def play( def update_frame( # TODO Description in Docstring self, - scene, + scene: Scene, mobjects: typing.Iterable[Mobject] | None = None, include_submobjects: bool = True, ignore_skipping: bool = True, - **kwargs, - ): + **kwargs: Any, + ) -> None: """Update the frame. Parameters @@ -160,7 +162,7 @@ def render(self, scene, time, moving_mobjects): self.update_frame(scene, moving_mobjects) self.add_frame(self.get_frame()) - def get_frame(self): + def get_frame(self) -> npt.NDArray: """ Gets the current frame as NumPy array. From 501d774e3848e3629a85c3da99089544dae5d33c Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Thu, 24 Oct 2024 08:51:31 +0200 Subject: [PATCH 27/45] Fix some typing issues in transform_mathcing_parts.py --- manim/animation/transform_matching_parts.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/manim/animation/transform_matching_parts.py b/manim/animation/transform_matching_parts.py index dbf5dd294e..44396ea42c 100644 --- a/manim/animation/transform_matching_parts.py +++ b/manim/animation/transform_matching_parts.py @@ -20,6 +20,8 @@ from .transform import FadeTransformPieces, Transform if TYPE_CHECKING: + from typing import Any + from ..scene.scene import Scene @@ -74,7 +76,7 @@ def __init__( transform_mismatches: bool = False, fade_transform_mismatches: bool = False, key_map: dict | None = None, - **kwargs, + **kwargs: Any, ): if isinstance(mobject, OpenGLVMobject): group_type = OpenGLVGroup @@ -162,11 +164,11 @@ def clean_up_from_scene(self, scene: Scene) -> None: scene.add(self.to_add) @staticmethod - def get_mobject_parts(mobject: Mobject): + def get_mobject_parts(mobject: Mobject) -> None: raise NotImplementedError("To be implemented in subclass.") @staticmethod - def get_mobject_key(mobject: Mobject): + def get_mobject_key(mobject: Mobject) -> None: raise NotImplementedError("To be implemented in subclass.") @@ -206,7 +208,7 @@ def __init__( transform_mismatches: bool = False, fade_transform_mismatches: bool = False, key_map: dict | None = None, - **kwargs, + **kwargs: Any, ): super().__init__( mobject, @@ -269,7 +271,7 @@ def __init__( transform_mismatches: bool = False, fade_transform_mismatches: bool = False, key_map: dict | None = None, - **kwargs, + **kwargs: Any, ): super().__init__( mobject, From fa9cad9137b3945ebe694c3d515170e04c7ad1ea Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Thu, 24 Oct 2024 08:51:59 +0200 Subject: [PATCH 28/45] Change stroke_width to float in vector_space_scene.py --- manim/scene/vector_space_scene.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manim/scene/vector_space_scene.py b/manim/scene/vector_space_scene.py index f5fb87a7b9..a6e1a92770 100644 --- a/manim/scene/vector_space_scene.py +++ b/manim/scene/vector_space_scene.py @@ -62,7 +62,7 @@ # Also, methods I would have thought of as getters, like coords_to_vector, are # actually doing a lot of animating. class VectorScene(Scene): - def __init__(self, basis_vector_stroke_width: int = 6, **kwargs: Any) -> None: + def __init__(self, basis_vector_stroke_width: float = 6, **kwargs: Any) -> None: super().__init__(**kwargs) self.basis_vector_stroke_width = basis_vector_stroke_width From 99c12c0b33cdc0453126e7c8224b1edc69fef8ee Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Thu, 24 Oct 2024 13:28:07 +0200 Subject: [PATCH 29/45] Handled a few type errors. Error count: 267 --- manim/scene/vector_space_scene.py | 35 ++++++++++++++++++------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/manim/scene/vector_space_scene.py b/manim/scene/vector_space_scene.py index a6e1a92770..b3f57026b5 100644 --- a/manim/scene/vector_space_scene.py +++ b/manim/scene/vector_space_scene.py @@ -164,7 +164,7 @@ def add_vector( color: ParsableManimColor = YELLOW, animate: bool = True, **kwargs: Any, - ) -> Vector: + ) -> Arrow: """ Returns the Vector after adding it to the Plane. @@ -218,7 +218,7 @@ def write_vector_coordinates(self, vector: Arrow, **kwargs: Any) -> Matrix: :class:`.Matrix` The column matrix representing the vector. """ - coords = vector.coordinate_label(**kwargs) + coords: Matrix = vector.coordinate_label(**kwargs) self.play(Write(coords)) return coords @@ -282,7 +282,7 @@ def get_basis_vector_labels(self, **kwargs: Any) -> VGroup: def get_vector_label( self, vector: Vector, - label: Any, + label: MathTex | str, at_tip: bool = False, direction: str = "left", rotate: bool = False, @@ -333,9 +333,11 @@ def get_vector_label( if not rotate: label.rotate(-angle, about_point=ORIGIN) if direction == "left": - label.shift(-label.get_bottom() + 0.1 * UP) + temp_shift_1: InternalPoint3D = label.get_bottom() + label.shift(-temp_shift_1 + 0.1 * UP) else: - label.shift(-label.get_top() + 0.1 * DOWN) + temp_shift_2: InternalPoint3D = label.get_top() + label.shift(-temp_shift_2 + 0.1 * DOWN) label.rotate(angle, about_point=ORIGIN) label.shift((vector.get_end() - vector.get_start()) / 2) return label @@ -394,8 +396,8 @@ def position_y_coordinate( def coords_to_vector( self, - vector: np.ndarray | list | tuple, - coords_start: np.ndarray | list | tuple = 2 * RIGHT + 2 * UP, + vector: InternalPoint3D, + coords_start: InternalPoint3D = 2 * RIGHT + 2 * UP, clean_up: bool = True, ) -> None: """ @@ -457,7 +459,7 @@ def coords_to_vector( def vector_to_coords( self, - vector: np.ndarray | list | tuple, + vector: InternalPoint3D, integer_labels: bool = True, clean_up: bool = True, ) -> tuple[Matrix, Line, Line]: @@ -518,7 +520,7 @@ def vector_to_coords( self.add(*starting_mobjects) return array, x_line, y_line - def show_ghost_movement(self, vector: Arrow | list | tuple | np.ndarray) -> None: + def show_ghost_movement(self, vector: InternalPoint3D | Arrow) -> None: """ This method plays an animation that partially shows the entire plane moving in the direction of a particular vector. This is useful when you wish to @@ -663,7 +665,7 @@ def setup(self) -> None: self.foreground_mobjects: list[Mobject] = [] self.transformable_mobjects: list[Mobject] = [] self.moving_vectors = [] - self.transformable_labels: list[Mobject] = [] + self.transformable_labels: list[MathTex] = [] self.moving_mobjects: list[Mobject] = [] self.background_plane = NumberPlane(**self.background_plane_kwargs) @@ -839,8 +841,9 @@ def add_vector( self, vector: Arrow | list | tuple | np.ndarray, color: ParsableManimColor = YELLOW, + animate: bool = True, **kwargs: Any, - ) -> Vector: + ) -> Arrow: """ Adds a vector to the scene, and puts it in the special list self.moving_vectors. @@ -864,7 +867,7 @@ def add_vector( Arrow The arrow representing the vector. """ - vector = super().add_vector(vector, color=color, **kwargs) + vector = super().add_vector(vector, color=color, animate=animate, **kwargs) self.moving_vectors.append(vector) return vector @@ -1061,7 +1064,8 @@ def get_moving_mobject_movement( for m in self.moving_mobjects: if m.target is None: m.target = m.copy() - target_point = func(m.get_center()) + temp: InternalPoint3D = m.get_center() # type: ignore[assignment] + target_point = func(temp) m.target.move_to(target_point) return self.get_piece_movement(self.moving_mobjects) @@ -1087,7 +1091,7 @@ def get_vector_movement( """ for v in self.moving_vectors: v.target = Vector(func(v.get_end()), color=v.get_color()) - norm = np.linalg.norm(v.target.get_end()) + norm = float(np.linalg.norm(v.target.get_end())) if norm < 0.1: v.target.get_tip().scale(norm) return self.get_piece_movement(self.moving_vectors) @@ -1103,8 +1107,9 @@ def get_transformable_label_movement(self) -> Animation: The animation of the movement. """ for label in self.transformable_labels: + target_text: MathTex | str = label.target_text label.target = self.get_vector_label( - label.vector.target, label.target_text, **label.kwargs + label.vector.target, target_text, **label.kwargs ) return self.get_piece_movement(self.transformable_labels) From dee6ef93303a1f1aeb418f50d4ef5b7164d98285 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Thu, 24 Oct 2024 14:07:05 +0200 Subject: [PATCH 30/45] Handled several typing issues in three_d_scene.py Error count: 267 -> 248 --- manim/mobject/value_tracker.py | 9 +++- manim/scene/scene.py | 2 +- manim/scene/three_d_scene.py | 94 +++++++++++++++++++--------------- manim/utils/config_ops.py | 6 ++- 4 files changed, 67 insertions(+), 44 deletions(-) diff --git a/manim/mobject/value_tracker.py b/manim/mobject/value_tracker.py index 9d81035e89..2d65e903d6 100644 --- a/manim/mobject/value_tracker.py +++ b/manim/mobject/value_tracker.py @@ -5,12 +5,17 @@ __all__ = ["ValueTracker", "ComplexValueTracker"] +from typing import TYPE_CHECKING + import numpy as np from manim.mobject.mobject import Mobject from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL from manim.utils.paths import straight_path +if TYPE_CHECKING: + from typing_extensions import Any, Self + class ValueTracker(Mobject, metaclass=ConvertToOpenGL): """A mobject that can be used for tracking (real-valued) parameters. @@ -69,7 +74,7 @@ def construct(self): """ - def __init__(self, value=0, **kwargs): + def __init__(self, value: float = 0, **kwargs: Any) -> None: super().__init__(**kwargs) self.set(points=np.zeros((1, 3))) self.set_value(value) @@ -78,7 +83,7 @@ def get_value(self) -> float: """Get the current value of this ValueTracker.""" return self.points[0, 0] - def set_value(self, value: float): + def set_value(self, value: float) -> Self: """Sets a new scalar value to the ValueTracker""" self.points[0, 0] = value return self diff --git a/manim/scene/scene.py b/manim/scene/scene.py index 58c4f42316..2b50f93688 100644 --- a/manim/scene/scene.py +++ b/manim/scene/scene.py @@ -824,7 +824,7 @@ def clear(self) -> Self: self.foreground_mobjects = [] return self - def get_moving_mobjects(self, *animations: Animation): + def get_moving_mobjects(self, *animations: Animation) -> list[Mobject]: """ Gets all moving mobjects in the passed animation(s). diff --git a/manim/scene/three_d_scene.py b/manim/scene/three_d_scene.py index 7f39f4cf32..a74fafbb37 100644 --- a/manim/scene/three_d_scene.py +++ b/manim/scene/three_d_scene.py @@ -7,6 +7,8 @@ import warnings from collections.abc import Iterable, Sequence +from itertools import chain +from typing import TYPE_CHECKING import numpy as np @@ -27,6 +29,9 @@ from ..scene.scene import Scene from ..utils.config_ops import merge_dicts_recursively +if TYPE_CHECKING: + from typing_extensions import Any + class ThreeDScene(Scene): """ @@ -36,10 +41,10 @@ class ThreeDScene(Scene): def __init__( self, - camera_class=ThreeDCamera, - ambient_camera_rotation=None, - default_angled_camera_orientation_kwargs=None, - **kwargs, + camera_class: type[ThreeDCamera] = ThreeDCamera, + ambient_camera_rotation: Any = None, + default_angled_camera_orientation_kwargs: dict[str, Any] | None = None, + **kwargs: Any, ): self.ambient_camera_rotation = ambient_camera_rotation if default_angled_camera_orientation_kwargs is None: @@ -60,8 +65,8 @@ def set_camera_orientation( zoom: float | None = None, focal_distance: float | None = None, frame_center: Mobject | Sequence[float] | None = None, - **kwargs, - ): + **kwargs: Any, + ) -> None: """ This method sets the orientation of the camera in the scene. @@ -99,7 +104,9 @@ def set_camera_orientation( if frame_center is not None: self.renderer.camera._frame_center.move_to(frame_center) - def begin_ambient_camera_rotation(self, rate: float = 0.02, about: str = "theta"): + def begin_ambient_camera_rotation( + self, rate: float = 0.02, about: str = "theta" + ) -> None: """ This method begins an ambient rotation of the camera about the Z_AXIS, in the anticlockwise direction @@ -114,7 +121,7 @@ def begin_ambient_camera_rotation(self, rate: float = 0.02, about: str = "theta" """ # TODO, use a ValueTracker for rate, so that it # can begin and end smoothly - about: str = about.lower() + about = about.lower() try: if config.renderer == RendererType.CAIRO: trackers = { @@ -132,14 +139,18 @@ def begin_ambient_camera_rotation(self, rate: float = 0.02, about: str = "theta" "phi": cam.increment_phi, "gamma": cam.increment_gamma, } - cam.add_updater(lambda m, dt: methods[about](rate * dt)) + + def updater(m: Mobject, dt: float) -> None: + methods[about](rate * dt) + + cam.add_updater(updater) self.add(self.camera) except Exception as e: raise ValueError("Invalid ambient rotation angle.") from e - def stop_ambient_camera_rotation(self, about="theta"): + def stop_ambient_camera_rotation(self, about: str = "theta") -> None: """This method stops all ambient camera rotation.""" - about: str = about.lower() + about = about.lower() try: if config.renderer == RendererType.CAIRO: trackers = { @@ -160,7 +171,7 @@ def begin_3dillusion_camera_rotation( rate: float = 1, origin_phi: float | None = None, origin_theta: float | None = None, - ): + ) -> None: """ This method creates a 3D camera rotation illusion around the current camera orientation. @@ -183,7 +194,7 @@ def begin_3dillusion_camera_rotation( val_tracker_theta = ValueTracker(0) - def update_theta(m, dt): + def update_theta(m: ValueTracker, dt: float) -> ValueTracker: val_tracker_theta.increment_value(dt * rate) val_for_left_right = 0.2 * np.sin(val_tracker_theta.get_value()) return m.set_value(origin_theta + val_for_left_right) @@ -193,7 +204,7 @@ def update_theta(m, dt): val_tracker_phi = ValueTracker(0) - def update_phi(m, dt): + def update_phi(m: ValueTracker, dt: float) -> ValueTracker: val_tracker_phi.increment_value(dt * rate) val_for_up_down = 0.1 * np.cos(val_tracker_phi.get_value()) - 0.1 return m.set_value(origin_phi + val_for_up_down) @@ -201,7 +212,7 @@ def update_phi(m, dt): self.renderer.camera.phi_tracker.add_updater(update_phi) self.add(self.renderer.camera.phi_tracker) - def stop_3dillusion_camera_rotation(self): + def stop_3dillusion_camera_rotation(self) -> None: """This method stops all illusion camera rotations.""" self.renderer.camera.theta_tracker.clear_updaters() self.remove(self.renderer.camera.theta_tracker) @@ -217,8 +228,8 @@ def move_camera( focal_distance: float | None = None, frame_center: Mobject | Sequence[float] | None = None, added_anims: Iterable[Animation] = [], - **kwargs, - ): + **kwargs: Any, + ) -> None: """ This method animates the movement of the camera to the given spherical coordinates. @@ -300,7 +311,7 @@ def move_camera( anims += [Transform(cam, cam2)] - self.play(*anims + added_anims, **kwargs) + self.play(chain(*anims, added_anims), **kwargs) # These lines are added to improve performance. If manim thinks that frame_center is moving, # it is required to redraw every object. These lines remove frame_center from the Scene once @@ -309,7 +320,7 @@ def move_camera( if frame_center is not None and config.renderer == RendererType.CAIRO: self.remove(self.camera._frame_center) - def get_moving_mobjects(self, *animations: Animation): + def get_moving_mobjects(self, *animations: Animation) -> list[Mobject]: """ This method returns a list of all of the Mobjects in the Scene that are moving, that are also in the animations passed. @@ -327,7 +338,7 @@ def get_moving_mobjects(self, *animations: Animation): return self.mobjects return moving_mobjects - def add_fixed_orientation_mobjects(self, *mobjects: Mobject, **kwargs): + def add_fixed_orientation_mobjects(self, *mobjects: Mobject, **kwargs: Any) -> None: """ This method is used to prevent the rotation and tilting of mobjects as the camera moves around. The mobject can @@ -349,12 +360,12 @@ def add_fixed_orientation_mobjects(self, *mobjects: Mobject, **kwargs): self.add(*mobjects) self.renderer.camera.add_fixed_orientation_mobjects(*mobjects, **kwargs) elif config.renderer == RendererType.OPENGL: + mob: OpenGLMobject for mob in mobjects: - mob: OpenGLMobject mob.fix_orientation() self.add(mob) - def add_fixed_in_frame_mobjects(self, *mobjects: Mobject): + def add_fixed_in_frame_mobjects(self, *mobjects: Mobject) -> None: """ This method is used to prevent the rotation and movement of mobjects as the camera moves around. The mobject is @@ -371,12 +382,12 @@ def add_fixed_in_frame_mobjects(self, *mobjects: Mobject): self.camera: ThreeDCamera self.camera.add_fixed_in_frame_mobjects(*mobjects) elif config.renderer == RendererType.OPENGL: + mob: OpenGLMobject for mob in mobjects: - mob: OpenGLMobject mob.fix_in_frame() self.add(mob) - def remove_fixed_orientation_mobjects(self, *mobjects: Mobject): + def remove_fixed_orientation_mobjects(self, *mobjects: Mobject) -> None: """ This method "unfixes" the orientation of the mobjects passed, meaning they will no longer be at the same angle @@ -391,12 +402,12 @@ def remove_fixed_orientation_mobjects(self, *mobjects: Mobject): if config.renderer == RendererType.CAIRO: self.renderer.camera.remove_fixed_orientation_mobjects(*mobjects) elif config.renderer == RendererType.OPENGL: + mob: OpenGLMobject for mob in mobjects: - mob: OpenGLMobject mob.unfix_orientation() self.remove(mob) - def remove_fixed_in_frame_mobjects(self, *mobjects: Mobject): + def remove_fixed_in_frame_mobjects(self, *mobjects: Mobject) -> None: """ This method undoes what add_fixed_in_frame_mobjects does. It allows the mobject to be affected by the movement of @@ -410,13 +421,13 @@ def remove_fixed_in_frame_mobjects(self, *mobjects: Mobject): if config.renderer == RendererType.CAIRO: self.renderer.camera.remove_fixed_in_frame_mobjects(*mobjects) elif config.renderer == RendererType.OPENGL: + mob: OpenGLMobject for mob in mobjects: - mob: OpenGLMobject mob.unfix_from_frame() self.remove(mob) ## - def set_to_default_angled_camera_orientation(self, **kwargs): + def set_to_default_angled_camera_orientation(self, **kwargs: Any) -> None: """ This method sets the default_angled_camera_orientation to the keyword arguments passed, and sets the camera to that orientation. @@ -449,9 +460,12 @@ class SpecialThreeDScene(ThreeDScene): def __init__( self, - cut_axes_at_radius=True, - camera_config={"should_apply_shading": True, "exponential_projection": True}, - three_d_axes_config={ + cut_axes_at_radius: bool = True, + camera_config: dict[str, Any] = { + "should_apply_shading": True, + "exponential_projection": True, + }, + three_d_axes_config: dict[str, Any] = { "num_axis_pieces": 1, "axis_config": { "unit_size": 2, @@ -460,20 +474,20 @@ def __init__( "stroke_width": 2, }, }, - sphere_config={"radius": 2, "resolution": (24, 48)}, - default_angled_camera_position={ + sphere_config: dict[str, Any] = {"radius": 2, "resolution": (24, 48)}, + default_angled_camera_position: dict[str, Any] = { "phi": 70 * DEGREES, "theta": -110 * DEGREES, }, # When scene is extracted with -l flag, this # configuration will override the above configuration. - low_quality_config={ + low_quality_config: dict[str, Any] = { "camera_config": {"should_apply_shading": False}, "three_d_axes_config": {"num_axis_pieces": 1}, "sphere_config": {"resolution": (12, 24)}, }, - **kwargs, - ): + **kwargs: Any, + ) -> None: self.cut_axes_at_radius = cut_axes_at_radius self.camera_config = camera_config self.three_d_axes_config = three_d_axes_config @@ -487,7 +501,7 @@ def __init__( _config = merge_dicts_recursively(_config, kwargs) super().__init__(**_config) - def get_axes(self): + def get_axes(self) -> ThreeDAxes: """Return a set of 3D axes. Returns @@ -511,7 +525,7 @@ def get_axes(self): tick.add(VectorizedPoint(1.5 * tick.get_center())) return axes - def get_sphere(self, **kwargs): + def get_sphere(self, **kwargs: Any) -> Sphere: """ Returns a sphere with the passed keyword arguments as properties. @@ -528,7 +542,7 @@ def get_sphere(self, **kwargs): config = merge_dicts_recursively(self.sphere_config, kwargs) return Sphere(**config) - def get_default_camera_position(self): + def get_default_camera_position(self) -> dict[str, Any]: """ Returns the default_angled_camera position. @@ -539,6 +553,6 @@ def get_default_camera_position(self): """ return self.default_angled_camera_position - def set_camera_to_default_position(self): + def set_camera_to_default_position(self) -> None: """Sets the camera to its default position.""" self.set_camera_orientation(**self.default_angled_camera_position) diff --git a/manim/utils/config_ops.py b/manim/utils/config_ops.py index cdd9c8e9f5..4767c5414c 100644 --- a/manim/utils/config_ops.py +++ b/manim/utils/config_ops.py @@ -10,11 +10,15 @@ import itertools as it +from typing import TYPE_CHECKING import numpy as np +if TYPE_CHECKING: + from typing_extensions import Any -def merge_dicts_recursively(*dicts): + +def merge_dicts_recursively(*dicts: dict[str, Any]) -> dict[str, Any]: """ Creates a dict whose keyset is the union of all the input dictionaries. The value for each key is based From 5bf2d0eb0edfc6a102208751e6ad46f0b3b6cd90 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Thu, 24 Oct 2024 21:22:20 +0200 Subject: [PATCH 31/45] Dealing with type errors in scene_file_writer.py Error count: 248 -> 216 --- manim/camera/camera.py | 4 ++- manim/scene/scene_file_writer.py | 62 ++++++++++++++++++-------------- manim/utils/sounds.py | 3 +- 3 files changed, 40 insertions(+), 29 deletions(-) diff --git a/manim/camera/camera.py b/manim/camera/camera.py index af5899c5c5..329f420c36 100644 --- a/manim/camera/camera.py +++ b/manim/camera/camera.py @@ -274,7 +274,9 @@ def init_background(self): ) self.background[:, :] = background_rgba - def get_image(self, pixel_array: np.ndarray | list | tuple | None = None): + def get_image( + self, pixel_array: np.ndarray | list | tuple | None = None + ) -> Image.Image: """Returns an image from the passed pixel array, or from the current frame if the passed pixel array is none. diff --git a/manim/scene/scene_file_writer.py b/manim/scene/scene_file_writer.py index 4293de7105..3fa0ad7eac 100644 --- a/manim/scene/scene_file_writer.py +++ b/manim/scene/scene_file_writer.py @@ -25,6 +25,8 @@ from .. import config, logger from .._config.logger_utils import set_file_logger from ..constants import RendererType +from ..renderer.cairo_renderer import CairoRenderer +from ..renderer.opengl_renderer import OpenGLRenderer from ..utils.file_ops import ( add_extension_if_not_present, add_version_before_extension, @@ -104,7 +106,9 @@ class SceneFileWriter: force_output_as_scene_name = False - def __init__(self, renderer, scene_name, **kwargs): + def __init__( + self, renderer: CairoRenderer | OpenGLRenderer, scene_name: str, **kwargs: Any + ): self.renderer = renderer self.init_output_directories(scene_name) self.init_audio() @@ -118,7 +122,7 @@ def __init__(self, renderer, scene_name, **kwargs): name="autocreated", type_=DefaultSectionType.NORMAL, skip_animations=False ) - def init_output_directories(self, scene_name): + def init_output_directories(self, scene_name: str) -> None: """Initialise output directories. Notes @@ -225,7 +229,7 @@ def next_section(self, name: str, type_: str, skip_animations: bool) -> None: ), ) - def add_partial_movie_file(self, hash_animation: str): + def add_partial_movie_file(self, hash_animation: str) -> None: """Adds a new partial movie file path to `scene.partial_movie_files` and current section from a hash. This method will compute the path from the hash. In addition to that it adds the new animation to the current section. @@ -250,7 +254,7 @@ def add_partial_movie_file(self, hash_animation: str): self.partial_movie_files.append(new_partial_movie_file) self.sections[-1].partial_movie_files.append(new_partial_movie_file) - def get_resolution_directory(self): + def get_resolution_directory(self) -> str: """Get the name of the resolution directory directly containing the video file. @@ -280,11 +284,11 @@ def get_resolution_directory(self): return f"{pixel_height}p{frame_rate}" # Sound - def init_audio(self): + def init_audio(self) -> None: """Preps the writer for adding audio to the movie.""" self.includes_sound = False - def create_audio_segment(self): + def create_audio_segment(self) -> None: """Creates an empty, silent, Audio Segment.""" self.audio_segment = AudioSegment.silent() @@ -293,7 +297,7 @@ def add_audio_segment( new_segment: AudioSegment, time: float | None = None, gain_to_background: float | None = None, - ): + ) -> None: """ This method adds an audio segment from an AudioSegment type object and suitable parameters. @@ -338,8 +342,8 @@ def add_sound( sound_file: str, time: float | None = None, gain: float | None = None, - **kwargs, - ): + **kwargs: Any, + ) -> None: """ This method adds an audio segment from a sound file. @@ -378,7 +382,9 @@ def add_sound( self.add_audio_segment(new_segment, time, **kwargs) # Writers - def begin_animation(self, allow_write: bool = False, file_path=None): + def begin_animation( + self, allow_write: bool = False, file_path: str | None = None + ) -> None: """ Used internally by manim to stream the animation to FFMPEG for displaying or writing to a file. @@ -391,7 +397,7 @@ def begin_animation(self, allow_write: bool = False, file_path=None): if write_to_movie() and allow_write: self.open_partial_movie_stream(file_path=file_path) - def end_animation(self, allow_write: bool = False): + def end_animation(self, allow_write: bool = False) -> None: """ Internally used by Manim to stop streaming to FFMPEG gracefully. @@ -404,7 +410,7 @@ def end_animation(self, allow_write: bool = False): if write_to_movie() and allow_write: self.close_partial_movie_stream() - def listen_and_write(self): + def listen_and_write(self) -> None: """For internal use only: blocks until new frame is available on the queue.""" while True: num_frames, frame_data = self.queue.get() @@ -431,7 +437,7 @@ def encode_and_write_frame(self, frame: PixelArray, num_frames: int) -> None: def write_frame( self, frame_or_renderer: np.ndarray | OpenGLRenderer, num_frames: int = 1 - ): + ) -> None: """ Used internally by Manim to write a frame to the FFMPEG input buffer. @@ -454,7 +460,7 @@ def write_frame( self.queue.put(msg) if is_png_format() and not config["dry_run"]: - image: Image = ( + image: Image.Image = ( frame_or_renderer.get_image() if config.renderer == RendererType.OPENGL else Image.fromarray(frame_or_renderer) @@ -468,14 +474,16 @@ def write_frame( config["zero_pad"], ) - def output_image(self, image: Image.Image, target_dir, ext, zero_pad: bool): + def output_image( + self, image: Image.Image, target_dir: Path, ext: str, zero_pad: bool + ) -> None: if zero_pad: image.save(f"{target_dir}{str(self.frame_count).zfill(zero_pad)}{ext}") else: image.save(f"{target_dir}{self.frame_count}{ext}") self.frame_count += 1 - def save_final_image(self, image: np.ndarray): + def save_final_image(self, image: Image.Image) -> None: """ The name is a misnomer. This method saves the image passed to it as an in the default image directory. @@ -516,7 +524,7 @@ def finish(self) -> None: if self.subcaptions: self.write_subcaption_file() - def open_partial_movie_stream(self, file_path=None) -> None: + def open_partial_movie_stream(self, file_path: str | None = None) -> None: """Open a container holding a video stream. This is used internally by Manim initialize the container holding @@ -582,7 +590,7 @@ def close_partial_movie_stream(self) -> None: {"path": f"'{self.partial_movie_file_path}'"}, ) - def is_already_cached(self, hash_invocation: str): + def is_already_cached(self, hash_invocation: str) -> bool: """Will check if a file named with `hash_invocation` exists. Parameters @@ -607,9 +615,9 @@ def combine_files( self, input_files: list[str], output_file: Path, - create_gif=False, - includes_sound=False, - ): + create_gif: bool = False, + includes_sound: bool = False, + ) -> None: file_list = self.partial_movie_directory / "partial_movie_file_list.txt" logger.debug( f"Partial movie files to combine ({len(input_files)} files): %(p)s", @@ -708,7 +716,7 @@ def combine_files( partial_movies_input.close() output_container.close() - def combine_to_movie(self): + def combine_to_movie(self) -> None: """Used internally by Manim to combine the separate partial movie files that make up a Scene into a single video file for that Scene. @@ -806,7 +814,7 @@ def combine_to_movie(self): shutil.move(str(temp_file_path), str(movie_file_path)) sound_file_path.unlink() - self.print_file_ready_message(str(movie_file_path)) + self.print_file_ready_message(movie_file_path) if write_to_movie(): for file_path in partial_movie_files: # We have to modify the accessed time so if we have to clean the cache we remove the one used the longest. @@ -828,7 +836,7 @@ def combine_to_section_videos(self) -> None: with (self.sections_output_dir / f"{self.output_name}.json").open("w") as file: json.dump(sections_index, file, indent=4) - def clean_cache(self): + def clean_cache(self) -> None: """Will clean the cache by removing the oldest partial_movie_files.""" cached_partial_movies = [ (self.partial_movie_directory / file_name) @@ -850,7 +858,7 @@ def clean_cache(self): " You can change this behaviour by changing max_files_cached in config.", ) - def flush_cache_directory(self): + def flush_cache_directory(self) -> None: """Delete all the cached partial movie files""" cached_partial_movies = [ self.partial_movie_directory / file_name @@ -864,7 +872,7 @@ def flush_cache_directory(self): {"par_dir": self.partial_movie_directory}, ) - def write_subcaption_file(self): + def write_subcaption_file(self) -> None: """Writes the subcaption file.""" if config.output_file is None: return @@ -872,7 +880,7 @@ def write_subcaption_file(self): subcaption_file.write_text(srt.compose(self.subcaptions), encoding="utf-8") logger.info(f"Subcaption file has been written as {subcaption_file}") - def print_file_ready_message(self, file_path): + def print_file_ready_message(self, file_path: Path) -> None: """Prints the "File Ready" message to STDOUT.""" config["output_file"] = file_path logger.info("\nFile ready at %(file_path)s\n", {"file_path": f"'{file_path}'"}) diff --git a/manim/utils/sounds.py b/manim/utils/sounds.py index 5e0ea060f3..903c0c8b54 100644 --- a/manim/utils/sounds.py +++ b/manim/utils/sounds.py @@ -6,13 +6,14 @@ "get_full_sound_file_path", ] +from pathlib import Path from .. import config from ..utils.file_ops import seek_full_path_from_defaults # Still in use by add_sound() function in scene_file_writer.py -def get_full_sound_file_path(sound_file_name): +def get_full_sound_file_path(sound_file_name: str) -> Path: return seek_full_path_from_defaults( sound_file_name, default_dir=config.get_dir("assets_dir"), From da3526199a962e7002a818be55017669cddce741 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Fri, 25 Oct 2024 20:53:36 +0200 Subject: [PATCH 32/45] Ensured that all methods in scene.py have type declarations. Error count: 216 -> 225 --- manim/gui/gui.py | 6 +- manim/renderer/cairo_renderer.py | 12 +- manim/renderer/opengl_renderer.py | 4 +- manim/scene/moving_camera_scene.py | 13 +- manim/scene/scene.py | 190 +++++++++++++++++------------ 5 files changed, 135 insertions(+), 90 deletions(-) diff --git a/manim/gui/gui.py b/manim/gui/gui.py index 75ec67312c..d9cb91b3cf 100644 --- a/manim/gui/gui.py +++ b/manim/gui/gui.py @@ -11,6 +11,8 @@ from .. import __version__, config +from ..renderer.cairo_renderer import CairoRenderer +from ..renderer.opengl_renderer import OpenGLRenderer from ..utils.module_ops import scene_classes_from_file __all__ = ["configure_pygui"] @@ -20,7 +22,9 @@ window = dpg.generate_uuid() -def configure_pygui(renderer, widgets, update=True): +def configure_pygui( + renderer: CairoRenderer | OpenGLRenderer, widgets, update: bool = True +) -> None: if not dearpygui_imported: raise RuntimeError("Attempted to use DearPyGUI when it isn't imported.") if update: diff --git a/manim/renderer/cairo_renderer.py b/manim/renderer/cairo_renderer.py index 991e02f0e4..a45fcb6dd5 100644 --- a/manim/renderer/cairo_renderer.py +++ b/manim/renderer/cairo_renderer.py @@ -35,11 +35,11 @@ class CairoRenderer: def __init__( self, - file_writer_class=SceneFileWriter, - camera_class=None, - skip_animations=False, - **kwargs, - ): + file_writer_class: type[SceneFileWriter] = SceneFileWriter, + camera_class: Camera | None = None, + skip_animations: bool = False, + **kwargs: Any, + ) -> None: # All of the following are set to EITHER the value passed via kwargs, # OR the value stored in the global config dict at the time of # _instance construction_. @@ -265,7 +265,7 @@ def update_skipping_status(self): self.skip_animations = True raise EndSceneEarlyException() - def scene_finished(self, scene): + def scene_finished(self, scene: Scene) -> None: # If no animations in scene, render an image instead if self.num_plays: self.file_writer.finish() diff --git a/manim/renderer/opengl_renderer.py b/manim/renderer/opengl_renderer.py index cdb63ceaa5..6ca381cd54 100644 --- a/manim/renderer/opengl_renderer.py +++ b/manim/renderer/opengl_renderer.py @@ -216,7 +216,9 @@ def interpolate(self, *args, **kwargs): class OpenGLRenderer: - def __init__(self, file_writer_class=SceneFileWriter, skip_animations=False): + def __init__( + self, file_writer_class=SceneFileWriter, skip_animations=False + ) -> None: # Measured in pixel widths, used for vector graphics self.anti_alias_width = 1.5 self._file_writer_class = file_writer_class diff --git a/manim/scene/moving_camera_scene.py b/manim/scene/moving_camera_scene.py index eafc992ef5..748ab5fa31 100644 --- a/manim/scene/moving_camera_scene.py +++ b/manim/scene/moving_camera_scene.py @@ -89,6 +89,8 @@ def create_scene(number): __all__ = ["MovingCameraScene"] +from typing import TYPE_CHECKING + from manim.animation.animation import Animation from ..camera.moving_camera import MovingCamera @@ -96,6 +98,11 @@ def create_scene(number): from ..utils.family import extract_mobject_family_members from ..utils.iterables import list_update +if TYPE_CHECKING: + from typing_extensions import Any + + from manim.mobject.mobject import Mobject + class MovingCameraScene(Scene): """ @@ -111,10 +118,12 @@ class MovingCameraScene(Scene): :class:`.MovingCamera` """ - def __init__(self, camera_class=MovingCamera, **kwargs): + def __init__( + self, camera_class: MovingCamera = MovingCamera, **kwargs: Any + ) -> None: super().__init__(camera_class=camera_class, **kwargs) - def get_moving_mobjects(self, *animations: Animation): + def get_moving_mobjects(self, *animations: Animation) -> list[Mobject]: """ This method returns a list of all of the Mobjects in the Scene that are moving, that are also in the animations passed. diff --git a/manim/scene/scene.py b/manim/scene/scene.py index 2b50f93688..7edfeaf693 100644 --- a/manim/scene/scene.py +++ b/manim/scene/scene.py @@ -53,19 +53,21 @@ if TYPE_CHECKING: from collections.abc import Iterable, Sequence - from typing import Callable + from typing import Any, Callable from typing_extensions import Self + from manim.typing import InternalPoint3D + class RerunSceneHandler(FileSystemEventHandler): """A class to handle rerunning a Scene after the input file is modified.""" - def __init__(self, queue): + def __init__(self, queue: Queue) -> None: super().__init__() self.queue = queue - def on_modified(self, event): + def on_modified(self, event: Any) -> None: self.queue.put(("rerun_file", [], {})) @@ -102,10 +104,10 @@ def construct(self): def __init__( self, - renderer: bool = None, - camera_class: type[Camera] = Camera, + renderer: CairoRenderer | OpenGLRenderer | None = None, + camera_class: Camera = Camera, always_update_mobjects: bool = False, - random_seed: bool = None, + random_seed: int | None = None, skip_animations: bool = False, ) -> None: self.camera_class = camera_class @@ -115,22 +117,22 @@ def __init__( self.animations = None self.stop_condition = None - self.moving_mobjects = [] - self.static_mobjects = [] + self.moving_mobjects: list[Mobject] = [] + self.static_mobjects: list[Mobject] = [] self.time_progression = None self.duration = None self.last_t = None - self.queue = Queue() + self.queue: Queue = Queue() self.skip_animation_preview = False - self.meshes = [] + self.meshes: list[Object3D] = [] self.camera_target = ORIGIN - self.widgets = [] + self.widgets: list[Any] = [] self.dearpygui_imported = dearpygui_imported - self.updaters = [] - self.point_lights = [] + self.updaters: list[Callable[[float], None]] = [] + self.point_lights: list[Any] = [] self.ambient_light = None - self.key_to_function_map = {} - self.mouse_press_callbacks = [] + self.key_to_function_map: dict[str, Callable[[None], None]] = {} + self.mouse_press_callbacks: list[Callable[[None], None]] = [] self.interactive_mode = False if config.renderer == RendererType.OPENGL: @@ -157,10 +159,10 @@ def __init__( np.random.seed(self.random_seed) @property - def camera(self): + def camera(self) -> Camera: return self.renderer.camera - def __deepcopy__(self, clone_from_id): + def __deepcopy__(self, clone_from_id: Any) -> Scene: cls = self.__class__ result = cls.__new__(cls) clone_from_id[id(self)] = result @@ -218,7 +220,7 @@ def __deepcopy__(self, clone_from_id): result.mobject_updater_lists.append((mobject_clone, cloned_updaters)) return result - def render(self, preview: bool = False): + def render(self, preview: bool = False) -> bool: """ Renders this Scene. @@ -258,7 +260,7 @@ def render(self, preview: bool = False): if config["preview"] or config["show_in_file_browser"]: open_media_file(self.renderer.file_writer) - def setup(self): + def setup(self) -> None: """ This is meant to be implemented by any scenes which are commonly subclassed, and have some common setup @@ -266,7 +268,7 @@ def setup(self): """ pass - def tear_down(self): + def tear_down(self) -> None: """ This is meant to be implemented by any scenes which are commonly subclassed, and have some common method @@ -274,7 +276,7 @@ def tear_down(self): """ pass - def construct(self): + def construct(self) -> None: """Add content to the Scene. From within :meth:`Scene.construct`, display mobjects on screen by calling @@ -319,10 +321,10 @@ def next_section( """ self.renderer.file_writer.next_section(name, section_type, skip_animations) - def __str__(self): + def __str__(self) -> str: return self.__class__.__name__ - def get_attrs(self, *keys: str): + def get_attrs(self, *keys: str) -> list[Any]: """ Gets attributes of a scene given the attribute's identifier/name. @@ -338,7 +340,7 @@ def get_attrs(self, *keys: str): """ return [getattr(self, key) for key in keys] - def update_mobjects(self, dt: float): + def update_mobjects(self, dt: float) -> None: """ Begins updating all mobjects in the Scene. @@ -350,12 +352,12 @@ def update_mobjects(self, dt: float): for mobject in self.mobjects: mobject.update(dt) - def update_meshes(self, dt): + def update_meshes(self, dt) -> None: for obj in self.meshes: for mesh in obj.get_family(): mesh.update(dt) - def update_self(self, dt: float): + def update_self(self, dt: float) -> None: """Run all scene updater functions. Among all types of update functions (mobject updaters, mesh updaters, @@ -401,7 +403,7 @@ def should_update_mobjects(self) -> bool: wait_animation.is_static_wait = not should_update return not wait_animation.is_static_wait - def get_top_level_mobjects(self): + def get_top_level_mobjects(self) -> list[Mobject]: """ Returns all mobjects which are not submobjects. @@ -414,13 +416,13 @@ def get_top_level_mobjects(self): # of another mobject from the scene families = [m.get_family() for m in self.mobjects] - def is_top_level(mobject): + def is_top_level(mobject: Mobject) -> bool: num_families = sum((mobject in family) for family in families) return num_families == 1 return list(filter(is_top_level, self.mobjects)) - def get_mobject_family_members(self): + def get_mobject_family_members(self) -> list[Mobject]: """ Returns list of family-members of all mobjects in scene. If a Circle() and a VGroup(Rectangle(),Triangle()) were added, @@ -443,7 +445,7 @@ def get_mobject_family_members(self): use_z_index=self.renderer.camera.use_z_index, ) - def add(self, *mobjects: Mobject): + def add(self, *mobjects: Mobject) -> Self: """ Mobjects will be displayed, from background to foreground in the order with which they are added. @@ -483,7 +485,7 @@ def add(self, *mobjects: Mobject): self.moving_mobjects += mobjects return self - def add_mobjects_from_animations(self, animations): + def add_mobjects_from_animations(self, animations: list[Animation]) -> None: curr_mobjects = self.get_mobject_family_members() for animation in animations: if animation.is_introducer(): @@ -495,7 +497,7 @@ def add_mobjects_from_animations(self, animations): self.add(mob) curr_mobjects += mob.get_family() - def remove(self, *mobjects: Mobject): + def remove(self, *mobjects: Mobject) -> Self: """ Removes mobjects in the passed list of mobjects from the scene and the foreground, by removing them @@ -625,7 +627,7 @@ def restructure_mobjects( to_remove: Sequence[Mobject], mobject_list_name: str = "mobjects", extract_families: bool = True, - ): + ) -> Scene: """ tl:wr If your scene has a Group(), and you removed a mobject from the Group, @@ -663,7 +665,9 @@ def restructure_mobjects( setattr(self, mobject_list_name, new_list) return self - def get_restructured_mobject_list(self, mobjects: list, to_remove: list): + def get_restructured_mobject_list( + self, mobjects: list[Mobject], to_remove: list[Mobject] + ) -> list[Mobject]: """ Given a list of mobjects and a list of mobjects to be removed, this filters out the removable mobjects from the list of mobjects. @@ -682,9 +686,11 @@ def get_restructured_mobject_list(self, mobjects: list, to_remove: list): list The list of mobjects with the mobjects to remove removed. """ - new_mobjects = [] + new_mobjects: list[Mobject] = [] - def add_safe_mobjects_from_list(list_to_examine, set_to_remove): + def add_safe_mobjects_from_list( + list_to_examine: list[Mobject], set_to_remove: set[Mobject] + ) -> None: for mob in list_to_examine: if mob in set_to_remove: continue @@ -698,7 +704,7 @@ def add_safe_mobjects_from_list(list_to_examine, set_to_remove): return new_mobjects # TODO, remove this, and calls to this - def add_foreground_mobjects(self, *mobjects: Mobject): + def add_foreground_mobjects(self, *mobjects: Mobject) -> Scene: """ Adds mobjects to the foreground, and internally to the list foreground_mobjects, and mobjects. @@ -717,7 +723,7 @@ def add_foreground_mobjects(self, *mobjects: Mobject): self.add(*mobjects) return self - def add_foreground_mobject(self, mobject: Mobject): + def add_foreground_mobject(self, mobject: Mobject) -> Scene: """ Adds a single mobject to the foreground, and internally to the list foreground_mobjects, and mobjects. @@ -734,7 +740,7 @@ def add_foreground_mobject(self, mobject: Mobject): """ return self.add_foreground_mobjects(mobject) - def remove_foreground_mobjects(self, *to_remove: Mobject): + def remove_foreground_mobjects(self, *to_remove: Mobject) -> Scene: """ Removes mobjects from the foreground, and internally from the list foreground_mobjects. @@ -752,7 +758,7 @@ def remove_foreground_mobjects(self, *to_remove: Mobject): self.restructure_mobjects(to_remove, "foreground_mobjects") return self - def remove_foreground_mobject(self, mobject: Mobject): + def remove_foreground_mobject(self, mobject: Mobject) -> Scene: """ Removes a single mobject from the foreground, and internally from the list foreground_mobjects. @@ -769,7 +775,7 @@ def remove_foreground_mobject(self, mobject: Mobject): """ return self.remove_foreground_mobjects(mobject) - def bring_to_front(self, *mobjects: Mobject): + def bring_to_front(self, *mobjects: Mobject) -> Scene: """ Adds the passed mobjects to the scene again, pushing them to he front of the scene. @@ -788,7 +794,7 @@ def bring_to_front(self, *mobjects: Mobject): self.add(*mobjects) return self - def bring_to_back(self, *mobjects: Mobject): + def bring_to_back(self, *mobjects: Mobject) -> Scene: """ Removes the mobject from the scene and adds them to the back of the scene. @@ -855,7 +861,9 @@ def get_moving_mobjects(self, *animations: Animation) -> list[Mobject]: return mobjects[i:] return [] - def get_moving_and_static_mobjects(self, animations): + def get_moving_and_static_mobjects( + self, animations: list[Animation] + ) -> tuple[list[Mobject], list[Mobject]]: all_mobjects = list_update(self.mobjects, self.foreground_mobjects) all_mobject_families = extract_mobject_family_members( all_mobjects, @@ -876,8 +884,8 @@ def get_moving_and_static_mobjects(self, animations): def compile_animations( self, *args: Animation | Iterable[Animation] | types.GeneratorType[Animation], - **kwargs, - ): + **kwargs: Any, + ) -> tuple[Animation]: """ Creates _MethodAnimations from any _AnimationBuilders and updates animation kwargs with kwargs passed to play(). @@ -919,7 +927,7 @@ def compile_animations( def _get_animation_time_progression( self, animations: list[Animation], duration: float - ): + ) -> tqdm[float]: """ You will hardly use this when making your own animations. This method is for Manim's internal use. @@ -972,10 +980,10 @@ def _get_animation_time_progression( def get_time_progression( self, run_time: float, - description, + description: str, n_iterations: int | None = None, override_skip_animations: bool = False, - ): + ) -> tqdm[float]: """ You will hardly use this when making your own animations. This method is for Manim's internal use. @@ -1003,7 +1011,7 @@ def get_time_progression( The CommandLine Progress Bar. """ if self.renderer.skip_animations and not override_skip_animations: - times = [run_time] + times: Iterable[float] = [run_time] else: step = 1 / config["frame_rate"] times = np.arange(0, run_time, step) @@ -1017,7 +1025,7 @@ def get_time_progression( ) return time_progression - def get_run_time(self, animations: list[Animation]): + def get_run_time(self, animations: list[Animation]) -> float: """ Gets the total run time for a list of animations. @@ -1032,7 +1040,7 @@ def get_run_time(self, animations: list[Animation]): float The total ``run_time`` of all of the animations in the list. """ - max_run_time = 0 + max_run_time: float = 0 frame_rate = ( 1 / config.frame_rate ) # config.frame_rate holds the number of frames per second @@ -1058,11 +1066,11 @@ def get_run_time(self, animations: list[Animation]): def play( self, *args: Animation | Iterable[Animation] | types.GeneratorType[Animation], - subcaption=None, - subcaption_duration=None, - subcaption_offset=0, - **kwargs, - ): + subcaption: str | None = None, + subcaption_duration: float | None = None, + subcaption_offset: float = 0, + **kwargs: Any, + ) -> None: r"""Plays an animation in this scene. Parameters @@ -1127,7 +1135,7 @@ def wait( duration: float = DEFAULT_WAIT_TIME, stop_condition: Callable[[], bool] | None = None, frozen_frame: bool | None = None, - ): + ) -> None: """Plays a "no operation" animation. Parameters @@ -1157,7 +1165,7 @@ def wait( ) ) - def pause(self, duration: float = DEFAULT_WAIT_TIME): + def pause(self, duration: float = DEFAULT_WAIT_TIME) -> None: """Pauses the scene (i.e., displays a frozen frame). This is an alias for :meth:`.wait` with ``frozen_frame`` @@ -1174,7 +1182,9 @@ def pause(self, duration: float = DEFAULT_WAIT_TIME): """ self.wait(duration=duration, frozen_frame=True) - def wait_until(self, stop_condition: Callable[[], bool], max_time: float = 60): + def wait_until( + self, stop_condition: Callable[[], bool], max_time: float = 60 + ) -> None: """Wait until a condition is satisfied, up to a given maximum duration. Parameters @@ -1190,8 +1200,8 @@ def wait_until(self, stop_condition: Callable[[], bool], max_time: float = 60): def compile_animation_data( self, *animations: Animation | Iterable[Animation] | types.GeneratorType[Animation], - **play_kwargs, - ): + **play_kwargs: Any, + ) -> Self: """Given a list of animations, compile the corresponding static and moving mobjects, and gather the animation durations. @@ -1257,7 +1267,7 @@ def is_current_animation_frozen_frame(self) -> bool: and self.animations[0].is_static_wait ) - def play_internal(self, skip_rendering: bool = False): + def play_internal(self, skip_rendering: bool = False) -> None: """ This method is used to prep the animations for rendering, apply the arguments and parameters required to them, @@ -1290,7 +1300,7 @@ def play_internal(self, skip_rendering: bool = False): # Closing the progress bar at the end of the play. self.time_progression.close() - def check_interactive_embed_is_valid(self): + def check_interactive_embed_is_valid(self) -> bool: if config["force_window"]: return True if self.skip_animation_preview: @@ -1315,13 +1325,13 @@ def check_interactive_embed_is_valid(self): return False return True - def interactive_embed(self): + def interactive_embed(self) -> None: """Like embed(), but allows for screen interaction.""" if not self.check_interactive_embed_is_valid(): return self.interactive_mode = True - def ipython(shell, namespace): + def ipython(shell: InteractiveShellEmbed, namespace: dict[str, Any]) -> None: import manim.opengl def load_module_into_namespace(module, namespace): @@ -1340,7 +1350,7 @@ def embedded_rerun(*args, **kwargs): shell(local_ns=namespace) self.queue.put(("exit_keyboard", [], {})) - def get_embedded_method(method_name): + def get_embedded_method(method_name: str): return lambda *args, **kwargs: self.queue.put((method_name, args, kwargs)) local_namespace = inspect.currentframe().f_back.f_locals @@ -1388,7 +1398,11 @@ def get_embedded_method(method_name): self.interact(shell, keyboard_thread) - def interact(self, shell, keyboard_thread): + from IPython.terminal.embed import InteractiveShellEmbed + + def interact( + self, shell: InteractiveShellEmbed, keyboard_thread: threading.Thread + ) -> None: event_handler = RerunSceneHandler(self.queue) file_observer = Observer() file_observer.schedule(event_handler, config["input_file"], recursive=True) @@ -1465,7 +1479,7 @@ def interact(self, shell, keyboard_thread): if self.renderer.window.is_closing: self.renderer.window.destroy() - def embed(self): + def embed(self) -> None: if not config["preview"]: logger.warning("Called embed() while no preview window is available.") return @@ -1507,7 +1521,7 @@ def embed(self): # End scene when exiting an embed. raise Exception("Exiting scene.") - def update_to_time(self, t): + def update_to_time(self, t: float) -> None: dt = t - self.last_t self.last_t = t for animation in self.animations: @@ -1573,8 +1587,8 @@ def add_sound( sound_file: str, time_offset: float = 0, gain: float | None = None, - **kwargs, - ): + **kwargs: Any, + ) -> None: """ This method is used to add a sound to the animation. @@ -1615,7 +1629,7 @@ def construct(self): time = self.renderer.time + time_offset self.renderer.file_writer.add_sound(sound_file, time, gain, **kwargs) - def on_mouse_motion(self, point, d_point): + def on_mouse_motion(self, point: InternalPoint3D, d_point: InternalPoint3D) -> None: self.mouse_point.move_to(point) if SHIFT_VALUE in self.renderer.pressed_keys: shift = -d_point @@ -1625,13 +1639,13 @@ def on_mouse_motion(self, point, d_point): shift = np.dot(np.transpose(transform), shift) self.camera.shift(shift) - def on_mouse_scroll(self, point, offset): + def on_mouse_scroll(self, point: InternalPoint3D, offset: InternalPoint3D) -> None: if not config.use_projection_stroke_shaders: factor = 1 + np.arctan(-2.1 * offset[1]) self.camera.scale(factor, about_point=self.camera_target) self.mouse_scroll_orbit_controls(point, offset) - def on_key_press(self, symbol, modifiers): + def on_key_press(self, symbol: int, modifiers: Any) -> None: try: char = chr(symbol) except OverflowError: @@ -1647,10 +1661,16 @@ def on_key_press(self, symbol, modifiers): if char in self.key_to_function_map: self.key_to_function_map[char]() - def on_key_release(self, symbol, modifiers): + def on_key_release(self, symbol: int, modifiers: Any) -> None: pass - def on_mouse_drag(self, point, d_point, buttons, modifiers): + def on_mouse_drag( + self, + point: InternalPoint3D, + d_point: InternalPoint3D, + buttons: int, + modifiers: Any, + ): self.mouse_drag_point.move_to(point) if buttons == 1: self.camera.increment_theta(-d_point[0]) @@ -1664,7 +1684,9 @@ def on_mouse_drag(self, point, d_point, buttons, modifiers): self.mouse_drag_orbit_controls(point, d_point, buttons, modifiers) - def mouse_scroll_orbit_controls(self, point, offset): + def mouse_scroll_orbit_controls( + self, point: InternalPoint3D, offset: InternalPoint3D + ) -> None: camera_to_target = self.camera_target - self.camera.get_position() camera_to_target *= np.sign(offset[1]) shift_vector = 0.01 * camera_to_target @@ -1672,7 +1694,13 @@ def mouse_scroll_orbit_controls(self, point, offset): opengl.translation_matrix(*shift_vector) @ self.camera.model_matrix ) - def mouse_drag_orbit_controls(self, point, d_point, buttons, modifiers): + def mouse_drag_orbit_controls( + self, + point: InternalPoint3D, + d_point: InternalPoint3D, + buttons: int, + modifiers: Any, + ) -> None: # Left click drag. if buttons == 1: # Translate to target the origin and rotate around the z axis. @@ -1745,9 +1773,11 @@ def mouse_drag_orbit_controls(self, point, d_point, buttons, modifiers): ) self.camera_target += total_shift_vector - def set_key_function(self, char, func): + def set_key_function(self, char: int, func: Callable[[None], Any]) -> None: self.key_to_function_map[char] = func - def on_mouse_press(self, point, button, modifiers): + def on_mouse_press( + self, point: InternalPoint3D, button: str, modifiers: Any + ) -> None: for func in self.mouse_press_callbacks: func() From 79790db7f5fe3faec00c7dba40a7ef75fde2481f Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Fri, 25 Oct 2024 21:20:50 +0200 Subject: [PATCH 33/45] Handle type issues related to interactivity by asserting that the camera is the OpenGLCamera Error count: 225 -> 182 --- manim/scene/scene.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/manim/scene/scene.py b/manim/scene/scene.py index 7edfeaf693..efecbb8286 100644 --- a/manim/scene/scene.py +++ b/manim/scene/scene.py @@ -42,7 +42,7 @@ from ..constants import * from ..gui.gui import configure_pygui from ..renderer.cairo_renderer import CairoRenderer -from ..renderer.opengl_renderer import OpenGLRenderer +from ..renderer.opengl_renderer import OpenGLCamera, OpenGLRenderer from ..renderer.shader import Object3D from ..utils import opengl, space_ops from ..utils.exceptions import EndSceneEarlyException, RerunSceneException @@ -1327,6 +1327,7 @@ def check_interactive_embed_is_valid(self) -> bool: def interactive_embed(self) -> None: """Like embed(), but allows for screen interaction.""" + assert isinstance(self.camera, OpenGLCamera) if not self.check_interactive_embed_is_valid(): return self.interactive_mode = True @@ -1630,6 +1631,7 @@ def construct(self): self.renderer.file_writer.add_sound(sound_file, time, gain, **kwargs) def on_mouse_motion(self, point: InternalPoint3D, d_point: InternalPoint3D) -> None: + assert isinstance(self.camera, OpenGLCamera) self.mouse_point.move_to(point) if SHIFT_VALUE in self.renderer.pressed_keys: shift = -d_point @@ -1640,12 +1642,14 @@ def on_mouse_motion(self, point: InternalPoint3D, d_point: InternalPoint3D) -> N self.camera.shift(shift) def on_mouse_scroll(self, point: InternalPoint3D, offset: InternalPoint3D) -> None: + assert isinstance(self.camera, OpenGLCamera) if not config.use_projection_stroke_shaders: factor = 1 + np.arctan(-2.1 * offset[1]) self.camera.scale(factor, about_point=self.camera_target) self.mouse_scroll_orbit_controls(point, offset) def on_key_press(self, symbol: int, modifiers: Any) -> None: + assert isinstance(self.camera, OpenGLCamera) try: char = chr(symbol) except OverflowError: @@ -1671,6 +1675,7 @@ def on_mouse_drag( buttons: int, modifiers: Any, ): + assert isinstance(self.camera, OpenGLCamera) self.mouse_drag_point.move_to(point) if buttons == 1: self.camera.increment_theta(-d_point[0]) @@ -1687,6 +1692,7 @@ def on_mouse_drag( def mouse_scroll_orbit_controls( self, point: InternalPoint3D, offset: InternalPoint3D ) -> None: + assert isinstance(self.camera, OpenGLCamera) camera_to_target = self.camera_target - self.camera.get_position() camera_to_target *= np.sign(offset[1]) shift_vector = 0.01 * camera_to_target @@ -1701,6 +1707,7 @@ def mouse_drag_orbit_controls( buttons: int, modifiers: Any, ) -> None: + assert isinstance(self.camera, OpenGLCamera) # Left click drag. if buttons == 1: # Translate to target the origin and rotate around the z axis. From 080113f7df1c5c1e2969b92e1fb40a83e6e22dbe Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Fri, 25 Oct 2024 21:23:42 +0200 Subject: [PATCH 34/45] Handle type issues in scene.py Error count: 182 -> 167 --- manim/scene/scene.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/manim/scene/scene.py b/manim/scene/scene.py index efecbb8286..ec55fa5bfc 100644 --- a/manim/scene/scene.py +++ b/manim/scene/scene.py @@ -115,11 +115,11 @@ def __init__( self.random_seed = random_seed self.skip_animations = skip_animations - self.animations = None + self.animations: list[Animation] = None self.stop_condition = None self.moving_mobjects: list[Mobject] = [] self.static_mobjects: list[Mobject] = [] - self.time_progression = None + self.time_progression: tqdm[float] = None self.duration = None self.last_t = None self.queue: Queue = Queue() @@ -885,7 +885,7 @@ def compile_animations( self, *args: Animation | Iterable[Animation] | types.GeneratorType[Animation], **kwargs: Any, - ) -> tuple[Animation]: + ) -> list[Animation]: """ Creates _MethodAnimations from any _AnimationBuilders and updates animation kwargs with kwargs passed to play(). From abd702229890baffbae044fdcfcc00e1f207faa5 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Fri, 25 Oct 2024 21:43:16 +0200 Subject: [PATCH 35/45] Asserting that the renderer or camera is of the proper type to use certain methods. This is mainly related to interactive elements and the 3D camera used in the ThreeDScene Error count: 167 -> 143 --- manim/scene/scene.py | 3 +++ manim/scene/three_d_scene.py | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/manim/scene/scene.py b/manim/scene/scene.py index ec55fa5bfc..db4e0a00d6 100644 --- a/manim/scene/scene.py +++ b/manim/scene/scene.py @@ -1301,6 +1301,7 @@ def play_internal(self, skip_rendering: bool = False) -> None: self.time_progression.close() def check_interactive_embed_is_valid(self) -> bool: + assert isinstance(self.renderer, OpenGLRenderer) if config["force_window"]: return True if self.skip_animation_preview: @@ -1404,6 +1405,7 @@ def get_embedded_method(method_name: str): def interact( self, shell: InteractiveShellEmbed, keyboard_thread: threading.Thread ) -> None: + assert isinstance(self.renderer, OpenGLRenderer) event_handler = RerunSceneHandler(self.queue) file_observer = Observer() file_observer.schedule(event_handler, config["input_file"], recursive=True) @@ -1481,6 +1483,7 @@ def interact( self.renderer.window.destroy() def embed(self) -> None: + assert isinstance(self.renderer, OpenGLRenderer) if not config["preview"]: logger.warning("Called embed() while no preview window is available.") return diff --git a/manim/scene/three_d_scene.py b/manim/scene/three_d_scene.py index a74fafbb37..cc30dc67ea 100644 --- a/manim/scene/three_d_scene.py +++ b/manim/scene/three_d_scene.py @@ -91,6 +91,7 @@ def set_camera_orientation( The new center of the camera frame in cartesian coordinates. """ + assert isinstance(self.renderer.camera, ThreeDCamera) if phi is not None: self.renderer.camera.set_phi(phi) if theta is not None: @@ -187,6 +188,7 @@ def begin_3dillusion_camera_rotation( The azimutal angle the camera should move around. Defaults to the current theta angle. """ + assert isinstance(self.renderer.camera, ThreeDCamera) if origin_theta is None: origin_theta = self.renderer.camera.theta_tracker.get_value() if origin_phi is None: @@ -214,6 +216,7 @@ def update_phi(m: ValueTracker, dt: float) -> ValueTracker: def stop_3dillusion_camera_rotation(self) -> None: """This method stops all illusion camera rotations.""" + assert isinstance(self.renderer.camera, ThreeDCamera) self.renderer.camera.theta_tracker.clear_updaters() self.remove(self.renderer.camera.theta_tracker) self.renderer.camera.phi_tracker.clear_updaters() @@ -330,6 +333,7 @@ def get_moving_mobjects(self, *animations: Animation) -> list[Mobject]: *animations The animations whose mobjects will be checked. """ + assert isinstance(self.renderer.camera, ThreeDCamera) moving_mobjects = super().get_moving_mobjects(*animations) camera_mobjects = self.renderer.camera.get_value_trackers() + [ self.renderer.camera._frame_center, @@ -356,6 +360,7 @@ def add_fixed_orientation_mobjects(self, *mobjects: Mobject, **kwargs: Any) -> N use_static_center_func : bool center_func : function """ + assert isinstance(self.renderer.camera, ThreeDCamera) if config.renderer == RendererType.CAIRO: self.add(*mobjects) self.renderer.camera.add_fixed_orientation_mobjects(*mobjects, **kwargs) @@ -399,6 +404,7 @@ def remove_fixed_orientation_mobjects(self, *mobjects: Mobject) -> None: *mobjects The Mobjects whose orientation must be unfixed. """ + assert isinstance(self.renderer.camera, ThreeDCamera) if config.renderer == RendererType.CAIRO: self.renderer.camera.remove_fixed_orientation_mobjects(*mobjects) elif config.renderer == RendererType.OPENGL: @@ -418,6 +424,7 @@ def remove_fixed_in_frame_mobjects(self, *mobjects: Mobject) -> None: *mobjects The Mobjects whose position and orientation must be unfixed. """ + assert isinstance(self.renderer.camera, ThreeDCamera) if config.renderer == RendererType.CAIRO: self.renderer.camera.remove_fixed_in_frame_mobjects(*mobjects) elif config.renderer == RendererType.OPENGL: @@ -488,6 +495,7 @@ def __init__( }, **kwargs: Any, ) -> None: + assert isinstance(self.renderer.camera, ThreeDCamera) self.cut_axes_at_radius = cut_axes_at_radius self.camera_config = camera_config self.three_d_axes_config = three_d_axes_config From 3fc6197716096101473205b6447ba112cc075aae Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Sat, 26 Oct 2024 18:39:14 +0200 Subject: [PATCH 36/45] Avoid cyclic import of dependencies Error count: 143 -> 143 --- manim/scene/scene_file_writer.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/manim/scene/scene_file_writer.py b/manim/scene/scene_file_writer.py index 3fa0ad7eac..6096ac2b5a 100644 --- a/manim/scene/scene_file_writer.py +++ b/manim/scene/scene_file_writer.py @@ -25,8 +25,6 @@ from .. import config, logger from .._config.logger_utils import set_file_logger from ..constants import RendererType -from ..renderer.cairo_renderer import CairoRenderer -from ..renderer.opengl_renderer import OpenGLRenderer from ..utils.file_ops import ( add_extension_if_not_present, add_version_before_extension, @@ -40,6 +38,7 @@ from .section import DefaultSectionType, Section if TYPE_CHECKING: + from manim.renderer.cairo_renderer import CairoRenderer from manim.renderer.opengl_renderer import OpenGLRenderer From c5d574311830ce7e0505888f44a6922885088a1b Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Sat, 26 Oct 2024 19:03:59 +0200 Subject: [PATCH 37/45] Handling no-untyped-call type errors in manim/scene/scene.py Error count: 143 -> 131 --- manim/camera/moving_camera.py | 19 +++++++++++++------ manim/camera/three_d_camera.py | 2 +- manim/renderer/cairo_renderer.py | 2 +- manim/renderer/opengl_renderer.py | 25 +++++++++++++++++-------- manim/renderer/shader.py | 9 +++++++-- manim/scene/scene.py | 2 +- manim/utils/family_ops.py | 8 +++++++- 7 files changed, 47 insertions(+), 20 deletions(-) diff --git a/manim/camera/moving_camera.py b/manim/camera/moving_camera.py index 1d01d01e22..004d7beb6c 100644 --- a/manim/camera/moving_camera.py +++ b/manim/camera/moving_camera.py @@ -10,6 +10,8 @@ __all__ = ["MovingCamera"] +from typing import TYPE_CHECKING + import numpy as np from .. import config @@ -19,6 +21,11 @@ from ..mobject.mobject import Mobject from ..utils.color import WHITE +if TYPE_CHECKING: + from typing import Any + + from manim.utils.color import ParsableManimColor + class MovingCamera(Camera): """ @@ -32,12 +39,12 @@ class MovingCamera(Camera): def __init__( self, - frame=None, - fixed_dimension=0, # width - default_frame_stroke_color=WHITE, - default_frame_stroke_width=0, - **kwargs, - ): + frame: ScreenRectangle | None = None, + fixed_dimension: Any = 0, # width + default_frame_stroke_color: ParsableManimColor = WHITE, + default_frame_stroke_width: float = 0, + **kwargs: Any, + ) -> None: """ Frame is a Mobject, (should almost certainly be a rectangle) determining which region of space the camera displays diff --git a/manim/camera/three_d_camera.py b/manim/camera/three_d_camera.py index f45854e810..6d4dd0bb9c 100644 --- a/manim/camera/three_d_camera.py +++ b/manim/camera/three_d_camera.py @@ -84,7 +84,7 @@ def capture_mobjects(self, mobjects, **kwargs): self.reset_rotation_matrix() super().capture_mobjects(mobjects, **kwargs) - def get_value_trackers(self): + def get_value_trackers(self) -> list[ValueTracker]: """A list of :class:`ValueTrackers <.ValueTracker>` of phi, theta, focal_distance, gamma and zoom. diff --git a/manim/renderer/cairo_renderer.py b/manim/renderer/cairo_renderer.py index a45fcb6dd5..4d6b52b644 100644 --- a/manim/renderer/cairo_renderer.py +++ b/manim/renderer/cairo_renderer.py @@ -53,7 +53,7 @@ def __init__( self.time = 0 self.static_image = None - def init_scene(self, scene): + def init_scene(self, scene: Scene) -> None: self.file_writer: Any = self._file_writer_class( self, scene.__class__.__name__, diff --git a/manim/renderer/opengl_renderer.py b/manim/renderer/opengl_renderer.py index 6ca381cd54..abf38e10ce 100644 --- a/manim/renderer/opengl_renderer.py +++ b/manim/renderer/opengl_renderer.py @@ -4,7 +4,7 @@ import itertools as it import time from functools import cached_property -from typing import Any +from typing import TYPE_CHECKING, Any import moderngl import numpy as np @@ -35,6 +35,13 @@ render_opengl_vectorized_mobject_stroke, ) +if TYPE_CHECKING: + from typing_extensions import Self + + from manim.mobject.mobject import Mobject + from manim.scene.scene import Scene + + __all__ = ["OpenGLCamera", "OpenGLRenderer"] @@ -166,28 +173,28 @@ def set_euler_angles(self, theta=None, phi=None, gamma=None): self.refresh_rotation_matrix() return self - def set_theta(self, theta): + def set_theta(self, theta: float) -> Self: return self.set_euler_angles(theta=theta) - def set_phi(self, phi): + def set_phi(self, phi: float) -> Self: return self.set_euler_angles(phi=phi) - def set_gamma(self, gamma): + def set_gamma(self, gamma: float) -> Self: return self.set_euler_angles(gamma=gamma) - def increment_theta(self, dtheta): + def increment_theta(self, dtheta: float) -> Self: self.euler_angles[0] += dtheta self.refresh_rotation_matrix() return self - def increment_phi(self, dphi): + def increment_phi(self, dphi: float) -> Self: phi = self.euler_angles[1] new_phi = clip(phi + dphi, -PI / 2, PI / 2) self.euler_angles[1] = new_phi self.refresh_rotation_matrix() return self - def increment_gamma(self, dgamma): + def increment_gamma(self, dgamma: float) -> Self: self.euler_angles[2] += dgamma self.refresh_rotation_matrix() return self @@ -442,7 +449,9 @@ def clear_screen(self): self.frame_buffer_object.clear(*self.background_color) self.window.swap_buffers() - def render(self, scene, frame_offset, moving_mobjects): + def render( + self, scene: Scene, frame_offset, moving_mobjects: list[Mobject] + ) -> None: self.update_frame(scene) if self.skip_animations: diff --git a/manim/renderer/shader.py b/manim/renderer/shader.py index a098ed30ca..352fe23136 100644 --- a/manim/renderer/shader.py +++ b/manim/renderer/shader.py @@ -4,7 +4,9 @@ import inspect import re import textwrap +from collections.abc import Generator from pathlib import Path +from typing import TYPE_CHECKING import moderngl import numpy as np @@ -12,6 +14,9 @@ from .. import config from ..utils import opengl +if TYPE_CHECKING: + from typing_extensions import Self + SHADER_FOLDER = Path(__file__).parent / "shaders" shader_program_cache: dict = {} file_path_to_code_map: dict = {} @@ -143,7 +148,7 @@ def get_meshes(self): yield parent dfs.extend(parent.children) - def get_family(self): + def get_family(self) -> Generator[Object3D]: dfs = [self] while dfs: parent = dfs.pop() @@ -181,7 +186,7 @@ def init_updaters(self): self.has_updaters = False self.updating_suspended = False - def update(self, dt=0): + def update(self, dt: float = 0) -> Self: if not self.has_updaters or self.updating_suspended: return self for updater in self.time_based_updaters: diff --git a/manim/scene/scene.py b/manim/scene/scene.py index db4e0a00d6..82a3fe1141 100644 --- a/manim/scene/scene.py +++ b/manim/scene/scene.py @@ -352,7 +352,7 @@ def update_mobjects(self, dt: float) -> None: for mobject in self.mobjects: mobject.update(dt) - def update_meshes(self, dt) -> None: + def update_meshes(self, dt: float) -> None: for obj in self.meshes: for mesh in obj.get_family(): mesh.update(dt) diff --git a/manim/utils/family_ops.py b/manim/utils/family_ops.py index 8d4af9d5a5..b3c3596524 100644 --- a/manim/utils/family_ops.py +++ b/manim/utils/family_ops.py @@ -1,6 +1,10 @@ from __future__ import annotations import itertools as it +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from manim.mobject.mobject import Mobject __all__ = [ "extract_mobject_family_members", @@ -15,7 +19,9 @@ def extract_mobject_family_members(mobject_list, only_those_with_points=False): return result -def restructure_list_to_exclude_certain_family_members(mobject_list, to_remove): +def restructure_list_to_exclude_certain_family_members( + mobject_list: list[Mobject], to_remove: list[Mobject] +): """ Removes anything in to_remove from mobject_list, but in the event that one of the items to be removed is a member of the family of an item in mobject_list, From 90de4280ed9b0ce795c2cb52a5e7ec4943499ae4 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Sat, 26 Oct 2024 20:43:41 +0200 Subject: [PATCH 38/45] Handling assignment type errors in manim/scene/*.py Error count: 131 -> 121 --- manim/scene/moving_camera_scene.py | 2 +- manim/scene/scene.py | 13 +++++++------ manim/scene/three_d_scene.py | 13 ++++++------- manim/scene/vector_space_scene.py | 6 ++++-- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/manim/scene/moving_camera_scene.py b/manim/scene/moving_camera_scene.py index 748ab5fa31..8859a4d154 100644 --- a/manim/scene/moving_camera_scene.py +++ b/manim/scene/moving_camera_scene.py @@ -119,7 +119,7 @@ class MovingCameraScene(Scene): """ def __init__( - self, camera_class: MovingCamera = MovingCamera, **kwargs: Any + self, camera_class: type[MovingCamera] = MovingCamera, **kwargs: Any ) -> None: super().__init__(camera_class=camera_class, **kwargs) diff --git a/manim/scene/scene.py b/manim/scene/scene.py index 82a3fe1141..4555de6495 100644 --- a/manim/scene/scene.py +++ b/manim/scene/scene.py @@ -105,7 +105,7 @@ def construct(self): def __init__( self, renderer: CairoRenderer | OpenGLRenderer | None = None, - camera_class: Camera = Camera, + camera_class: type[Camera] = Camera, always_update_mobjects: bool = False, random_seed: int | None = None, skip_animations: bool = False, @@ -115,13 +115,14 @@ def __init__( self.random_seed = random_seed self.skip_animations = skip_animations - self.animations: list[Animation] = None - self.stop_condition = None + # TODO: We should probably change the default value to the empty list. + self.animations: list[Animation] | None = None + self.stop_condition: Callable[[], bool] | None = None self.moving_mobjects: list[Mobject] = [] self.static_mobjects: list[Mobject] = [] self.time_progression: tqdm[float] = None - self.duration = None - self.last_t = None + self.duration: float | None = None + self.last_t: float | None = None self.queue: Queue = Queue() self.skip_animation_preview = False self.meshes: list[Object3D] = [] @@ -474,7 +475,7 @@ def add(self, *mobjects: Mobject) -> Self: self.remove(*new_meshes) self.meshes += new_meshes elif config.renderer == RendererType.CAIRO: - mobjects = [*mobjects, *self.foreground_mobjects] + mobjects: list[Mobject] = [*mobjects, *self.foreground_mobjects] self.restructure_mobjects(to_remove=mobjects) self.mobjects += mobjects if self.moving_mobjects: diff --git a/manim/scene/three_d_scene.py b/manim/scene/three_d_scene.py index cc30dc67ea..a2f57e5426 100644 --- a/manim/scene/three_d_scene.py +++ b/manim/scene/three_d_scene.py @@ -25,7 +25,6 @@ from ..constants import DEGREES, RendererType from ..mobject.mobject import Mobject from ..mobject.types.vectorized_mobject import VectorizedPoint, VGroup -from ..renderer.opengl_renderer import OpenGLCamera from ..scene.scene import Scene from ..utils.config_ops import merge_dicts_recursively @@ -134,7 +133,7 @@ def begin_ambient_camera_rotation( x.add_updater(lambda m, dt: x.increment_value(rate * dt)) self.add(x) elif config.renderer == RendererType.OPENGL: - cam: OpenGLCamera = self.camera + cam: ThreeDCamera = self.camera methods = { "theta": cam.increment_theta, "phi": cam.increment_phi, @@ -278,7 +277,7 @@ def move_camera( if frame_center is not None: anims.append(self.camera._frame_center.animate.move_to(frame_center)) elif config.renderer == RendererType.OPENGL: - cam: OpenGLCamera = self.camera + cam: ThreeDCamera = self.camera cam2 = cam.copy() methods = { "theta": cam2.set_theta, @@ -365,7 +364,7 @@ def add_fixed_orientation_mobjects(self, *mobjects: Mobject, **kwargs: Any) -> N self.add(*mobjects) self.renderer.camera.add_fixed_orientation_mobjects(*mobjects, **kwargs) elif config.renderer == RendererType.OPENGL: - mob: OpenGLMobject + mob: Mobject for mob in mobjects: mob.fix_orientation() self.add(mob) @@ -387,7 +386,7 @@ def add_fixed_in_frame_mobjects(self, *mobjects: Mobject) -> None: self.camera: ThreeDCamera self.camera.add_fixed_in_frame_mobjects(*mobjects) elif config.renderer == RendererType.OPENGL: - mob: OpenGLMobject + mob: Mobject for mob in mobjects: mob.fix_in_frame() self.add(mob) @@ -408,7 +407,7 @@ def remove_fixed_orientation_mobjects(self, *mobjects: Mobject) -> None: if config.renderer == RendererType.CAIRO: self.renderer.camera.remove_fixed_orientation_mobjects(*mobjects) elif config.renderer == RendererType.OPENGL: - mob: OpenGLMobject + mob: Mobject for mob in mobjects: mob.unfix_orientation() self.remove(mob) @@ -428,7 +427,7 @@ def remove_fixed_in_frame_mobjects(self, *mobjects: Mobject) -> None: if config.renderer == RendererType.CAIRO: self.renderer.camera.remove_fixed_in_frame_mobjects(*mobjects) elif config.renderer == RendererType.OPENGL: - mob: OpenGLMobject + mob: Mobject for mob in mobjects: mob.unfix_from_frame() self.remove(mob) diff --git a/manim/scene/vector_space_scene.py b/manim/scene/vector_space_scene.py index b3f57026b5..c79131deae 100644 --- a/manim/scene/vector_space_scene.py +++ b/manim/scene/vector_space_scene.py @@ -333,10 +333,10 @@ def get_vector_label( if not rotate: label.rotate(-angle, about_point=ORIGIN) if direction == "left": - temp_shift_1: InternalPoint3D = label.get_bottom() + temp_shift_1: InternalPoint3D = np.asarray(label.get_bottom()) label.shift(-temp_shift_1 + 0.1 * UP) else: - temp_shift_2: InternalPoint3D = label.get_top() + temp_shift_2: InternalPoint3D = np.asarray(label.get_top()) label.shift(-temp_shift_2 + 0.1 * DOWN) label.rotate(angle, about_point=ORIGIN) label.shift((vector.get_end() - vector.get_start()) / 2) @@ -1107,6 +1107,8 @@ def get_transformable_label_movement(self) -> Animation: The animation of the movement. """ for label in self.transformable_labels: + # TODO: This location and lines 933 and 335 are the only locations in + # the code where the target_text property is referenced. target_text: MathTex | str = label.target_text label.target = self.get_vector_label( label.vector.target, target_text, **label.kwargs From 0a8c41e9428964566dd30a4e2009726625bf2934 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Sat, 26 Oct 2024 20:59:50 +0200 Subject: [PATCH 39/45] Handling arg-type type errors in manim/scene/*.py Error count: 121 -> 116 --- manim/animation/transform.py | 6 +++++- manim/scene/vector_space_scene.py | 12 +++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/manim/animation/transform.py b/manim/animation/transform.py index a7c62a9e6a..e00a6d3b28 100644 --- a/manim/animation/transform.py +++ b/manim/animation/transform.py @@ -49,6 +49,8 @@ from ..utils.rate_functions import smooth, squish_rate_func if TYPE_CHECKING: + from typing import Any + from ..scene.scene import Scene @@ -615,7 +617,9 @@ def __init__(self, mobject: Mobject, **kwargs) -> None: class ApplyFunction(Transform): - def __init__(self, function: types.MethodType, mobject: Mobject, **kwargs) -> None: + def __init__( + self, function: Callable[[Any], Any], mobject: Mobject, **kwargs: Any + ) -> None: self.function = function super().__init__(mobject, **kwargs) diff --git a/manim/scene/vector_space_scene.py b/manim/scene/vector_space_scene.py index c79131deae..c5fba1e287 100644 --- a/manim/scene/vector_space_scene.py +++ b/manim/scene/vector_space_scene.py @@ -130,7 +130,9 @@ def lock_in_faded_grid( self.add(axes) self.renderer.update_frame() - self.renderer.camera = Camera(self.renderer.get_frame()) + # TODO: To fix a type error, the output from get_frame() is + # sent to the background parameter of the Camera constructor. + self.renderer.camera = Camera(background=self.renderer.get_frame()) self.clear() def get_vector( @@ -194,7 +196,7 @@ def add_vector( The arrow representing the vector. """ if not isinstance(vector, Arrow): - vector = Vector(vector, color=color, **kwargs) + vector = Vector(np.asarray(vector), color=color, **kwargs) if animate: self.play(GrowArrow(vector)) self.add(vector) @@ -245,7 +247,11 @@ def get_basis_vectors( """ return VGroup( *( - Vector(vect, color=color, stroke_width=self.basis_vector_stroke_width) + Vector( + np.asarray(vect), + color=color, + stroke_width=self.basis_vector_stroke_width, + ) for vect, color in [([1, 0], i_hat_color), ([0, 1], j_hat_color)] ) ) From e8d97415293b8b4aa5795c1d83922ae8e7be0e9c Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Sat, 26 Oct 2024 21:32:23 +0200 Subject: [PATCH 40/45] Handling arg-type type errors in manim/scene/*.py Error count: 116 -> 112 --- manim/animation/transform.py | 2 +- manim/scene/scene.py | 12 ++++++++++-- manim/scene/three_d_scene.py | 4 ++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/manim/animation/transform.py b/manim/animation/transform.py index e00a6d3b28..7f16c668f5 100644 --- a/manim/animation/transform.py +++ b/manim/animation/transform.py @@ -518,7 +518,7 @@ def construct(self): def __init__( self, - function: types.MethodType, + function: Callable, mobject: Mobject, run_time: float = DEFAULT_POINTWISE_FUNCTION_RUN_TIME, **kwargs, diff --git a/manim/scene/scene.py b/manim/scene/scene.py index 4555de6495..bad253975d 100644 --- a/manim/scene/scene.py +++ b/manim/scene/scene.py @@ -116,6 +116,8 @@ def __init__( self.skip_animations = skip_animations # TODO: We should probably change the default value to the empty list. + # This would remove several type issues, but it also triggers a lot of + # errors in the unittests (pytest) self.animations: list[Animation] | None = None self.stop_condition: Callable[[], bool] | None = None self.moving_mobjects: list[Mobject] = [] @@ -145,6 +147,8 @@ def __init__( if renderer is None: self.renderer: CairoRenderer | OpenGLRenderer = CairoRenderer( + # TODO: Is it a suitable approach to make an instance of + # the self.camera_class here? camera_class=self.camera_class, skip_animations=self.skip_animations, ) @@ -521,8 +525,12 @@ def remove(self, *mobjects: Mobject) -> Self: self.mobjects, mobjects_to_remove, ) + + def lambda_function(mesh: Object3D) -> bool: + return mesh not in set(meshes_to_remove) + self.meshes = list( - filter(lambda mesh: mesh not in set(meshes_to_remove), self.meshes), + filter(lambda_function, self.meshes), ) return self elif config.renderer == RendererType.CAIRO: @@ -667,7 +675,7 @@ def restructure_mobjects( return self def get_restructured_mobject_list( - self, mobjects: list[Mobject], to_remove: list[Mobject] + self, mobjects: list[Mobject], to_remove: Sequence[Mobject] ) -> list[Mobject]: """ Given a list of mobjects and a list of mobjects to be removed, this diff --git a/manim/scene/three_d_scene.py b/manim/scene/three_d_scene.py index a2f57e5426..4b9ba15256 100644 --- a/manim/scene/three_d_scene.py +++ b/manim/scene/three_d_scene.py @@ -310,8 +310,8 @@ def move_camera( "focal distance of OpenGLCamera can not be adjusted.", stacklevel=2, ) - - anims += [Transform(cam, cam2)] + # TODO: Clarify if the mapping below is correct (mobject = cam and taget_mobject = cam2) + anims += [Transform(mobject=cam, target_mobject=cam2)] self.play(chain(*anims, added_anims), **kwargs) From 059566eecfcb1dbce18e5440c9804484553ac47f Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Sat, 26 Oct 2024 21:55:03 +0200 Subject: [PATCH 41/45] Fixing various type errors Error count: 112 -> 102 --- manim/scene/scene.py | 33 +++++++++++++++++++++++---------- manim/utils/family.py | 2 +- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/manim/scene/scene.py b/manim/scene/scene.py index bad253975d..c5bf3e9ef2 100644 --- a/manim/scene/scene.py +++ b/manim/scene/scene.py @@ -241,6 +241,7 @@ def render(self, preview: bool = False) -> bool: pass except RerunSceneException: self.remove(*self.mobjects) + # TODO: The CairoRenderer does not have the method clear_screen() self.renderer.clear_screen() self.renderer.num_plays = 0 return True @@ -265,6 +266,8 @@ def render(self, preview: bool = False) -> bool: if config["preview"] or config["show_in_file_browser"]: open_media_file(self.renderer.file_writer) + # TODO: What value should the function return when it reaches this point? + def setup(self) -> None: """ This is meant to be implemented by any scenes which @@ -394,7 +397,9 @@ def should_update_mobjects(self) -> bool: This is only called when a single Wait animation is played. """ + assert isinstance(self.animations, list) wait_animation = self.animations[0] + assert isinstance(wait_animation, Wait) if wait_animation.is_static_wait is None: should_update = ( self.always_update_mobjects @@ -468,7 +473,7 @@ def add(self, *mobjects: Mobject) -> Self: """ if config.renderer == RendererType.OPENGL: new_mobjects = [] - new_meshes = [] + new_meshes: list[Object3D] = [] for mobject_or_mesh in mobjects: if isinstance(mobject_or_mesh, Object3D): new_meshes.append(mobject_or_mesh) @@ -479,15 +484,18 @@ def add(self, *mobjects: Mobject) -> Self: self.remove(*new_meshes) self.meshes += new_meshes elif config.renderer == RendererType.CAIRO: - mobjects: list[Mobject] = [*mobjects, *self.foreground_mobjects] - self.restructure_mobjects(to_remove=mobjects) - self.mobjects += mobjects + new_and_foreground_mobjects: list[Mobject] = [ + *mobjects, + *self.foreground_mobjects, + ] + self.restructure_mobjects(to_remove=new_and_foreground_mobjects) + self.mobjects += new_and_foreground_mobjects if self.moving_mobjects: self.restructure_mobjects( - to_remove=mobjects, + to_remove=new_and_foreground_mobjects, mobject_list_name="moving_mobjects", ) - self.moving_mobjects += mobjects + self.moving_mobjects += new_and_foreground_mobjects return self def add_mobjects_from_animations(self, animations: list[Animation]) -> None: @@ -515,7 +523,7 @@ def remove(self, *mobjects: Mobject) -> Self: """ if config.renderer == RendererType.OPENGL: mobjects_to_remove = [] - meshes_to_remove = set() + meshes_to_remove: set[Object3D] = set() for mobject_or_mesh in mobjects: if isinstance(mobject_or_mesh, Object3D): meshes_to_remove.add(mobject_or_mesh) @@ -892,7 +900,10 @@ def get_moving_and_static_mobjects( def compile_animations( self, - *args: Animation | Iterable[Animation] | types.GeneratorType[Animation], + # TODO: Consider to remove the part with the types.GeneratorType + *args: Animation + | Iterable[Animation] + | types.GeneratorType[Animation, None, None], **kwargs: Any, ) -> list[Animation]: """ @@ -1074,7 +1085,9 @@ def get_run_time(self, animations: list[Animation]) -> float: def play( self, - *args: Animation | Iterable[Animation] | types.GeneratorType[Animation], + *args: Animation + | Iterable[Animation] + | types.GeneratorType[Animation, None, None], subcaption: str | None = None, subcaption_duration: float | None = None, subcaption_offset: float = 0, @@ -1686,7 +1699,7 @@ def on_mouse_drag( d_point: InternalPoint3D, buttons: int, modifiers: Any, - ): + ) -> None: assert isinstance(self.camera, OpenGLCamera) self.mouse_drag_point.move_to(point) if buttons == 1: diff --git a/manim/utils/family.py b/manim/utils/family.py index 17b39f347f..64da2a52af 100644 --- a/manim/utils/family.py +++ b/manim/utils/family.py @@ -13,7 +13,7 @@ def extract_mobject_family_members( mobjects: Iterable[Mobject], use_z_index=False, only_those_with_points: bool = False, -): +) -> list[Mobject]: """Returns a list of the types of mobjects and their family members present. A "family" in this context refers to a mobject, its submobjects, and their submobjects, recursively. From 5bba0916aa6d46874a48bcc257440564e124cff7 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Sat, 26 Oct 2024 22:08:20 +0200 Subject: [PATCH 42/45] Fixing various type errors Error count: 102 -> 97 --- manim/scene/scene.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/manim/scene/scene.py b/manim/scene/scene.py index c5bf3e9ef2..bd04d68387 100644 --- a/manim/scene/scene.py +++ b/manim/scene/scene.py @@ -53,6 +53,7 @@ if TYPE_CHECKING: from collections.abc import Iterable, Sequence + from types import FrameType from typing import Any, Callable from typing_extensions import Self @@ -124,6 +125,9 @@ def __init__( self.static_mobjects: list[Mobject] = [] self.time_progression: tqdm[float] = None self.duration: float | None = None + # TODO: We should probably change the default value to 0, to avoid + # handling the case where the value is None. + # This change triggers no errors in the unittests (pytest). self.last_t: float | None = None self.queue: Queue = Queue() self.skip_animation_preview = False @@ -1221,9 +1225,11 @@ def wait_until( def compile_animation_data( self, - *animations: Animation | Iterable[Animation] | types.GeneratorType[Animation], + *animations: Animation + | Iterable[Animation] + | types.GeneratorType[Animation, None, None], **play_kwargs: Any, - ) -> Self: + ) -> Self | None: """Given a list of animations, compile the corresponding static and moving mobjects, and gather the animation durations. @@ -1318,6 +1324,7 @@ def play_internal(self, skip_rendering: bool = False) -> None: animation.clean_up_from_scene(self) if not self.renderer.skip_animations: self.update_mobjects(0) + # TODO: The OpenGLRenderer does not have the property static.image. self.renderer.static_image = None # Closing the progress bar at the end of the play. self.time_progression.close() @@ -1387,7 +1394,7 @@ def get_embedded_method(method_name: str): from IPython.core.getipython import get_ipython from IPython.terminal.embed import InteractiveShellEmbed - from traitlets.config import Config + from traitlets.config import Config # type: ignore[import-untyped] cfg = Config() cfg.TerminalInteractiveShell.confirm_exit = False @@ -1529,7 +1536,9 @@ def embed(self) -> None: # Use the locals of the caller as the local namespace # once embedded, and add a few custom shortcuts. - local_ns = inspect.currentframe().f_back.f_locals + current_frame = inspect.currentframe() + assert isinstance(current_frame, FrameType) + local_ns = current_frame.f_back.f_locals # local_ns["touch"] = self.interact for method in ( "play", From 1165469c7ebe70860162ab6e075d716f65e4482a Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Sat, 26 Oct 2024 22:30:45 +0200 Subject: [PATCH 43/45] Fixing various type errors Error count: 97 -> 90 --- manim/camera/multi_camera.py | 6 ++++-- manim/scene/scene.py | 2 +- manim/scene/scene_file_writer.py | 2 +- manim/scene/three_d_scene.py | 5 +++-- manim/scene/vector_space_scene.py | 3 ++- manim/scene/zoomed_scene.py | 1 + 6 files changed, 12 insertions(+), 7 deletions(-) diff --git a/manim/camera/multi_camera.py b/manim/camera/multi_camera.py index a5202135e9..46c8889c5b 100644 --- a/manim/camera/multi_camera.py +++ b/manim/camera/multi_camera.py @@ -5,7 +5,7 @@ __all__ = ["MultiCamera"] -from manim.mobject.types.image_mobject import ImageMobject +from manim.mobject.types.image_mobject import ImageMobject, ImageMobjectFromCamera from ..camera.moving_camera import MovingCamera from ..utils.iterables import list_difference_update @@ -38,7 +38,9 @@ def __init__( ) super().__init__(**kwargs) - def add_image_mobject_from_camera(self, image_mobject_from_camera: ImageMobject): + def add_image_mobject_from_camera( + self, image_mobject_from_camera: ImageMobjectFromCamera + ): """Adds an ImageMobject that's been obtained from the camera into the list ``self.image_mobject_from_cameras`` diff --git a/manim/scene/scene.py b/manim/scene/scene.py index bd04d68387..54dcbf57eb 100644 --- a/manim/scene/scene.py +++ b/manim/scene/scene.py @@ -1814,7 +1814,7 @@ def mouse_drag_orbit_controls( ) self.camera_target += total_shift_vector - def set_key_function(self, char: int, func: Callable[[None], Any]) -> None: + def set_key_function(self, char: str, func: Callable[[None], Any]) -> None: self.key_to_function_map[char] = func def on_mouse_press( diff --git a/manim/scene/scene_file_writer.py b/manim/scene/scene_file_writer.py index 6096ac2b5a..634887b1b5 100644 --- a/manim/scene/scene_file_writer.py +++ b/manim/scene/scene_file_writer.py @@ -15,7 +15,7 @@ import av import numpy as np -import srt +import srt # type: ignore[import-untyped] from PIL import Image from pydub import AudioSegment diff --git a/manim/scene/three_d_scene.py b/manim/scene/three_d_scene.py index 4b9ba15256..f79f637e7a 100644 --- a/manim/scene/three_d_scene.py +++ b/manim/scene/three_d_scene.py @@ -31,6 +31,8 @@ if TYPE_CHECKING: from typing_extensions import Any + from ..renderer.opengl_renderer import OpenGLCamera + class ThreeDScene(Scene): """ @@ -133,7 +135,7 @@ def begin_ambient_camera_rotation( x.add_updater(lambda m, dt: x.increment_value(rate * dt)) self.add(x) elif config.renderer == RendererType.OPENGL: - cam: ThreeDCamera = self.camera + cam: OpenGLCamera = self.camera methods = { "theta": cam.increment_theta, "phi": cam.increment_phi, @@ -263,7 +265,6 @@ def move_camera( anims = [] if config.renderer == RendererType.CAIRO: - self.camera: ThreeDCamera value_tracker_pairs = [ (phi, self.camera.phi_tracker), (theta, self.camera.theta_tracker), diff --git a/manim/scene/vector_space_scene.py b/manim/scene/vector_space_scene.py index c5fba1e287..b31f2b11af 100644 --- a/manim/scene/vector_space_scene.py +++ b/manim/scene/vector_space_scene.py @@ -724,7 +724,8 @@ def add_background_mobject(self, *mobjects: Mobject) -> None: """ self.add_special_mobjects(self.background_mobjects, *mobjects) - # TODO, this conflicts with Scene.add_fore + # TODO, this conflicts with Scene.add_foreground_mobject + # Please be aware that there is also the method Scene.add_foreground_mobjects. def add_foreground_mobject(self, *mobjects: Mobject) -> None: """ Adds the mobjects to the special list diff --git a/manim/scene/zoomed_scene.py b/manim/scene/zoomed_scene.py index 685d4d4c35..b865051d08 100644 --- a/manim/scene/zoomed_scene.py +++ b/manim/scene/zoomed_scene.py @@ -150,6 +150,7 @@ def activate_zooming(self, animate: bool = False) -> None: of the zoomed camera. """ self.zoom_activated = True + assert isinstance(self.renderer.camera, MultiCamera) self.renderer.camera.add_image_mobject_from_camera(self.zoomed_display) if animate: self.play(self.get_zoom_in_animation()) From 4c1467435d118ecc3156ddf50350408a53059c0e Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Mon, 28 Oct 2024 08:20:16 +0100 Subject: [PATCH 44/45] Some aggressive changes to silence a significant number of type errors. Error count: 90 -> 66 --- manim/scene/scene.py | 4 ++-- manim/scene/scene_file_writer.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/manim/scene/scene.py b/manim/scene/scene.py index 54dcbf57eb..621062d3c3 100644 --- a/manim/scene/scene.py +++ b/manim/scene/scene.py @@ -119,7 +119,7 @@ def __init__( # TODO: We should probably change the default value to the empty list. # This would remove several type issues, but it also triggers a lot of # errors in the unittests (pytest) - self.animations: list[Animation] | None = None + self.animations: list[Animation] = [] self.stop_condition: Callable[[], bool] | None = None self.moving_mobjects: list[Mobject] = [] self.static_mobjects: list[Mobject] = [] @@ -128,7 +128,7 @@ def __init__( # TODO: We should probably change the default value to 0, to avoid # handling the case where the value is None. # This change triggers no errors in the unittests (pytest). - self.last_t: float | None = None + self.last_t: float = 0 self.queue: Queue = Queue() self.skip_animation_preview = False self.meshes: list[Object3D] = [] diff --git a/manim/scene/scene_file_writer.py b/manim/scene/scene_file_writer.py index 634887b1b5..f2592b9931 100644 --- a/manim/scene/scene_file_writer.py +++ b/manim/scene/scene_file_writer.py @@ -553,7 +553,7 @@ def open_partial_movie_stream(self, file_path: str | None = None) -> None: partial_movie_file_pix_fmt = "argb" with av.open(file_path, mode="w") as video_container: - stream = video_container.add_stream( + stream: Any = video_container.add_stream( partial_movie_file_codec, rate=fps, options=av_options, @@ -643,7 +643,7 @@ def combine_files( output_container.metadata["comment"] = ( f"Rendered with Manim Community v{__version__}" ) - output_stream = output_container.add_stream( + output_stream: Any = output_container.add_stream( codec_name="gif" if create_gif else None, template=partial_movies_stream if not create_gif else None, ) From bf7a82fedc0e797093ba398f4a69fb692f123418 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Mon, 28 Oct 2024 08:55:09 +0100 Subject: [PATCH 45/45] Commented out an import (IPython) that makes the CI tests fail. --- manim/scene/scene.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manim/scene/scene.py b/manim/scene/scene.py index 621062d3c3..9b0e2e4033 100644 --- a/manim/scene/scene.py +++ b/manim/scene/scene.py @@ -1429,7 +1429,7 @@ def get_embedded_method(method_name: str): self.interact(shell, keyboard_thread) - from IPython.terminal.embed import InteractiveShellEmbed + # from IPython.terminal.embed import InteractiveShellEmbed def interact( self, shell: InteractiveShellEmbed, keyboard_thread: threading.Thread