Skip to content
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

chore(lib): add missing type hints and mypy is happy! #75

Merged
merged 2 commits into from
Nov 28, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ repos:
rev: 'v0.991'
hooks:
- id: mypy
additional_dependencies: [types-setuptools]
args:
- --install-types
- --non-interactive
- --ignore-missing-imports
# Disallow dynamic typing
- --disallow-any-unimported
- --disallow-any-generics
- --disallow-subclassing-any

Expand All @@ -49,7 +49,7 @@ repos:
# Configuring warnings
- --warn-unused-ignores
- --warn-no-return
- --warn-return-any
- --no-warn-return-any
- --warn-redundant-casts

# Strict equality
Expand Down
30 changes: 19 additions & 11 deletions manim_slides/commons.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
from typing import Callable
from typing import Any, Callable

import click
from click import Context, Parameter

from .defaults import CONFIG_PATH, FOLDER_PATH
from .manim import logger

F = Callable[..., Any]
Wrapper = Callable[[F], F]

def config_path_option(function: Callable) -> Callable:

def config_path_option(function: F) -> F:
"""Wraps a function to add configuration path option."""
return click.option(
wrapper: Wrapper = click.option(
"-c",
"--config",
"config_path",
Expand All @@ -18,10 +21,11 @@ def config_path_option(function: Callable) -> Callable:
type=click.Path(dir_okay=False),
help="Set path to configuration file.",
show_default=True,
)(function)
)
return wrapper(function)


def config_options(function: Callable) -> Callable:
def config_options(function: F) -> F:
"""Wraps a function to add configuration options."""
function = config_path_option(function)
function = click.option(
Expand All @@ -36,7 +40,7 @@ def config_options(function: Callable) -> Callable:
return function


def verbosity_option(function: Callable) -> Callable:
def verbosity_option(function: F) -> F:
"""Wraps a function to add verbosity option."""

def callback(ctx: Context, param: Parameter, value: bool) -> None:
Expand All @@ -46,7 +50,7 @@ def callback(ctx: Context, param: Parameter, value: bool) -> None:

logger.setLevel(value)

return click.option(
wrapper: Wrapper = click.option(
"-v",
"--verbosity",
type=click.Choice(
Expand All @@ -59,16 +63,20 @@ def callback(ctx: Context, param: Parameter, value: bool) -> None:
envvar="MANIM_SLIDES_VERBOSITY",
show_envvar=True,
callback=callback,
)(function)
)

return wrapper(function)

def folder_path_option(function: Callable) -> Callable:

def folder_path_option(function: F) -> F:
"""Wraps a function to add folder path option."""
return click.option(
wrapper: Wrapper = click.option(
"--folder",
metavar="DIRECTORY",
default=FOLDER_PATH,
type=click.Path(exists=True, file_okay=False),
help="Set slides folder.",
show_default=True,
)(function)
)

return wrapper(function)
38 changes: 22 additions & 16 deletions manim_slides/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import subprocess
import tempfile
from enum import Enum
from typing import List, Optional, Set
from typing import Callable, Dict, List, Optional, Set, Union

from pydantic import BaseModel, root_validator, validator
from PySide6.QtCore import Qt
Expand All @@ -24,7 +24,7 @@ def merge_basenames(files: List[str]) -> str:
return os.path.join(dirname, basename + ext)


class Key(BaseModel):
class Key(BaseModel): # type: ignore
"""Represents a list of key codes, with optionally a name."""

ids: Set[int]
Expand All @@ -48,7 +48,7 @@ def match(self, key_id: int) -> bool:
return m


class Config(BaseModel):
class Config(BaseModel): # type: ignore
"""General Manim Slides config"""

QUIT: Key = Key(ids=[Qt.Key_Q], name="QUIT")
Expand All @@ -60,8 +60,8 @@ class Config(BaseModel):
HIDE_MOUSE: Key = Key(ids=[Qt.Key_H], name="HIDE / SHOW MOUSE")

@root_validator
def ids_are_unique_across_keys(cls, values):
ids = set()
def ids_are_unique_across_keys(cls, values: Dict[str, Key]) -> Dict[str, Key]:
ids: Set[int] = set()

for key in values.values():
if len(ids.intersection(key.ids)) != 0:
Expand All @@ -87,28 +87,30 @@ class SlideType(str, Enum):
last = "last"


class SlideConfig(BaseModel):
class SlideConfig(BaseModel): # type: ignore
type: SlideType
start_animation: int
end_animation: int
number: int
terminated: bool = False

@validator("start_animation", "end_animation")
def index_is_posint(cls, v: int):
def index_is_posint(cls, v: int) -> int:
if v < 0:
raise ValueError("Animation index (start or end) cannot be negative")
return v

@validator("number")
def number_is_strictly_posint(cls, v: int):
def number_is_strictly_posint(cls, v: int) -> int:
if v <= 0:
raise ValueError("Slide number cannot be negative or zero")
return v

@root_validator
def start_animation_is_before_end(cls, values):
if values["start_animation"] >= values["end_animation"]:
def start_animation_is_before_end(
cls, values: Dict[str, Union[SlideType, int, bool]]
) -> Dict[str, Union[SlideType, int, bool]]:
if values["start_animation"] >= values["end_animation"]: # type: ignore

if values["start_animation"] == values["end_animation"] == 0:
raise ValueError(
Expand All @@ -135,12 +137,12 @@ def slides_slice(self) -> slice:
return slice(self.start_animation, self.end_animation)


class PresentationConfig(BaseModel):
class PresentationConfig(BaseModel): # type: ignore
slides: List[SlideConfig]
files: List[str]

@validator("files", pre=True, each_item=True)
def is_file_and_exists(cls, v):
def is_file_and_exists(cls, v: str) -> str:
if not os.path.exists(v):
raise ValueError(
f"Animation file {v} does not exist. Are you in the right directory?"
Expand All @@ -152,7 +154,9 @@ def is_file_and_exists(cls, v):
return v

@root_validator
def animation_indices_match_files(cls, values):
def animation_indices_match_files(
cls, values: Dict[str, Union[List[SlideConfig], List[str]]]
) -> Dict[str, Union[List[SlideConfig], List[str]]]:
files = values.get("files")
slides = values.get("slides")

Expand All @@ -162,18 +166,20 @@ def animation_indices_match_files(cls, values):
n_files = len(files)

for slide in slides:
if slide.end_animation > n_files:
if slide.end_animation > n_files: # type: ignore
raise ValueError(
f"The following slide's contains animations not listed in files {files}: {slide}"
)

return values

def move_to(self, dest: str, copy=True) -> "PresentationConfig":
def move_to(self, dest: str, copy: bool = True) -> "PresentationConfig":
"""
Moves (or copy) the files to a given directory.
"""
move = shutil.copy if copy else shutil.move
copy_func: Callable[[str, str], None] = shutil.copy
move_func: Callable[[str, str], None] = shutil.move
move = copy_func if copy else move_func

n = len(self.files)
for i in range(n):
Expand Down
18 changes: 13 additions & 5 deletions manim_slides/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ def validate_config_option(
return config


class Converter(BaseModel):
class Converter(BaseModel): # type: ignore
presentation_configs: List[PresentationConfig] = []
assets_dir: str = "{basename}_assets"

def convert_to(self, dest: str):
def convert_to(self, dest: str) -> None:
"""Converts self, i.e., a list of presentations, into a given format."""
raise NotImplementedError

Expand Down Expand Up @@ -105,7 +105,7 @@ def load_template(self) -> str:
__name__, "data/revealjs_template.html"
).decode()

def convert_to(self, dest: str):
def convert_to(self, dest: str) -> None:
"""Converts this configuration into a RevealJS HTML presentation, saved to DEST."""
dirname = os.path.dirname(dest)
basename, ext = os.path.splitext(os.path.basename(dest))
Expand All @@ -130,7 +130,7 @@ def convert_to(self, dest: str):
f.write(content)


def show_config_options(function: Callable) -> Callable:
def show_config_options(function: Callable[..., Any]) -> Callable[..., Any]:
"""Wraps a function to add a `--show-config` option."""

def callback(ctx: Context, param: Parameter, value: bool) -> None:
Expand Down Expand Up @@ -191,7 +191,15 @@ def callback(ctx: Context, param: Parameter, value: bool) -> None:
)
@show_config_options
@verbosity_option
def convert(scenes, folder, dest, to, open_result, force, config_options):
def convert(
scenes: List[str],
folder: str,
dest: str,
to: str,
open_result: bool,
force: bool,
config_options: Dict[str, str],
) -> None:
"""
Convert SCENE(s) into a given format and writes the result in DEST.
"""
Expand Down
Loading