From b05ec3f49694f190c05696b651194f14804a5cb8 Mon Sep 17 00:00:00 2001 From: "F. Muenkel" <25496279+fmuenkel@users.noreply.github.com> Date: Wed, 26 Mar 2025 02:15:05 -0300 Subject: [PATCH 1/7] Stop ignoring manim._config erros in mypy.ini --- mypy.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy.ini b/mypy.ini index 4b5f718509..227305b1d1 100644 --- a/mypy.ini +++ b/mypy.ini @@ -49,7 +49,7 @@ warn_return_any = True # disable_recursive_aliases = True [mypy-manim._config.*] -ignore_errors = True +ignore_errors = False disable_error_code = return-value [mypy-manim._config.logger_utils] From 8818abe0f10acfde8eab376dcf104bf41004f2c2 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Sat, 26 Apr 2025 09:16:37 +0200 Subject: [PATCH 2/7] Fixing mypy issues in cli_colors.py --- manim/_config/cli_colors.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/manim/_config/cli_colors.py b/manim/_config/cli_colors.py index 5b1d151bdb..1eca1ac843 100644 --- a/manim/_config/cli_colors.py +++ b/manim/_config/cli_colors.py @@ -9,7 +9,7 @@ def parse_cli_ctx(parser: configparser.SectionProxy) -> dict[str, Any]: - formatter_settings: dict[str, str | int] = { + formatter_settings: dict[str, str | int | None] = { "indent_increment": int(parser["indent_increment"]), "width": int(parser["width"]), "col1_max_width": int(parser["col1_max_width"]), @@ -37,22 +37,24 @@ def parse_cli_ctx(parser: configparser.SectionProxy) -> dict[str, Any]: if theme is None: formatter = HelpFormatter.settings( theme=HelpTheme(**theme_settings), - **formatter_settings, # type: ignore[arg-type] + **formatter_settings, ) elif theme.lower() == "dark": formatter = HelpFormatter.settings( theme=HelpTheme.dark().with_(**theme_settings), - **formatter_settings, # type: ignore[arg-type] + **formatter_settings, ) elif theme.lower() == "light": formatter = HelpFormatter.settings( theme=HelpTheme.light().with_(**theme_settings), - **formatter_settings, # type: ignore[arg-type] + **formatter_settings, ) - return Context.settings( + return_val: dict[str, Any] = Context.settings( align_option_groups=parser["align_option_groups"].lower() == "true", align_sections=parser["align_sections"].lower() == "true", show_constraints=True, formatter_settings=formatter, ) + + return return_val From f3f32d83f877e7a5be3bf641ab094be03d47d07c Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Sat, 26 Apr 2025 12:00:36 +0200 Subject: [PATCH 3/7] Aspect ratio should be a float. --- manim/_config/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manim/_config/utils.py b/manim/_config/utils.py index f109af6939..0dfe8b61ae 100644 --- a/manim/_config/utils.py +++ b/manim/_config/utils.py @@ -1104,7 +1104,7 @@ def pixel_height(self, value: int) -> None: self._set_pos_number("pixel_height", value, False) @property - def aspect_ratio(self) -> int: + def aspect_ratio(self) -> float: """Aspect ratio (width / height) in pixels (--resolution, -r).""" return self._d["pixel_width"] / self._d["pixel_height"] From 6811ef386100474a07882475e65a34e2b8f28256 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Fri, 23 May 2025 09:00:45 +0200 Subject: [PATCH 4/7] Handled more mypy issues in _config/utils.py # Conflicts: # manim/_config/utils.py --- manim/_config/utils.py | 65 +++++++++++++++++++++++------------------- mypy.ini | 3 ++ 2 files changed, 39 insertions(+), 29 deletions(-) diff --git a/manim/_config/utils.py b/manim/_config/utils.py index 0dfe8b61ae..e90ca1db2e 100644 --- a/manim/_config/utils.py +++ b/manim/_config/utils.py @@ -20,7 +20,7 @@ import os import re import sys -from collections.abc import Iterable, Iterator, Mapping, MutableMapping +from collections.abc import Iterator, Mapping, MutableMapping from pathlib import Path from typing import TYPE_CHECKING, Any, ClassVar, NoReturn @@ -131,7 +131,7 @@ def make_config_parser( return parser -def _determine_quality(qual: str) -> str: +def _determine_quality(qual: str | None) -> str: for quality, values in constants.QUALITIES.items(): if values["flag"] is not None and values["flag"] == qual: return quality @@ -334,6 +334,7 @@ def __len__(self) -> int: def __contains__(self, key: object) -> bool: try: + assert isinstance(key, str) self.__getitem__(key) return True except AttributeError: @@ -653,8 +654,8 @@ def digest_parser(self, parser: configparser.ConfigParser) -> Self: # plugins plugins = parser["CLI"].get("plugins", fallback="", raw=True) - plugins = [] if plugins == "" else plugins.split(",") - self.plugins = plugins + plugin_list = [] if plugins is None or plugins == "" else plugins.split(",") + self.plugins = plugin_list # the next two must be set AFTER digesting pixel_width and pixel_height self["frame_height"] = parser["CLI"].getfloat("frame_height", 8.0) width = parser["CLI"].getfloat("frame_width", None) @@ -664,31 +665,31 @@ def digest_parser(self, parser: configparser.ConfigParser) -> Self: self["frame_width"] = width # other logic - val = parser["CLI"].get("tex_template_file") - if val: - self.tex_template_file = val + tex_template_file = parser["CLI"].get("tex_template_file") + if tex_template_file: + self.tex_template_file = Path(tex_template_file) - val = parser["CLI"].get("progress_bar") - if val: - self.progress_bar = val + progress_bar = parser["CLI"].get("progress_bar") + if progress_bar: + self.progress_bar = progress_bar - val = parser["ffmpeg"].get("loglevel") - if val: - self.ffmpeg_loglevel = val + ffmpeg_loglevel = parser["ffmpeg"].get("loglevel") + if ffmpeg_loglevel: + self.ffmpeg_loglevel = ffmpeg_loglevel try: - val = parser["jupyter"].getboolean("media_embed") + media_embed = parser["jupyter"].getboolean("media_embed") except ValueError: - val = None - self.media_embed = val + media_embed = None + self.media_embed = media_embed - val = parser["jupyter"].get("media_width") - if val: - self.media_width = val + media_width = parser["jupyter"].get("media_width") + if media_width: + self.media_width = media_width - val = parser["CLI"].get("quality", fallback="", raw=True) - if val: - self.quality = _determine_quality(val) + quality = parser["CLI"].get("quality", fallback="", raw=True) + if quality: + self.quality = _determine_quality(quality) return self @@ -1036,7 +1037,7 @@ def verbosity(self, val: str) -> None: logger.setLevel(val) @property - def format(self) -> str: + def format(self) -> str | None: """File format; "png", "gif", "mp4", "webm" or "mov".""" return self._d["format"] @@ -1068,7 +1069,7 @@ def ffmpeg_loglevel(self, val: str) -> None: logging.getLogger("libav").setLevel(self.ffmpeg_loglevel) @property - def media_embed(self) -> bool: + def media_embed(self) -> bool | None: """Whether to embed videos in Jupyter notebook.""" return self._d["media_embed"] @@ -1106,6 +1107,8 @@ def pixel_height(self, value: int) -> None: @property def aspect_ratio(self) -> float: """Aspect ratio (width / height) in pixels (--resolution, -r).""" + assert isinstance(self._d["pixel_width"], int) + assert isinstance(self._d["pixel_height"], int) return self._d["pixel_width"] / self._d["pixel_height"] @property @@ -1129,6 +1132,7 @@ def frame_width(self, value: float) -> None: @property def frame_y_radius(self) -> float: """Half the frame height (no flag).""" + assert isinstance(self._d["frame_height"], float) return self._d["frame_height"] / 2 @frame_y_radius.setter @@ -1140,6 +1144,7 @@ def frame_y_radius(self, value: float) -> None: @property def frame_x_radius(self) -> float: """Half the frame width (no flag).""" + assert isinstance(self._d["frame_width"], float) return self._d["frame_width"] / 2 @frame_x_radius.setter @@ -1304,6 +1309,7 @@ def quality(self, value: str | None) -> None: @property def transparent(self) -> bool: """Whether the background opacity is less than 1.0 (-t).""" + assert isinstance(self._d["background_opacity"], float) return self._d["background_opacity"] < 1.0 @transparent.setter @@ -1631,6 +1637,7 @@ def get_dir(self, key: str, **kwargs: Any) -> Path: all_args["quality"] = f"{self.pixel_height}p{self.frame_rate:g}" path = self._d[key] + assert isinstance(path, str) while "{" in path: try: path = path.format(**all_args) @@ -1730,7 +1737,7 @@ def custom_folders(self, value: str | Path) -> None: self._set_dir("custom_folders", value) @property - def input_file(self) -> str: + def input_file(self) -> str | Path: """Input file name.""" return self._d["input_file"] @@ -1759,7 +1766,7 @@ def scene_names(self, value: list[str]) -> None: @property def tex_template(self) -> TexTemplate: """Template used when rendering Tex. See :class:`.TexTemplate`.""" - if not hasattr(self, "_tex_template") or not self._tex_template: + if not hasattr(self, "_tex_template") or not self._tex_template: # type: ignore[has-type] fn = self._d["tex_template_file"] if fn: self._tex_template = TexTemplate.from_file(fn) @@ -1795,7 +1802,7 @@ def plugins(self) -> list[str]: return self._d["plugins"] @plugins.setter - def plugins(self, value: list[str]): + def plugins(self, value: list[str]) -> None: self._d["plugins"] = value @@ -1842,7 +1849,7 @@ def __init__(self, c: ManimConfig) -> None: self.__dict__["_c"] = c # there are required by parent class Mapping to behave like a dict - def __getitem__(self, key: str | int) -> Any: + def __getitem__(self, key: str) -> Any: if key in self._OPTS: return self._c[key] elif key in self._CONSTANTS: @@ -1850,7 +1857,7 @@ def __getitem__(self, key: str | int) -> Any: else: raise KeyError(key) - def __iter__(self) -> Iterable[str]: + def __iter__(self) -> Iterator[Any]: return iter(list(self._OPTS) + list(self._CONSTANTS)) def __len__(self) -> int: diff --git a/mypy.ini b/mypy.ini index 227305b1d1..602720871a 100644 --- a/mypy.ini +++ b/mypy.ini @@ -55,6 +55,9 @@ disable_error_code = return-value [mypy-manim._config.logger_utils] ignore_errors = False +[mypy-manim._config.utils] +ignore_errors = True + [mypy-manim.animation.*] ignore_errors = True From 3b9c8b866a4ebaa67288fb99bdde828befae7716 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Fri, 23 May 2025 09:01:31 +0200 Subject: [PATCH 5/7] Handled more mypy issues in _config/utils.py # Conflicts: # manim/_config/utils.py --- manim/_config/utils.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/manim/_config/utils.py b/manim/_config/utils.py index e90ca1db2e..791442dd25 100644 --- a/manim/_config/utils.py +++ b/manim/_config/utils.py @@ -425,7 +425,7 @@ def __deepcopy__(self, memo: dict[str, Any]) -> Self: # Deepcopying the underlying dict is enough because all properties # either read directly from it or compute their value on the fly from # values read directly from it. - c._d = copy.deepcopy(self._d, memo) + c._d = copy.deepcopy(self._d, memo) # type: ignore[arg-type] return c # helper type-checking methods @@ -649,8 +649,10 @@ def digest_parser(self, parser: configparser.ConfigParser) -> Self: "window_size" ] # if not "default", get a tuple of the position if window_size != "default": - window_size = tuple(map(int, re.split(r"[;,\-]", window_size))) - self.window_size = window_size + window_size_numbers = tuple(map(int, re.split(r"[;,\-]", window_size))) + self.window_size = window_size_numbers + else: + self.window_size = window_size # plugins plugins = parser["CLI"].get("plugins", fallback="", raw=True) @@ -1137,7 +1139,7 @@ def frame_y_radius(self) -> float: @frame_y_radius.setter def frame_y_radius(self, value: float) -> None: - self._d.__setitem__("frame_y_radius", value) or self._d.__setitem__( + self._d.__setitem__("frame_y_radius", value) or self._d.__setitem__( # type: ignore[func-returns-value] "frame_height", 2 * value ) @@ -1149,7 +1151,7 @@ def frame_x_radius(self) -> float: @frame_x_radius.setter def frame_x_radius(self, value: float) -> None: - self._d.__setitem__("frame_x_radius", value) or self._d.__setitem__( + self._d.__setitem__("frame_x_radius", value) or self._d.__setitem__( # type: ignore[func-returns-value] "frame_width", 2 * value ) @@ -1282,7 +1284,7 @@ def frame_size(self) -> tuple[int, int]: @frame_size.setter def frame_size(self, value: tuple[int, int]) -> None: - self._d.__setitem__("pixel_width", value[0]) or self._d.__setitem__( + self._d.__setitem__("pixel_width", value[0]) or self._d.__setitem__( # type: ignore[func-returns-value] "pixel_height", value[1] ) @@ -1292,7 +1294,7 @@ def quality(self) -> str | None: keys = ["pixel_width", "pixel_height", "frame_rate"] q = {k: self[k] for k in keys} for qual in constants.QUALITIES: - if all(q[k] == constants.QUALITIES[qual][k] for k in keys): + if all(q[k] == constants.QUALITIES[qual][k] for k in keys): # type: ignore[literal-required] return qual return None @@ -1419,12 +1421,12 @@ def window_position(self, value: str) -> None: self._d.__setitem__("window_position", value) @property - def window_size(self) -> str: + def window_size(self) -> str | tuple[int, ...]: """The size of the opengl window. 'default' to automatically scale the window based on the display monitor.""" return self._d["window_size"] @window_size.setter - def window_size(self, value: str) -> None: + def window_size(self, value: str | tuple[int, ...]) -> None: self._d.__setitem__("window_size", value) def resolve_movie_file_extension(self, is_transparent: bool) -> None: @@ -1875,4 +1877,4 @@ def __delitem__(self, key: Any) -> NoReturn: for opt in list(ManimFrame._OPTS) + list(ManimFrame._CONSTANTS): - setattr(ManimFrame, opt, property(lambda self, o=opt: self[o])) + setattr(ManimFrame, opt, property(lambda self, o=opt: self[o])) # type: ignore[misc] From 67108a0563a893a7468b64780b2b1c4c2356b683 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Sun, 27 Apr 2025 21:42:48 +0200 Subject: [PATCH 6/7] Removed two assert statements that triggered errors in the unittests. --- manim/_config/utils.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/manim/_config/utils.py b/manim/_config/utils.py index 791442dd25..736eb646bb 100644 --- a/manim/_config/utils.py +++ b/manim/_config/utils.py @@ -1134,8 +1134,7 @@ def frame_width(self, value: float) -> None: @property def frame_y_radius(self) -> float: """Half the frame height (no flag).""" - assert isinstance(self._d["frame_height"], float) - return self._d["frame_height"] / 2 + return self._d["frame_height"] / 2 # type: ignore[operator] @frame_y_radius.setter def frame_y_radius(self, value: float) -> None: @@ -1146,8 +1145,7 @@ def frame_y_radius(self, value: float) -> None: @property def frame_x_radius(self) -> float: """Half the frame width (no flag).""" - assert isinstance(self._d["frame_width"], float) - return self._d["frame_width"] / 2 + return self._d["frame_width"] / 2 # type: ignore[operator] @frame_x_radius.setter def frame_x_radius(self, value: float) -> None: From 3dd725db33bedde5ef4647335601851edd121dc6 Mon Sep 17 00:00:00 2001 From: Henrik Skov Midtiby Date: Fri, 23 May 2025 09:03:27 +0200 Subject: [PATCH 7/7] Fix last mypy issue in utils.py and activate mypy checking --- manim/_config/utils.py | 2 +- mypy.ini | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/manim/_config/utils.py b/manim/_config/utils.py index 736eb646bb..a10fde0031 100644 --- a/manim/_config/utils.py +++ b/manim/_config/utils.py @@ -1453,7 +1453,7 @@ def enable_gui(self, value: bool) -> None: self._set_boolean("enable_gui", value) @property - def gui_location(self) -> tuple[Any]: + def gui_location(self) -> tuple[int, ...]: """Location parameters for the GUI window (e.g., screen coordinates or layout settings).""" return self._d["gui_location"] diff --git a/mypy.ini b/mypy.ini index 602720871a..227305b1d1 100644 --- a/mypy.ini +++ b/mypy.ini @@ -55,9 +55,6 @@ disable_error_code = return-value [mypy-manim._config.logger_utils] ignore_errors = False -[mypy-manim._config.utils] -ignore_errors = True - [mypy-manim.animation.*] ignore_errors = True