Skip to content

Add typing annotations to svg_mobject.py #4318

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 20, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 22 additions & 17 deletions manim/mobject/svg/svg_mobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import os
from pathlib import Path
from typing import Any
from xml.etree import ElementTree as ET

import numpy as np
Expand Down Expand Up @@ -108,7 +109,7 @@
svg_default: dict | None = None,
path_string_config: dict | None = None,
use_svg_cache: bool = True,
**kwargs,
**kwargs: Any,
):
super().__init__(color=None, stroke_color=None, fill_color=None, **kwargs)

Expand All @@ -121,10 +122,10 @@
self.color = color
self.opacity = opacity
self.fill_color = fill_color
self.fill_opacity = fill_opacity
self.fill_opacity = fill_opacity # type: ignore[assignment]

Check warning

Code scanning / CodeQL

Overwriting attribute in super-class or sub-class Warning

Assignment overwrites attribute fill_opacity, which was previously defined in superclass
VMobject
.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type annotations for the SVGMobject allows this value to be None, which is not compatible with the superclass VMobject. It seems to be fixed using some kind of default SVG value magic a few lines later.

self.stroke_color = stroke_color
self.stroke_opacity = stroke_opacity
self.stroke_width = stroke_width
self.stroke_opacity = stroke_opacity # type: ignore[assignment]

Check warning

Code scanning / CodeQL

Overwriting attribute in super-class or sub-class Warning

Assignment overwrites attribute stroke_opacity, which was previously defined in superclass
VMobject
.
self.stroke_width = stroke_width # type: ignore[assignment]
Comment on lines +127 to +128
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

Check warning

Code scanning / CodeQL

Overwriting attribute in super-class or sub-class Warning

Assignment overwrites attribute stroke_width, which was previously defined in superclass
VMobject
.

if svg_default is None:
svg_default = {
Expand Down Expand Up @@ -262,13 +263,13 @@
svg
The parsed SVG file.
"""
result = []
result: list[VMobject] = []
for shape in svg.elements():
# can we combine the two continue cases into one?
if isinstance(shape, se.Group): # noqa: SIM114
continue
elif isinstance(shape, se.Path):
mob = self.path_to_mobject(shape)
mob: VMobject = self.path_to_mobject(shape)
elif isinstance(shape, se.SimpleLine):
mob = self.line_to_mobject(shape)
elif isinstance(shape, se.Rect):
Expand Down Expand Up @@ -422,7 +423,7 @@
return vmobject_class().set_points_as_corners(points)

@staticmethod
def text_to_mobject(text: se.Text):
def text_to_mobject(text: se.Text) -> VMobject:
"""Convert a text element to a vectorized mobject.

.. warning::
Expand All @@ -435,7 +436,7 @@
The parsed SVG text.
"""
logger.warning(f"Unsupported element type: {type(text)}")
return
return # type: ignore[return-value]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we get rid of this mypy ignore statement?


def move_into_position(self) -> None:
"""Scale and move the generated mobject into position."""
Expand Down Expand Up @@ -480,7 +481,7 @@
long_lines: bool = False,
should_subdivide_sharp_curves: bool = False,
should_remove_null_curves: bool = False,
**kwargs,
**kwargs: Any,
):
# Get rid of arcs
path_obj.approximate_arcs_with_quads()
Expand Down Expand Up @@ -509,11 +510,11 @@

def handle_commands(self) -> None:
all_points: list[np.ndarray] = []
last_move = None
last_move: np.ndarray = None
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The np.ndarray type seems to work here. But is there any better? I don't think it should be Point3DLike.

curve_start = None
last_true_move = None

def move_pen(pt, *, true_move: bool = False):
def move_pen(pt: np.ndarray, *, true_move: bool = False) -> None:
nonlocal last_move, curve_start, last_true_move
last_move = pt
if curve_start is None:
Expand All @@ -523,25 +524,29 @@

if self.n_points_per_curve == 4:

def add_cubic(start, cp1, cp2, end):
def add_cubic(
start: np.ndarray, cp1: np.ndarray, cp2: np.ndarray, end: np.ndarray
) -> None:
nonlocal all_points
assert len(all_points) % 4 == 0, len(all_points)
all_points += [start, cp1, cp2, end]
move_pen(end)

def add_quad(start, cp, end):
def add_quad(start: np.ndarray, cp: np.ndarray, end: np.ndarray) -> None:
add_cubic(start, (start + cp + cp) / 3, (cp + cp + end) / 3, end)
move_pen(end)

def add_line(start, end):
def add_line(start: np.ndarray, end: np.ndarray) -> None:
add_cubic(
start, (start + start + end) / 3, (start + end + end) / 3, end
)
move_pen(end)

else:

def add_cubic(start, cp1, cp2, end):
def add_cubic(
start: np.ndarray, cp1: np.ndarray, cp2: np.ndarray, end: np.ndarray
) -> None:
nonlocal all_points
assert len(all_points) % 3 == 0, len(all_points)
two_quads = get_quadratic_approximation_of_cubic(
Expand All @@ -554,13 +559,13 @@
all_points += two_quads[3:].tolist()
move_pen(end)

def add_quad(start, cp, end):
def add_quad(start: np.ndarray, cp: np.ndarray, end: np.ndarray) -> None:
nonlocal all_points
assert len(all_points) % 3 == 0, len(all_points)
all_points += [start, cp, end]
move_pen(end)

def add_line(start, end):
def add_line(start: np.ndarray, end: np.ndarray) -> None:
add_quad(start, (start + end) / 2, end)
move_pen(end)

Expand Down
3 changes: 0 additions & 3 deletions mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,6 @@ ignore_errors = True
[mypy-manim.mobject.svg.brace]
ignore_errors = True

[mypy-manim.mobject.svg.svg_mobject]
ignore_errors = True

[mypy-manim.mobject.table]
ignore_errors = True

Expand Down