mirror of
https://github.com/jeertmans/manim-slides.git
synced 2025-08-06 06:12:56 +08:00
feat(cli): add basic logging facilities (#50)
* feat(cli): add basic logging facilities This PR adds basic logging support, to be extended in the future. * fix: typo in decorator name
This commit is contained in:
@ -1,11 +1,13 @@
|
||||
from typing import Callable
|
||||
|
||||
import click
|
||||
from click import Context, Parameter
|
||||
|
||||
from .defaults import CONFIG_PATH
|
||||
from .manim import logger
|
||||
|
||||
|
||||
def config_path_option(function) -> Callable:
|
||||
def config_path_option(function: Callable) -> Callable:
|
||||
"""Wraps a function to add configuration path option."""
|
||||
return click.option(
|
||||
"-c",
|
||||
@ -18,7 +20,7 @@ def config_path_option(function) -> Callable:
|
||||
)(function)
|
||||
|
||||
|
||||
def config_options(function) -> Callable:
|
||||
def config_options(function: Callable) -> Callable:
|
||||
"""Wraps a function to add configuration options."""
|
||||
function = config_path_option(function)
|
||||
function = click.option(
|
||||
@ -31,3 +33,27 @@ def config_options(function) -> Callable:
|
||||
help="Merge any existing configuration file with the new configuration.",
|
||||
)(function)
|
||||
return function
|
||||
|
||||
|
||||
def verbosity_option(function: Callable) -> Callable:
|
||||
"""Wraps a function to add verbosity option."""
|
||||
|
||||
def callback(ctx: Context, param: Parameter, value: bool) -> None:
|
||||
|
||||
if not value or ctx.resilient_parsing:
|
||||
return
|
||||
|
||||
logger.setLevel(value)
|
||||
|
||||
return click.option(
|
||||
"-v",
|
||||
"--verbosity",
|
||||
type=click.Choice(
|
||||
["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
|
||||
case_sensitive=False,
|
||||
),
|
||||
help="Verbosity of CLI output",
|
||||
default=None,
|
||||
expose_value=False,
|
||||
callback=callback,
|
||||
)(function)
|
||||
|
@ -5,6 +5,7 @@ from typing import List, Optional, Set
|
||||
from pydantic import BaseModel, root_validator, validator
|
||||
|
||||
from .defaults import LEFT_ARROW_KEY_CODE, RIGHT_ARROW_KEY_CODE
|
||||
from .manim import logger
|
||||
|
||||
|
||||
class Key(BaseModel):
|
||||
@ -20,7 +21,12 @@ class Key(BaseModel):
|
||||
return v
|
||||
|
||||
def match(self, key_id: int):
|
||||
return key_id in self.ids
|
||||
m = key_id in self.ids
|
||||
|
||||
if m:
|
||||
logger.debug(f"Pressed key: {self.name}")
|
||||
|
||||
return m
|
||||
|
||||
|
||||
class Config(BaseModel):
|
||||
|
@ -11,9 +11,10 @@ import numpy as np
|
||||
from pydantic import ValidationError
|
||||
from tqdm import tqdm
|
||||
|
||||
from .commons import config_path_option
|
||||
from .commons import config_path_option, verbosity_option
|
||||
from .config import Config, PresentationConfig, SlideConfig, SlideType
|
||||
from .defaults import FOLDER_PATH, FONT_ARGS
|
||||
from .manim import logger
|
||||
|
||||
INTERPOLATION_FLAGS = {
|
||||
"nearest": cv2.INTER_NEAREST,
|
||||
@ -450,6 +451,9 @@ class Display:
|
||||
cv2.destroyAllWindows()
|
||||
|
||||
if self.record_to is not None and len(self.recordings) > 0:
|
||||
logger.debug(
|
||||
f"A total of {len(self.recordings)} frames will be saved to {self.record_to}"
|
||||
)
|
||||
file, frame_number, fps = self.recordings[0]
|
||||
|
||||
cap = cv2.VideoCapture(file)
|
||||
@ -489,6 +493,7 @@ class Display:
|
||||
show_default=True,
|
||||
)
|
||||
@click.help_option("-h", "--help")
|
||||
@verbosity_option
|
||||
def list_scenes(folder) -> None:
|
||||
"""List available scenes."""
|
||||
|
||||
@ -502,13 +507,18 @@ def _list_scenes(folder) -> List[str]:
|
||||
|
||||
for file in os.listdir(folder):
|
||||
if file.endswith(".json"):
|
||||
filepath = os.path.join(folder, file)
|
||||
try:
|
||||
filepath = os.path.join(folder, file)
|
||||
_ = PresentationConfig.parse_file(filepath)
|
||||
scenes.append(os.path.basename(file)[:-5])
|
||||
except Exception: # Could not parse this file as a proper presentation config
|
||||
except Exception as e: # Could not parse this file as a proper presentation config
|
||||
logger.warn(
|
||||
f"Something went wrong with parsing presentation config `{filepath}`: {e}"
|
||||
)
|
||||
pass
|
||||
|
||||
logger.info(f"Found {len(scenes)} valid scene configuration files in `{folder}`.")
|
||||
|
||||
return scenes
|
||||
|
||||
|
||||
@ -552,6 +562,7 @@ def _list_scenes(folder) -> List[str]:
|
||||
help="If set, the presentation will be recorded into a AVI video file with given name.",
|
||||
)
|
||||
@click.help_option("-h", "--help")
|
||||
@verbosity_option
|
||||
def present(
|
||||
scenes,
|
||||
config_path,
|
||||
@ -616,8 +627,8 @@ def present(
|
||||
f"File {config_file} does not exist, check the scene name and make sure to use Slide as your scene base class"
|
||||
)
|
||||
try:
|
||||
config = PresentationConfig.parse_file(config_file)
|
||||
presentations.append(Presentation(config))
|
||||
pres_config = PresentationConfig.parse_file(config_file)
|
||||
presentations.append(Presentation(pres_config))
|
||||
except ValidationError as e:
|
||||
raise click.UsageError(str(e))
|
||||
|
||||
@ -627,6 +638,7 @@ def present(
|
||||
except ValidationError as e:
|
||||
raise click.UsageError(str(e))
|
||||
else:
|
||||
logger.info("No configuration file found, using default configuration.")
|
||||
config = Config()
|
||||
|
||||
if record_to is not None:
|
||||
|
@ -5,7 +5,7 @@ import click
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
from .commons import config_options
|
||||
from .commons import config_options, verbosity_option
|
||||
from .config import Config
|
||||
from .defaults import CONFIG_PATH, FONT_ARGS
|
||||
|
||||
@ -39,6 +39,7 @@ def prompt(question: str) -> int:
|
||||
@click.command()
|
||||
@config_options
|
||||
@click.help_option("-h", "--help")
|
||||
@verbosity_option
|
||||
def wizard(config_path, force, merge):
|
||||
"""Launch configuration wizard."""
|
||||
return _init(config_path, force, merge, skip_interactive=False)
|
||||
@ -47,6 +48,7 @@ def wizard(config_path, force, merge):
|
||||
@click.command()
|
||||
@config_options
|
||||
@click.help_option("-h", "--help")
|
||||
@verbosity_option
|
||||
def init(config_path, force, merge, skip_interactive=False):
|
||||
"""Initialize a new default configuration file."""
|
||||
return _init(config_path, force, merge, skip_interactive=True)
|
||||
|
Reference in New Issue
Block a user