mirror of
https://github.com/ManimCommunity/manim.git
synced 2026-06-22 10:01:47 +00:00
Add type annotations to manim/_config/utils.py (#4230)
* Stop ignoring manim._config erros in mypy.ini * Aspect ratio should be a float. * Handled more mypy issues in _config/utils.py * Handled more mypy issues in _config/utils.py * Removed two assert statements that triggered errors in the unittests. * Fix last mypy issue in utils.py and activate mypy checking * Fix type of window_size in opengl_renderer_window.py * ... --------- Co-authored-by: F. Muenkel <25496279+fmuenkel@users.noreply.github.com> Co-authored-by: Francisco Manríquez Novoa <49853152+chopan050@users.noreply.github.com> Co-authored-by: Benjamin Hackl <devel@benjamin-hackl.at>
This commit is contained in:
parent
33a0e56d73
commit
a0414dccec
2 changed files with 63 additions and 49 deletions
|
|
@ -20,7 +20,7 @@ import logging
|
|||
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
|
||||
|
||||
|
|
@ -134,7 +134,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
|
||||
|
|
@ -338,6 +338,7 @@ class ManimConfig(MutableMapping):
|
|||
|
||||
def __contains__(self, key: object) -> bool:
|
||||
try:
|
||||
assert isinstance(key, str)
|
||||
self.__getitem__(key)
|
||||
return True
|
||||
except AttributeError:
|
||||
|
|
@ -428,7 +429,7 @@ class ManimConfig(MutableMapping):
|
|||
# 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
|
||||
|
|
@ -655,13 +656,15 @@ class ManimConfig(MutableMapping):
|
|||
"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)
|
||||
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)
|
||||
|
|
@ -671,31 +674,31 @@ class ManimConfig(MutableMapping):
|
|||
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
|
||||
|
||||
|
|
@ -1044,7 +1047,7 @@ class ManimConfig(MutableMapping):
|
|||
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"]
|
||||
|
||||
|
|
@ -1076,7 +1079,7 @@ class ManimConfig(MutableMapping):
|
|||
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"]
|
||||
|
||||
|
|
@ -1112,8 +1115,10 @@ class ManimConfig(MutableMapping):
|
|||
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)."""
|
||||
assert isinstance(self._d["pixel_width"], int)
|
||||
assert isinstance(self._d["pixel_height"], int)
|
||||
return self._d["pixel_width"] / self._d["pixel_height"]
|
||||
|
||||
@property
|
||||
|
|
@ -1137,22 +1142,22 @@ class ManimConfig(MutableMapping):
|
|||
@property
|
||||
def frame_y_radius(self) -> float:
|
||||
"""Half the frame height (no flag)."""
|
||||
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:
|
||||
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
|
||||
)
|
||||
|
||||
@property
|
||||
def frame_x_radius(self) -> float:
|
||||
"""Half the frame width (no flag)."""
|
||||
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:
|
||||
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
|
||||
)
|
||||
|
||||
|
|
@ -1285,7 +1290,7 @@ class ManimConfig(MutableMapping):
|
|||
|
||||
@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]
|
||||
)
|
||||
|
||||
|
|
@ -1295,7 +1300,7 @@ class ManimConfig(MutableMapping):
|
|||
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
|
||||
|
||||
|
|
@ -1312,6 +1317,7 @@ class ManimConfig(MutableMapping):
|
|||
@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
|
||||
|
|
@ -1421,12 +1427,12 @@ class ManimConfig(MutableMapping):
|
|||
self._d.__setitem__("window_position", value)
|
||||
|
||||
@property
|
||||
def window_size(self) -> str:
|
||||
"""The size of the opengl window as 'width,height' or 'default' to automatically scale the window based on the display monitor."""
|
||||
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:
|
||||
|
|
@ -1455,7 +1461,7 @@ class ManimConfig(MutableMapping):
|
|||
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"]
|
||||
|
||||
|
|
@ -1639,6 +1645,7 @@ class ManimConfig(MutableMapping):
|
|||
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)
|
||||
|
|
@ -1738,7 +1745,7 @@ class ManimConfig(MutableMapping):
|
|||
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"]
|
||||
|
||||
|
|
@ -1767,7 +1774,7 @@ class ManimConfig(MutableMapping):
|
|||
@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)
|
||||
|
|
@ -1803,7 +1810,7 @@ class ManimConfig(MutableMapping):
|
|||
return self._d["plugins"]
|
||||
|
||||
@plugins.setter
|
||||
def plugins(self, value: list[str]):
|
||||
def plugins(self, value: list[str]) -> None:
|
||||
self._d["plugins"] = value
|
||||
|
||||
@property
|
||||
|
|
@ -1861,7 +1868,7 @@ class ManimFrame(Mapping):
|
|||
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:
|
||||
|
|
@ -1869,7 +1876,7 @@ class ManimFrame(Mapping):
|
|||
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:
|
||||
|
|
@ -1887,4 +1894,4 @@ class ManimFrame(Mapping):
|
|||
|
||||
|
||||
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]
|
||||
|
|
|
|||
|
|
@ -25,14 +25,23 @@ class Window(PygletWindow):
|
|||
def __init__(
|
||||
self,
|
||||
renderer: OpenGLRenderer,
|
||||
window_size: str = config.window_size,
|
||||
window_size: str | tuple[int, ...] = config.window_size,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
monitors = get_monitors()
|
||||
mon_index = config.window_monitor
|
||||
monitor = monitors[min(mon_index, len(monitors) - 1)]
|
||||
|
||||
if window_size == "default":
|
||||
invalid_window_size_error_message = (
|
||||
"window_size must be specified either as 'default', a string of the form "
|
||||
"'width,height', or a tuple of 2 ints of the form (width, height)."
|
||||
)
|
||||
|
||||
if isinstance(window_size, tuple):
|
||||
if len(window_size) != 2:
|
||||
raise ValueError(invalid_window_size_error_message)
|
||||
size = window_size
|
||||
elif window_size == "default":
|
||||
# make window_width half the width of the monitor
|
||||
# but make it full screen if --fullscreen
|
||||
window_width = monitor.width
|
||||
|
|
@ -48,9 +57,7 @@ class Window(PygletWindow):
|
|||
(window_width, window_height) = tuple(map(int, window_size.split(",")))
|
||||
size = (window_width, window_height)
|
||||
else:
|
||||
raise ValueError(
|
||||
"Window_size must be specified as 'width,height' or 'default'.",
|
||||
)
|
||||
raise ValueError(invalid_window_size_error_message)
|
||||
|
||||
super().__init__(size=size)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue