chore(ci): pre-commit mypy (#41)

* chore(ci): pre-commit mypy

* chore: ignore non-lib files

* chore: ignore setup.py

* [pre-commit.ci] pre-commit autoupdate (#47)

updates:
- [github.com/psf/black: 22.8.0 → 22.10.0](https://github.com/psf/black/compare/22.8.0...22.10.0)
- [github.com/psf/black: 22.8.0 → 22.10.0](https://github.com/psf/black/compare/22.8.0...22.10.0)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* chore(ci): pre-commit mypy

* chore: ignore non-lib files

* chore: ignore setup.py

* fix: update pre-commit config for mypy

* feat: add some missing type hints

Co-authored-by: Jérome Eertmans <jeertmans@icloud.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Wu Tingfeng
2022-10-11 17:05:58 +08:00
committed by GitHub
parent 51a87840ce
commit 5b9cb1523c
9 changed files with 89 additions and 34 deletions

View File

@ -28,3 +28,39 @@ repos:
- flake8-comprehensions - flake8-comprehensions
- flake8-tidy-imports - flake8-tidy-imports
- flake8-typing-imports - flake8-typing-imports
- repo: https://github.com/pre-commit/mirrors-mypy
rev: 'v0.982'
hooks:
- id: mypy
args:
- --install-types
- --non-interactive
- --ignore-missing-imports
# Disallow dynamic typing
- --disallow-any-unimported
- --disallow-any-expr
- --disallow-any-decorated
- --disallow-any-generics
- --disallow-any-explicit
- --disallow-subclassing-any
# Disallow untyped definitions and calls
- --disallow-untyped-defs
- --disallow-incomplete-defs
- --check-untyped-defs
- --disallow-untyped-decorators
# None and optional handling
- --no-implicit-optional
# Configuring warnings
- --warn-unused-ignores
- --warn-no-return
- --warn-return-any
- --warn-redundant-casts
# Strict equality
- --strict-equality
# Config file
- --warn-unused-configs

View File

@ -1,3 +1,4 @@
# type: ignore
# Configuration file for the Sphinx documentation builder. # Configuration file for the Sphinx documentation builder.
# #
# For the full list of built-in configuration values, see the documentation: # For the full list of built-in configuration values, see the documentation:

View File

@ -1,4 +1,5 @@
# flake8: noqa: F403, F405 # flake8: noqa: F403, F405
# type: ignore
import sys import sys
if "manim" in sys.modules: if "manim" in sys.modules:

View File

@ -1,14 +1,29 @@
import platform import platform
from typing import Tuple
import cv2 import cv2
FONT_ARGS = (cv2.FONT_HERSHEY_SIMPLEX, 1, 255, 1, cv2.LINE_AA) __all__ = [
"FONT_ARGS",
"FOLDER_PATH",
"CONFIG_PATH",
"RIGHT_ARROW_KEY_CODE",
"LEFT_ARROW_KEY_CODE",
]
FONT_ARGS: Tuple[int, int, int, int, int] = (
cv2.FONT_HERSHEY_SIMPLEX, # type: ignore
1,
255,
1,
cv2.LINE_AA, # type: ignore
)
FOLDER_PATH: str = "./slides" FOLDER_PATH: str = "./slides"
CONFIG_PATH: str = ".manim-slides.json" CONFIG_PATH: str = ".manim-slides.json"
if platform.system() == "Windows": if platform.system() == "Windows":
RIGHT_ARROW_KEY_CODE = 2555904 RIGHT_ARROW_KEY_CODE: int = 2555904
LEFT_ARROW_KEY_CODE = 2424832 LEFT_ARROW_KEY_CODE: int = 2424832
elif platform.system() == "Darwin": elif platform.system() == "Darwin":
RIGHT_ARROW_KEY_CODE = 63235 RIGHT_ARROW_KEY_CODE = 63235
LEFT_ARROW_KEY_CODE = 63234 LEFT_ARROW_KEY_CODE = 63234

View File

@ -21,7 +21,7 @@ __all__ = [
@contextmanager @contextmanager
def suppress_stdout(): def suppress_stdout() -> None:
with open(os.devnull, "w") as devnull: with open(os.devnull, "w") as devnull:
old_stdout = sys.stdout old_stdout = sys.stdout
sys.stdout = devnull sys.stdout = devnull

View File

@ -56,7 +56,7 @@ def fix_time(t: float) -> float:
class Presentation: class Presentation:
"""Creates presentation from a configuration object.""" """Creates presentation from a configuration object."""
def __init__(self, config: PresentationConfig): def __init__(self, config: PresentationConfig) -> None:
self.slides: List[SlideConfig] = config.slides self.slides: List[SlideConfig] = config.slides
self.files: List[str] = config.files self.files: List[str] = config.files
@ -90,14 +90,14 @@ class Presentation:
"""Returns last slide.""" """Returns last slide."""
return self.slides[-1] return self.slides[-1]
def release_cap(self): def release_cap(self) -> None:
"""Releases current Video Capture, if existing.""" """Releases current Video Capture, if existing."""
if self.cap is not None: if self.cap is not None:
self.cap.release() self.cap.release()
self.loaded_animation_cap = -1 self.loaded_animation_cap = -1
def load_animation_cap(self, animation: int): def load_animation_cap(self, animation: int) -> None:
"""Loads video file of given animation.""" """Loads video file of given animation."""
# We must load a new VideoCapture file if: # We must load a new VideoCapture file if:
if (self.loaded_animation_cap != animation) or ( if (self.loaded_animation_cap != animation) or (
@ -123,7 +123,7 @@ class Presentation:
self.load_animation_cap(self.current_animation) self.load_animation_cap(self.current_animation)
return self.cap return self.cap
def rewind_current_slide(self): def rewind_current_slide(self) -> None:
"""Rewinds current slide to first frame.""" """Rewinds current slide to first frame."""
if self.reverse: if self.reverse:
self.current_animation = self.current_slide.end_animation - 1 self.current_animation = self.current_slide.end_animation - 1
@ -132,19 +132,19 @@ class Presentation:
self.current_cap.set(cv2.CAP_PROP_POS_FRAMES, 0) self.current_cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
def cancel_reverse(self): def cancel_reverse(self) -> None:
"""Cancels any effet produced by a reversed slide.""" """Cancels any effet produced by a reversed slide."""
if self.reverse: if self.reverse:
self.reverse = False self.reverse = False
self.reversed_animation = -1 self.reversed_animation = -1
self.release_cap() self.release_cap()
def reverse_current_slide(self): def reverse_current_slide(self) -> None:
"""Reverses current slide.""" """Reverses current slide."""
self.reverse = True self.reverse = True
self.rewind_current_slide() self.rewind_current_slide()
def load_next_slide(self): def load_next_slide(self) -> None:
"""Loads next slide.""" """Loads next slide."""
if self.reverse: if self.reverse:
self.cancel_reverse() self.cancel_reverse()
@ -157,7 +157,7 @@ class Presentation:
) )
self.rewind_current_slide() self.rewind_current_slide()
def load_previous_slide(self): def load_previous_slide(self) -> None:
"""Loads previous slide.""" """Loads previous slide."""
self.cancel_reverse() self.cancel_reverse()
self.current_slide_index = max(0, self.current_slide_index - 1) self.current_slide_index = max(0, self.current_slide_index - 1)
@ -168,7 +168,7 @@ class Presentation:
"""Returns the number of frames per second of the current video.""" """Returns the number of frames per second of the current video."""
return self.current_cap.get(cv2.CAP_PROP_FPS) return self.current_cap.get(cv2.CAP_PROP_FPS)
def add_last_slide(self): def add_last_slide(self) -> None:
"""Add a 'last' slide to the end of slides.""" """Add a 'last' slide to the end of slides."""
self.slides.append( self.slides.append(
SlideConfig( SlideConfig(
@ -179,14 +179,14 @@ class Presentation:
) )
) )
def reset(self): def reset(self) -> None:
"""Rests current presentation.""" """Rests current presentation."""
self.current_animation = 0 self.current_animation = 0
self.load_animation_cap(0) self.load_animation_cap(0)
self.current_slide_index = 0 self.current_slide_index = 0
self.slides[-1].terminated = False self.slides[-1].terminated = False
def load_last_slide(self): def load_last_slide(self) -> None:
"""Loads last slide.""" """Loads last slide."""
self.current_slide_index = len(self.slides) - 2 self.current_slide_index = len(self.slides) - 2
assert ( assert (
@ -276,7 +276,7 @@ class Display:
resolution=(1980, 1080), resolution=(1980, 1080),
interpolation_flag=cv2.INTER_LINEAR, interpolation_flag=cv2.INTER_LINEAR,
record_to=None, record_to=None,
): ) -> None:
self.presentations = presentations self.presentations = presentations
self.start_paused = start_paused self.start_paused = start_paused
self.config = config self.config = config
@ -319,7 +319,7 @@ class Display:
"""Returns the current presentation.""" """Returns the current presentation."""
return self.presentations[self.current_presentation_index] return self.presentations[self.current_presentation_index]
def run(self): def run(self) -> None:
"""Runs a series of presentations until end or exit.""" """Runs a series of presentations until end or exit."""
while not self.exit: while not self.exit:
self.lastframe, self.state = self.current_presentation.update_state( self.lastframe, self.state = self.current_presentation.update_state(
@ -342,7 +342,7 @@ class Display:
self.show_video() self.show_video()
self.show_info() self.show_info()
def show_video(self): def show_video(self) -> None:
"""Shows updated video.""" """Shows updated video."""
self.lag = now() - self.last_time self.lag = now() - self.last_time
self.last_time = now() self.last_time = now()
@ -369,7 +369,7 @@ class Display:
cv2.imshow(WINDOW_NAME, frame) cv2.imshow(WINDOW_NAME, frame)
def show_info(self): def show_info(self) -> None:
"""Shows updated information about presentations.""" """Shows updated information about presentations."""
info = np.zeros((130, 420), np.uint8) info = np.zeros((130, 420), np.uint8)
font_args = (FONT_ARGS[0], 0.7, *FONT_ARGS[2:]) font_args = (FONT_ARGS[0], 0.7, *FONT_ARGS[2:])
@ -406,7 +406,7 @@ class Display:
cv2.imshow(WINDOW_INFO_NAME, info) cv2.imshow(WINDOW_INFO_NAME, info)
def handle_key(self): def handle_key(self) -> None:
"""Handles key strokes.""" """Handles key strokes."""
sleep_time = math.ceil(1000 / self.current_presentation.fps) sleep_time = math.ceil(1000 / self.current_presentation.fps)
key = cv2.waitKeyEx(fix_time(sleep_time - self.lag)) key = cv2.waitKeyEx(fix_time(sleep_time - self.lag))
@ -445,7 +445,7 @@ class Display:
self.current_presentation.rewind_current_slide() self.current_presentation.rewind_current_slide()
self.state = State.PLAYING self.state = State.PLAYING
def quit(self): def quit(self) -> None:
"""Destroys all windows created by presentations and exits gracefully.""" """Destroys all windows created by presentations and exits gracefully."""
cv2.destroyAllWindows() cv2.destroyAllWindows()
@ -489,7 +489,7 @@ class Display:
show_default=True, show_default=True,
) )
@click.help_option("-h", "--help") @click.help_option("-h", "--help")
def list_scenes(folder): def list_scenes(folder) -> None:
"""List available scenes.""" """List available scenes."""
for i, scene in enumerate(_list_scenes(folder), start=1): for i, scene in enumerate(_list_scenes(folder), start=1):
@ -562,7 +562,7 @@ def present(
resolution, resolution,
interpolation_flag, interpolation_flag,
record_to, record_to,
): ) -> None:
""" """
Present SCENE(s), one at a time, in order. Present SCENE(s), one at a time, in order.
@ -586,7 +586,7 @@ def present(
click.echo("Choose number corresponding to desired scene/arguments.") click.echo("Choose number corresponding to desired scene/arguments.")
click.echo("(Use comma separated list for multiple entries)") click.echo("(Use comma separated list for multiple entries)")
def value_proc(value: str): def value_proc(value: str) -> List[str]:
indices = list(map(int, value.strip().replace(" ", "").split(","))) indices = list(map(int, value.strip().replace(" ", "").split(",")))
if not all(0 < i <= len(scene_choices) for i in indices): if not all(0 < i <= len(scene_choices) for i in indices):

View File

@ -11,7 +11,7 @@ from .defaults import FOLDER_PATH
from .manim import FFMPEG_BIN, MANIMGL, Scene, ThreeDScene, config, logger from .manim import FFMPEG_BIN, MANIMGL, Scene, ThreeDScene, config, logger
def reverse_video_file(src: str, dst: str): def reverse_video_file(src: str, dst: str) -> None:
"""Reverses a video file, writting the result to `dst`.""" """Reverses a video file, writting the result to `dst`."""
command = [FFMPEG_BIN, "-i", src, "-vf", "reverse", dst] command = [FFMPEG_BIN, "-i", src, "-vf", "reverse", dst]
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@ -23,7 +23,7 @@ class Slide(Scene):
Inherits from `manim.Scene` or `manimlib.Scene` and provide necessary tools for slides rendering. Inherits from `manim.Scene` or `manimlib.Scene` and provide necessary tools for slides rendering.
""" """
def __init__(self, *args, output_folder=FOLDER_PATH, **kwargs): def __init__(self, *args, output_folder=FOLDER_PATH, **kwargs) -> None:
if MANIMGL: if MANIMGL:
if not os.path.isdir("videos"): if not os.path.isdir("videos"):
os.mkdir("videos") os.mkdir("videos")
@ -69,19 +69,19 @@ class Slide(Scene):
return config["progress_bar"] != "none" return config["progress_bar"] != "none"
@property @property
def leave_progress_bar(self): def leave_progress_bar(self) -> None:
"""Returns True if progress bar should be left after completed.""" """Returns True if progress bar should be left after completed."""
if MANIMGL: if MANIMGL:
return getattr(super(Scene, self), "leave_progress_bars", False) return getattr(super(Scene, self), "leave_progress_bars", False)
else: else:
return config["progress_bar"] == "leave" return config["progress_bar"] == "leave"
def play(self, *args, **kwargs): def play(self, *args, **kwargs) -> None:
"""Overloads `self.play` and increment animation count.""" """Overloads `self.play` and increment animation count."""
super().play(*args, **kwargs) super().play(*args, **kwargs)
self.current_animation += 1 self.current_animation += 1
def pause(self): def pause(self) -> None:
"""Creates a new slide with previous animations.""" """Creates a new slide with previous animations."""
self.slides.append( self.slides.append(
SlideConfig( SlideConfig(
@ -94,12 +94,12 @@ class Slide(Scene):
self.current_slide += 1 self.current_slide += 1
self.pause_start_animation = self.current_animation self.pause_start_animation = self.current_animation
def start_loop(self): def start_loop(self) -> None:
"""Starts a loop.""" """Starts a loop."""
assert self.loop_start_animation is None, "You cannot nest loops" assert self.loop_start_animation is None, "You cannot nest loops"
self.loop_start_animation = self.current_animation self.loop_start_animation = self.current_animation
def end_loop(self): def end_loop(self) -> None:
"""Ends an existing loop.""" """Ends an existing loop."""
assert ( assert (
self.loop_start_animation is not None self.loop_start_animation is not None
@ -116,7 +116,7 @@ class Slide(Scene):
self.loop_start_animation = None self.loop_start_animation = None
self.pause_start_animation = self.current_animation self.pause_start_animation = self.current_animation
def save_slides(self, use_cache=True): def save_slides(self, use_cache=True) -> None:
""" """
Saves slides, optionally using cached files. Saves slides, optionally using cached files.
@ -182,12 +182,12 @@ class Slide(Scene):
f"Slide '{scene_name}' configuration written in '{os.path.abspath(slide_path)}'" f"Slide '{scene_name}' configuration written in '{os.path.abspath(slide_path)}'"
) )
def run(self, *args, **kwargs): def run(self, *args, **kwargs) -> None:
"""MANIMGL renderer""" """MANIMGL renderer"""
super().run(*args, **kwargs) super().run(*args, **kwargs)
self.save_slides(use_cache=False) self.save_slides(use_cache=False)
def render(self, *args, **kwargs): def render(self, *args, **kwargs) -> None:
"""MANIM render""" """MANIM render"""
# We need to disable the caching limit since we rely on intermidiate files # We need to disable the caching limit since we rely on intermidiate files
max_files_cached = config["max_files_cached"] max_files_cached = config["max_files_cached"]

View File

@ -1,3 +1,4 @@
# type: ignore
import importlib.util import importlib.util
import os import os
import sys import sys

View File

@ -1,4 +1,5 @@
# flake8: noqa: F403, F405 # flake8: noqa: F403, F405
# type: ignore
from manim import * from manim import *