From 8d7bb13ff151b94901c5d36da4f756f5d19f55de Mon Sep 17 00:00:00 2001 From: JasonGrace2282 Date: Thu, 30 May 2024 13:15:03 -0400 Subject: [PATCH 1/7] Add decorator --- manim/utils/decorators.py | 43 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 manim/utils/decorators.py diff --git a/manim/utils/decorators.py b/manim/utils/decorators.py new file mode 100644 index 0000000000..996a8ab2ee --- /dev/null +++ b/manim/utils/decorators.py @@ -0,0 +1,43 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from collections.abc import Callable + + from typing_extensions import ParamSpec + + P = ParamSpec("P") + T = TypeVar("T") + + +def internal(f: Callable[P, T]) -> Callable[P, T]: + """ + This decorator marks a function as internal + by adding a warning to the docstring of the object. + + Note that usage on a method starting with an underscore + has no effect, as sphinx does not document such methods + + .. code-block:: python + + @internal + def some_private_method(self): + # does some private stuff + ... + + + @internal # does not do anything, don't use + def _my_second_private_method(self): ... + """ + doc: str = f.__doc__ if f.__doc__ is not None else "" + newblockline = "\n " + directive = f".. warning::{newblockline}" + directive += newblockline.join( + ( + "This method is designed for internal use", + "and may not stay the same in future versions of Manim", + ) + ) + f.__doc__ = f"{directive}\n\n{doc}" + return f From bfea7da7895183fddf5fae5756505b0f9322b28d Mon Sep 17 00:00:00 2001 From: JasonGrace2282 Date: Thu, 30 May 2024 13:15:33 -0400 Subject: [PATCH 2/7] Mark some methods as internal on Mobject/VMobject --- manim/mobject/mobject.py | 15 ++++++++- manim/mobject/types/vectorized_mobject.py | 39 ++++++++++++++++++++++- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/manim/mobject/mobject.py b/manim/mobject/mobject.py index 6e405a18eb..cc7ed24cae 100644 --- a/manim/mobject/mobject.py +++ b/manim/mobject/mobject.py @@ -34,6 +34,7 @@ color_gradient, interpolate_color, ) +from ..utils.decorators import internal from ..utils.exceptions import MultiAnimationOverrideException from ..utils.iterables import list_update, remove_list_redundancies from ..utils.paths import straight_path @@ -83,6 +84,7 @@ class Mobject: animation_overrides = {} + @internal @classmethod def __init_subclass__(cls, **kwargs) -> None: super().__init_subclass__(**kwargs) @@ -1712,6 +1714,7 @@ def stretch_to_fit_depth(self, depth: float, **kwargs) -> Self: return self.rescale_to_fit(depth, 2, stretch=True, **kwargs) + @internal def set_coord(self, value, dim: int, direction: Vector3D = ORIGIN) -> Self: curr = self.get_coord(dim, direction) shift_vect = np.zeros(self.dim) @@ -1902,6 +1905,7 @@ def set_colors_by_radial_gradient( ) return self + @internal def set_submobject_colors_by_gradient(self, *colors: Iterable[ParsableManimColor]): if len(colors) == 0: raise ValueError("Need at least one color") @@ -1915,6 +1919,7 @@ def set_submobject_colors_by_gradient(self, *colors: Iterable[ParsableManimColor mob.set_color(color, family=False) return self + @internal def set_submobject_colors_by_radial_gradient( self, center: Point3D | None = None, @@ -2044,6 +2049,7 @@ def get_points_defining_boundary(self) -> Point3D_Array: def get_num_points(self) -> int: return len(self.points) + @internal def get_extremum_along_dim( self, points: Point3D_Array | None = None, dim: int = 0, key: int = 0 ) -> np.ndarray | float: @@ -2160,6 +2166,7 @@ def length_over_dim(self, dim: int) -> float: dim, ) - self.reduce_across_dimension(min, dim) + @internal def get_coord(self, dim: int, direction: Vector3D = ORIGIN): """Meant to generalize ``get_x``, ``get_y`` and ``get_z``""" return self.get_extremum_along_dim(dim=dim, key=direction[dim]) @@ -2196,6 +2203,7 @@ def point_from_proportion(self, alpha: float) -> Point3D: def proportion_from_point(self, point: Point3D) -> float: raise NotImplementedError("Please override in a child class.") + @internal def get_pieces(self, n_pieces: float) -> Group: template = self.copy() template.submobjects = [] @@ -2312,11 +2320,13 @@ def split(self) -> list[Self]: result = [self] if len(self.points) > 0 else [] return result + self.submobjects + @internal def get_family(self, recurse: bool = True) -> list[Self]: - sub_families = [x.get_family() for x in self.submobjects] + sub_families = [x.get_family(recurse=recurse) for x in self.submobjects] all_mobjects = [self] + list(it.chain(*sub_families)) return remove_list_redundancies(all_mobjects) + @internal def family_members_with_points(self) -> list[Self]: return [m for m in self.get_family() if m.get_num_points() > 0] @@ -2683,6 +2693,7 @@ def construct(self): return self.shuffle(*args, **kwargs) # Alignment + @internal def align_data(self, mobject: Mobject, skip_point_alignment: bool = False) -> None: """Aligns the data of this mobject with another mobject. @@ -2784,6 +2795,7 @@ def add_n_more_submobjects(self, n: int) -> Self | None: def repeat_submobject(self, submob: Mobject) -> Self: return submob.copy() + @internal def interpolate( self, mobject1: Mobject, @@ -2967,6 +2979,7 @@ def construct(self): return self # Errors + @internal def throw_error_if_no_points(self) -> None: if self.has_no_points(): caller_name = sys._getframe(1).f_code.co_name diff --git a/manim/mobject/types/vectorized_mobject.py b/manim/mobject/types/vectorized_mobject.py index cc938065d3..a4a22c0198 100644 --- a/manim/mobject/types/vectorized_mobject.py +++ b/manim/mobject/types/vectorized_mobject.py @@ -38,6 +38,7 @@ proportions_along_bezier_curve_for_point, ) from manim.utils.color import BLACK, WHITE, ManimColor, ParsableManimColor +from manim.utils.decorators import internal from manim.utils.iterables import ( make_even, resize_array, @@ -191,6 +192,7 @@ def get_mobject_type_class() -> type[VMobject]: return VMobject # Colors + @internal def init_colors(self, propagate_colors: bool = True) -> Self: self.set_fill( color=self.fill_color, @@ -221,6 +223,7 @@ def init_colors(self, propagate_colors: bool = True) -> Self: return self + @internal def generate_rgbas_array( self, color: ManimColor | list[ManimColor], opacity: float | Iterable[float] ) -> RGBA_Array_Float: @@ -249,6 +252,7 @@ def generate_rgbas_array( rgbas = np.append(rgbas, light_rgbas, axis=0) return rgbas + @internal def update_rgbas_array( self, array_name: str, @@ -708,6 +712,7 @@ def set_shade_in_3d( submob.z_index_group = self return self + @internal def set_points(self, points: Point3D_Array) -> Self: self.points: Point3D_Array = np.array(points) return self @@ -795,6 +800,7 @@ def append_points(self, new_points: Point3D_Array) -> Self: self.points = points return self + @internal def start_new_path(self, point: Point3D) -> Self: """Append a ``point`` to the :attr:`VMobject.points`, which will be the beginning of a new Bézier curve in the path given by the points. If @@ -825,6 +831,7 @@ def start_new_path(self, point: Point3D) -> Self: self.append_points([point]) return self + @internal def add_cubic_bezier_curve( self, anchor1: CubicBezierPoints, @@ -836,9 +843,11 @@ def add_cubic_bezier_curve( self.append_points([anchor1, handle1, handle2, anchor2]) # what type is curves? + @internal def add_cubic_bezier_curves(self, curves) -> None: self.append_points(curves.flatten()) + @internal def add_cubic_bezier_curve_to( self, handle1: CubicBezierPoints, @@ -871,6 +880,7 @@ def add_cubic_bezier_curve_to( self.append_points([self.get_last_point()] + new_points) return self + @internal def add_quadratic_bezier_curve_to( self, handle: QuadraticBezierPoints, @@ -1114,11 +1124,13 @@ def make_smooth(self) -> Self: def make_jagged(self) -> Self: return self.change_anchor_mode("jagged") + @internal def add_subpath(self, points: Point3D_Array) -> Self: assert len(points) % 4 == 0 self.append_points(points) return self + @internal def append_vectorized_mobject(self, vectorized_mobject: VMobject) -> None: if self.has_new_path_started(): # Remove last point, which is starting @@ -1146,6 +1158,7 @@ def rotate( super().rotate(angle, axis, about_point, **kwargs) return self + @internal def scale_handle_to_anchor_distances(self, factor: float) -> Self: """If the distance between a given handle point H and its associated anchor point A is d, then it changes H to be a distances factor*d @@ -1177,10 +1190,11 @@ def scale_handle_to_anchor_distances(self, factor: float) -> Self: submob.set_anchors_and_handles(a1, new_h1, new_h2, a2) return self - # + @internal def consider_points_equals(self, p0: Point3D, p1: Point3D) -> bool: return np.allclose(p0, p1, atol=self.tolerance_for_point_equality) + @internal def consider_points_equals_2d(self, p0: Point2D, p1: Point2D) -> bool: """Determine if two points are close enough to be considered equal. @@ -1207,11 +1221,13 @@ def consider_points_equals_2d(self, p0: Point2D, p1: Point2D) -> bool: return True # Information about line + @internal def get_cubic_bezier_tuples_from_points( self, points: Point3D_Array ) -> npt.NDArray[Point3D_Array]: return np.array(self.gen_cubic_bezier_tuples_from_points(points)) + @internal def gen_cubic_bezier_tuples_from_points( self, points: Point3D_Array ) -> tuple[Point3D_Array]: @@ -1238,6 +1254,7 @@ def gen_cubic_bezier_tuples_from_points( # Basically take every nppcc element. return tuple(points[i : i + nppcc] for i in range(0, len(points), nppcc)) + @internal def get_cubic_bezier_tuples(self) -> npt.NDArray[Point3D_Array]: return self.get_cubic_bezier_tuples_from_points(self.points) @@ -1275,6 +1292,7 @@ def _gen_subpaths_from_points( if (i2 - i1) >= nppcc ) + @internal def get_subpaths_from_points(self, points: Point3D_Array) -> list[Point3D_Array]: return list( self._gen_subpaths_from_points( @@ -1283,6 +1301,7 @@ def get_subpaths_from_points(self, points: Point3D_Array) -> list[Point3D_Array] ), ) + @internal def gen_subpaths_from_points_2d( self, points: Point3D_Array ) -> Generator[Point3D_Array]: @@ -1291,6 +1310,7 @@ def gen_subpaths_from_points_2d( lambda n: not self.consider_points_equals_2d(points[n - 1], points[n]), ) + @internal def get_subpaths(self) -> list[Point3D_Array]: """Returns subpaths formed by the curves of the VMobject. @@ -1303,6 +1323,7 @@ def get_subpaths(self) -> list[Point3D_Array]: """ return self.get_subpaths_from_points(self.points) + @internal def get_nth_curve_points(self, n: int) -> Point3D_Array: """Returns the points defining the nth curve of the vmobject. @@ -1320,6 +1341,7 @@ def get_nth_curve_points(self, n: int) -> Point3D_Array: nppcc = self.n_points_per_cubic_curve return self.points[nppcc * n : nppcc * (n + 1)] + @internal def get_nth_curve_function(self, n: int) -> Callable[[float], Point3D]: """Returns the expression of the nth curve. @@ -1335,6 +1357,7 @@ def get_nth_curve_function(self, n: int) -> Callable[[float], Point3D]: """ return bezier(self.get_nth_curve_points(n)) + @internal def get_nth_curve_length_pieces( self, n: int, @@ -1363,6 +1386,7 @@ def get_nth_curve_length_pieces( return norms + @internal def get_nth_curve_length( self, n: int, @@ -1387,6 +1411,7 @@ def get_nth_curve_length( return length + @internal def get_nth_curve_function_with_length( self, n: int, @@ -1426,6 +1451,7 @@ def get_num_curves(self) -> int: nppcc = self.n_points_per_cubic_curve return len(self.points) // nppcc + @internal def get_curve_functions( self, ) -> Generator[Callable[[float], Point3D]]: @@ -1442,6 +1468,7 @@ def get_curve_functions( for n in range(num_curves): yield self.get_nth_curve_function(n) + @internal def get_curve_functions_with_lengths( self, **kwargs ) -> Generator[tuple[Callable[[float], Point3D], float]]: @@ -1582,6 +1609,7 @@ def proportion_from_point( return alpha + @internal def get_anchors_and_handles(self) -> list[Point3D_Array]: """Returns anchors1, handles1, handles2, anchors2, where (anchors1[i], handles1[i], handles2[i], anchors2[i]) @@ -1596,6 +1624,7 @@ def get_anchors_and_handles(self) -> list[Point3D_Array]: nppcc = self.n_points_per_cubic_curve return [self.points[i::nppcc] for i in range(nppcc)] + @internal def get_start_anchors(self) -> Point3D_Array: """Returns the start anchors of the bezier curves. @@ -1606,6 +1635,7 @@ def get_start_anchors(self) -> Point3D_Array: """ return self.points[:: self.n_points_per_cubic_curve] + @internal def get_end_anchors(self) -> Point3D_Array: """Return the end anchors of the bezier curves. @@ -1617,6 +1647,7 @@ def get_end_anchors(self) -> Point3D_Array: nppcc = self.n_points_per_cubic_curve return self.points[nppcc - 1 :: nppcc] + @internal def get_anchors(self) -> Point3D_Array: """Returns the anchors of the curves forming the VMobject. @@ -1731,6 +1762,7 @@ def get_nth_subpath(path_list, n): vmobject.set_points(new_path2) return self + @internal def insert_n_curves(self, n: int) -> Self: """Inserts n curves to the bezier curves of the vmobject. @@ -1755,6 +1787,7 @@ def insert_n_curves(self, n: int) -> Self: self.append_points([new_path_point]) return self + @internal def insert_n_curves_to_point_list( self, n: int, points: Point3D_Array ) -> npt.NDArray[BezierPoints]: @@ -1782,6 +1815,7 @@ def insert_n_curves_to_point_list( new_points = new_bezier_tuples.reshape(-1, 3) return new_points + @internal def align_rgbas(self, vmobject: VMobject) -> Self: attrs = ["fill_rgbas", "stroke_rgbas", "background_stroke_rgbas"] for attr in attrs: @@ -1802,6 +1836,7 @@ def get_point_mobject(self, center: Point3D | None = None) -> VectorizedPoint: point.match_style(self) return point + @internal def interpolate_color( self, mobject1: VMobject, mobject2: VMobject, alpha: float ) -> None: @@ -1826,6 +1861,7 @@ def interpolate_color( val = val.copy() setattr(self, attr, val) + @internal def pointwise_become_partial( self, vmobject: VMobject, @@ -1888,6 +1924,7 @@ def pointwise_become_partial( ) return self + @internal def get_subcurve(self, a: float, b: float) -> Self: """Returns the subcurve of the VMobject between the interval [a, b]. The curve is a VMobject itself. From bd7eae72f921ad18ed12fdb91bfea1b4c3c0b6a9 Mon Sep 17 00:00:00 2001 From: JasonGrace2282 Date: Thu, 30 May 2024 21:57:33 -0400 Subject: [PATCH 3/7] Fix docstrings being weird and causing build warnings --- manim/utils/decorators.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/manim/utils/decorators.py b/manim/utils/decorators.py index 996a8ab2ee..32442d723f 100644 --- a/manim/utils/decorators.py +++ b/manim/utils/decorators.py @@ -1,5 +1,6 @@ from __future__ import annotations +import inspect from typing import TYPE_CHECKING, TypeVar if TYPE_CHECKING: @@ -30,14 +31,15 @@ def some_private_method(self): @internal # does not do anything, don't use def _my_second_private_method(self): ... """ - doc: str = f.__doc__ if f.__doc__ is not None else "" - newblockline = "\n " - directive = f".. warning::{newblockline}" - directive += newblockline.join( - ( - "This method is designed for internal use", - "and may not stay the same in future versions of Manim", - ) + # we have to keep the "No description provided" or + # docutils doesn't parse the directive properly + doc = f.__doc__ or "No description provided" + + directive = ( + ".. warning::\n\n" + " This method is designed for internal use and may not stay the same in future versions of Manim" + " Use these in your code at your own risk" ) - f.__doc__ = f"{directive}\n\n{doc}" + + f.__doc__ = f"{directive}\n\n{inspect.cleandoc(doc)}" return f From d5377cb1155e125684679ffdc388bf1e6a7b8c65 Mon Sep 17 00:00:00 2001 From: JasonGrace2282 Date: Fri, 31 May 2024 08:00:49 -0400 Subject: [PATCH 4/7] don't use ParamSpec --- manim/utils/decorators.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/manim/utils/decorators.py b/manim/utils/decorators.py index 32442d723f..1b81827dd9 100644 --- a/manim/utils/decorators.py +++ b/manim/utils/decorators.py @@ -1,18 +1,13 @@ from __future__ import annotations import inspect -from typing import TYPE_CHECKING, TypeVar +from collections.abc import Callable +from typing import Any, TypeVar -if TYPE_CHECKING: - from collections.abc import Callable +F = TypeVar("F", bound=Callable[..., Any]) - from typing_extensions import ParamSpec - P = ParamSpec("P") - T = TypeVar("T") - - -def internal(f: Callable[P, T]) -> Callable[P, T]: +def internal(f: F, /) -> F: """ This decorator marks a function as internal by adding a warning to the docstring of the object. From 97b7a575ba23134a893b068c060a5d7fbce878a2 Mon Sep 17 00:00:00 2001 From: JasonGrace2282 Date: Wed, 5 Jun 2024 12:08:03 -0400 Subject: [PATCH 5/7] Change spacing --- manim/utils/decorators.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/manim/utils/decorators.py b/manim/utils/decorators.py index 1b81827dd9..4e724ae467 100644 --- a/manim/utils/decorators.py +++ b/manim/utils/decorators.py @@ -31,9 +31,9 @@ def _my_second_private_method(self): ... doc = f.__doc__ or "No description provided" directive = ( - ".. warning::\n\n" - " This method is designed for internal use and may not stay the same in future versions of Manim" - " Use these in your code at your own risk" + ".. warning::\n\n " + "This method is designed for internal use and may not stay the same in future versions of Manim. " + "Use these in your code at your own risk" ) f.__doc__ = f"{directive}\n\n{inspect.cleandoc(doc)}" From 10fa509a72e0e313810e8083affafb4d583ac425 Mon Sep 17 00:00:00 2001 From: adeshpande <110117391+JasonGrace2282@users.noreply.github.com> Date: Sun, 14 Jul 2024 09:57:35 -0400 Subject: [PATCH 6/7] Improve decorator message Co-authored-by: Benjamin Hackl --- manim/utils/decorators.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/manim/utils/decorators.py b/manim/utils/decorators.py index 4e724ae467..ff9e6b48d5 100644 --- a/manim/utils/decorators.py +++ b/manim/utils/decorators.py @@ -32,8 +32,9 @@ def _my_second_private_method(self): ... directive = ( ".. warning::\n\n " - "This method is designed for internal use and may not stay the same in future versions of Manim. " - "Use these in your code at your own risk" + "This method is part of Manim's internal interface, changes " + "to its behavior might happen without following usual deprecation " + "periods. Use in your code at your own risk." ) f.__doc__ = f"{directive}\n\n{inspect.cleandoc(doc)}" From c6c65332757f9e6fc4e5ad199802aee2a0c61037 Mon Sep 17 00:00:00 2001 From: JasonGrace2282 Date: Sun, 14 Jul 2024 15:43:59 -0400 Subject: [PATCH 7/7] Some feedback --- manim/mobject/mobject.py | 1 - manim/mobject/types/vectorized_mobject.py | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/manim/mobject/mobject.py b/manim/mobject/mobject.py index cc7ed24cae..cfefc9197a 100644 --- a/manim/mobject/mobject.py +++ b/manim/mobject/mobject.py @@ -2166,7 +2166,6 @@ def length_over_dim(self, dim: int) -> float: dim, ) - self.reduce_across_dimension(min, dim) - @internal def get_coord(self, dim: int, direction: Vector3D = ORIGIN): """Meant to generalize ``get_x``, ``get_y`` and ``get_z``""" return self.get_extremum_along_dim(dim=dim, key=direction[dim]) diff --git a/manim/mobject/types/vectorized_mobject.py b/manim/mobject/types/vectorized_mobject.py index 006972d667..b0ac3613fe 100644 --- a/manim/mobject/types/vectorized_mobject.py +++ b/manim/mobject/types/vectorized_mobject.py @@ -738,6 +738,7 @@ def resize_points( self.points = resize_func(self.points, new_length) return self + @internal def set_anchors_and_handles( self, anchors1: CubicBezierPoints,