diff --git a/manim/mobject/mobject.py b/manim/mobject/mobject.py index ee487a7fc5..5a2d96a186 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: @@ -2196,6 +2202,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 +2319,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 +2692,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 +2794,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 +2978,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 86b5cd1386..d8b76afb41 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 @@ -733,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, @@ -795,6 +801,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 +832,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 +844,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 +881,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, @@ -1112,11 +1123,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 @@ -1144,6 +1157,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 @@ -1175,10 +1189,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. @@ -1205,11 +1220,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]: @@ -1236,6 +1253,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) @@ -1273,6 +1291,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( @@ -1281,6 +1300,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]: @@ -1289,6 +1309,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. @@ -1301,6 +1322,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. @@ -1318,6 +1340,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. @@ -1333,6 +1356,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, @@ -1361,6 +1385,7 @@ def get_nth_curve_length_pieces( return norms + @internal def get_nth_curve_length( self, n: int, @@ -1385,6 +1410,7 @@ def get_nth_curve_length( return length + @internal def get_nth_curve_function_with_length( self, n: int, @@ -1424,6 +1450,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]]: @@ -1440,6 +1467,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]]: @@ -1580,6 +1608,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]) @@ -1594,6 +1623,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. @@ -1604,6 +1634,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. @@ -1615,6 +1646,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. @@ -1729,6 +1761,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. @@ -1753,6 +1786,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]: @@ -1780,6 +1814,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: @@ -1800,6 +1835,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: @@ -1824,6 +1860,7 @@ def interpolate_color( val = val.copy() setattr(self, attr, val) + @internal def pointwise_become_partial( self, vmobject: VMobject, @@ -1917,6 +1954,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. diff --git a/manim/utils/decorators.py b/manim/utils/decorators.py new file mode 100644 index 0000000000..ff9e6b48d5 --- /dev/null +++ b/manim/utils/decorators.py @@ -0,0 +1,41 @@ +from __future__ import annotations + +import inspect +from collections.abc import Callable +from typing import Any, TypeVar + +F = TypeVar("F", bound=Callable[..., Any]) + + +def internal(f: F, /) -> F: + """ + 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): ... + """ + # 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 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)}" + return f