Skip to content

Commit ee0501c

Browse files
authored
Add type hints to manim.cli module (#3988)
* Add type hints to cli * Import click.Parameter instead of non existing cloup.Parameter * Stop ignoring manim.cli errors in mypy.ini * Fix mypy errors * Remove unused TypeVar C * click.Command.command -> cloup.Group.command * Address Jason's requested changes * exit() -> sys.exit()
1 parent c6edb33 commit ee0501c

File tree

17 files changed

+543
-198
lines changed

17 files changed

+543
-198
lines changed

docs/source/reference_index/utilities_misc.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Module Index
1010
:toctree: ../reference
1111

1212
~utils.bezier
13+
cli
1314
~utils.color
1415
~utils.commands
1516
~utils.config_ops

manim/_config/cli_colors.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
from __future__ import annotations
22

33
import configparser
4+
from typing import Any
45

56
from cloup import Context, HelpFormatter, HelpTheme, Style
67

78
__all__ = ["parse_cli_ctx"]
89

910

10-
def parse_cli_ctx(parser: configparser.SectionProxy) -> Context:
11+
def parse_cli_ctx(parser: configparser.SectionProxy) -> dict[str, Any]:
1112
formatter_settings: dict[str, str | int] = {
1213
"indent_increment": int(parser["indent_increment"]),
1314
"width": int(parser["width"]),

manim/cli/__init__.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
"""The Manim CLI, and the available commands for ``manim``.
2+
3+
This page is a work in progress. Please run ``manim`` or ``manim --help`` in
4+
your terminal to find more information on the following commands.
5+
6+
Available commands
7+
------------------
8+
9+
.. autosummary::
10+
:toctree: ../reference
11+
12+
cfg
13+
checkhealth
14+
init
15+
plugins
16+
render
17+
"""

manim/cli/cfg/group.py

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,23 @@
1111
import contextlib
1212
from ast import literal_eval
1313
from pathlib import Path
14+
from typing import Any, cast
1415

1516
import cloup
1617
from rich.errors import StyleSyntaxError
1718
from rich.style import Style
1819

19-
from ... import cli_ctx_settings, console
20-
from ..._config.utils import config_file_paths, make_config_parser
21-
from ...constants import EPILOG
22-
from ...utils.file_ops import guarantee_existence, open_file
20+
from manim._config import cli_ctx_settings, console
21+
from manim._config.utils import config_file_paths, make_config_parser
22+
from manim.constants import EPILOG
23+
from manim.utils.file_ops import guarantee_existence, open_file
2324

2425
RICH_COLOUR_INSTRUCTIONS: str = """
2526
[red]The default colour is used by the input statement.
2627
If left empty, the default colour will be used.[/red]
2728
[magenta] For a full list of styles, visit[/magenta] [green]https://rich.readthedocs.io/en/latest/style.html[/green]
2829
"""
29-
RICH_NON_STYLE_ENTRIES: str = ["log.width", "log.height", "log.timestamps"]
30+
RICH_NON_STYLE_ENTRIES: list[str] = ["log.width", "log.height", "log.timestamps"]
3031

3132
__all__ = [
3233
"value_from_string",
@@ -41,57 +42,69 @@
4142

4243

4344
def value_from_string(value: str) -> str | int | bool:
44-
"""Extracts the literal of proper datatype from a string.
45+
"""Extract the literal of proper datatype from a ``value`` string.
46+
4547
Parameters
4648
----------
4749
value
4850
The value to check get the literal from.
4951
5052
Returns
5153
-------
52-
Union[:class:`str`, :class:`int`, :class:`bool`]
53-
Returns the literal of appropriate datatype.
54+
:class:`str` | :class:`int` | :class:`bool`
55+
The literal of appropriate datatype.
5456
"""
5557
with contextlib.suppress(SyntaxError, ValueError):
5658
value = literal_eval(value)
5759
return value
5860

5961

60-
def _is_expected_datatype(value: str, expected: str, style: bool = False) -> bool:
61-
"""Checks whether `value` is the same datatype as `expected`,
62-
and checks if it is a valid `style` if `style` is true.
62+
def _is_expected_datatype(
63+
value: str, expected: str, validate_style: bool = False
64+
) -> bool:
65+
"""Check whether the literal from ``value`` is the same datatype as the
66+
literal from ``expected``. If ``validate_style`` is ``True``, also check if
67+
the style given by ``value`` is valid, according to ``rich``.
6368
6469
Parameters
6570
----------
6671
value
67-
The string of the value to check (obtained from reading the user input).
72+
The string of the value to check, obtained from reading the user input.
6873
expected
69-
The string of the literal datatype must be matched by `value`. Obtained from
70-
reading the cfg file.
71-
style
72-
Whether or not to confirm if `value` is a style, by default False
74+
The string of the literal datatype which must be matched by ``value``.
75+
This is obtained from reading the ``cfg`` file.
76+
validate_style
77+
Whether or not to confirm if ``value`` is a valid style, according to
78+
``rich``. Default is ``False``.
7379
7480
Returns
7581
-------
7682
:class:`bool`
77-
Whether or not `value` matches the datatype of `expected`.
83+
Whether or not the literal from ``value`` matches the datatype of the
84+
literal from ``expected``.
7885
"""
79-
value = value_from_string(value)
80-
expected = type(value_from_string(expected))
86+
value_literal = value_from_string(value)
87+
ExpectedLiteralType = type(value_from_string(expected))
8188

82-
return isinstance(value, expected) and (is_valid_style(value) if style else True)
89+
return isinstance(value_literal, ExpectedLiteralType) and (
90+
(isinstance(value_literal, str) and is_valid_style(value_literal))
91+
if validate_style
92+
else True
93+
)
8394

8495

8596
def is_valid_style(style: str) -> bool:
86-
"""Checks whether the entered color is a valid color according to rich
97+
"""Checks whether the entered color style is valid, according to ``rich``.
98+
8799
Parameters
88100
----------
89101
style
90102
The style to check whether it is valid.
103+
91104
Returns
92105
-------
93-
Boolean
94-
Returns whether it is valid style or not according to rich.
106+
:class:`bool`
107+
Whether the color style is valid or not, according to ``rich``.
95108
"""
96109
try:
97110
Style.parse(style)
@@ -100,16 +113,20 @@ def is_valid_style(style: str) -> bool:
100113
return False
101114

102115

103-
def replace_keys(default: dict) -> dict:
104-
"""Replaces _ to . and vice versa in a dictionary for rich
116+
def replace_keys(default: dict[str, Any]) -> dict[str, Any]:
117+
"""Replace ``_`` with ``.`` and vice versa in a dictionary's keys for
118+
``rich``.
119+
105120
Parameters
106121
----------
107122
default
108-
The dictionary to check and replace
123+
The dictionary whose keys will be checked and replaced.
124+
109125
Returns
110126
-------
111127
:class:`dict`
112-
The dictionary which is modified by replacing _ with . and vice versa
128+
The dictionary whose keys are modified by replacing ``_`` with ``.``
129+
and vice versa.
113130
"""
114131
for key in default:
115132
if "_" in key:
@@ -133,7 +150,7 @@ def replace_keys(default: dict) -> dict:
133150
help="Manages Manim configuration files.",
134151
)
135152
@cloup.pass_context
136-
def cfg(ctx):
153+
def cfg(ctx: cloup.Context) -> None:
137154
"""Responsible for the cfg subcommand."""
138155
pass
139156

@@ -147,7 +164,7 @@ def cfg(ctx):
147164
help="Specify if this config is for user or the working directory.",
148165
)
149166
@cloup.option("-o", "--open", "openfile", is_flag=True)
150-
def write(level: str = None, openfile: bool = False) -> None:
167+
def write(level: str | None = None, openfile: bool = False) -> None:
151168
config_paths = config_file_paths()
152169
console.print(
153170
"[yellow bold]Manim Configuration File Writer[/yellow bold]",
@@ -166,7 +183,7 @@ def write(level: str = None, openfile: bool = False) -> None:
166183
action = "save this as"
167184
for category in parser:
168185
console.print(f"{category}", style="bold green underline")
169-
default = parser[category]
186+
default = cast(dict[str, Any], parser[category])
170187
if category == "logger":
171188
console.print(RICH_COLOUR_INSTRUCTIONS)
172189
default = replace_keys(default)
@@ -249,7 +266,7 @@ def write(level: str = None, openfile: bool = False) -> None:
249266

250267

251268
@cfg.command(context_settings=cli_ctx_settings)
252-
def show():
269+
def show() -> None:
253270
parser = make_config_parser()
254271
rich_non_style_entries = [a.replace(".", "_") for a in RICH_NON_STYLE_ENTRIES]
255272
for category in parser:
@@ -269,7 +286,7 @@ def show():
269286
@cfg.command(context_settings=cli_ctx_settings)
270287
@cloup.option("-d", "--directory", default=Path.cwd())
271288
@cloup.pass_context
272-
def export(ctx, directory):
289+
def export(ctx: cloup.Context, directory: str) -> None:
273290
directory_path = Path(directory)
274291
if directory_path.absolute == Path.cwd().absolute:
275292
console.print(

0 commit comments

Comments
 (0)