Files
FastAnime/fastanime/cli/cli.py
2025-07-13 12:30:09 +03:00

115 lines
3.3 KiB
Python

from typing import TYPE_CHECKING
import click
from click.core import ParameterSource
from .. import __version__
from ..core.config import AppConfig
from ..core.constants import PROJECT_NAME, USER_CONFIG_PATH
from .config import ConfigLoader
from .options import options_from_model
from .utils.exceptions import setup_exceptions_handler
from .utils.lazyloader import LazyGroup
from .utils.logging import setup_logging
if TYPE_CHECKING:
from typing import TypedDict
from typing_extensions import Unpack
class Options(TypedDict):
no_config: bool | None
trace: bool | None
log_to_file: bool | None
dev: bool | None
log: bool | None
rich_traceback: bool | None
commands = {
"config": ".config",
"search": ".search",
}
@click.group(
cls=LazyGroup,
root="fastanime.cli.commands",
lazy_subcommands=commands,
context_settings=dict(auto_envvar_prefix=PROJECT_NAME),
)
@click.version_option(__version__, "--version")
@click.option(
"--no-config",
is_flag=True,
help="Don't load the user config file.",
envvar=f"{PROJECT_NAME}_NO_CONFIG",
)
@click.option(
"--trace",
is_flag=True,
help="Controls Whether to display tracebacks or not",
envvar=f"{PROJECT_NAME}_TRACE",
)
@click.option(
"--dev",
is_flag=True,
help="Controls Whether the app is in dev mode",
envvar=f"{PROJECT_NAME}_DEV",
)
@click.option(
"--log", is_flag=True, help="Controls Whether to log", envvar=f"{PROJECT_NAME}_LOG"
)
@click.option(
"--log-to-file",
is_flag=True,
help="Controls Whether to log to a file",
envvar=f"{PROJECT_NAME}_LOG_TO_FILE",
)
@click.option(
"--rich-traceback",
is_flag=True,
help="Controls Whether to display a rich traceback",
envvar=f"{PROJECT_NAME}_LOG_TO_FILE",
)
@options_from_model(AppConfig)
@click.pass_context
def cli(ctx: click.Context, **options: "Unpack[Options]"):
"""
The main entry point for the FastAnime CLI.
"""
setup_logging(
options["log"],
options["log_to_file"],
options["rich_traceback"],
)
setup_exceptions_handler(options["trace"], options["dev"])
loader = ConfigLoader(config_path=USER_CONFIG_PATH)
config = AppConfig.model_validate({}) if options["no_config"] else loader.load()
# update app config with command line parameters
for param_name, param_value in ctx.params.items():
source = ctx.get_parameter_source(param_name)
if (
source == ParameterSource.ENVIRONMENT
or source == ParameterSource.COMMANDLINE
):
parameter = None
for param in ctx.command.params:
if param.name == param_name:
parameter = param
break
if (
parameter
and hasattr(parameter, "model_name")
and hasattr(parameter, "field_name")
):
model_name = getattr(parameter, "model_name")
field_name = getattr(parameter, "field_name")
if hasattr(config, model_name):
model_instance = getattr(config, model_name)
if hasattr(model_instance, field_name):
setattr(model_instance, field_name, param_value)
ctx.obj = config