# SPDX-License-Identifier: GPLv3-or-later
# Copyright © 2025 pygaindalf Rui Pinheiro
"""Argument parsing and CLI option definitions for pygaindalf.
Defines global options, command actions, and wraps argparse for use throughout the application.
"""
import argparse
import os
import sys
from abc import ABCMeta, abstractmethod
from typing import TYPE_CHECKING, Any, override
from ...helpers.script_info import get_exe_name, get_script_name, is_unit_test
if TYPE_CHECKING:
from collections.abc import Sequence
###################
# Argument parser
ENV_PREFIX = get_script_name().upper()
[docs]
class ArgParserBase(argparse.ArgumentParser, metaclass=ABCMeta):
[docs]
def __init__(self, *args, **kwargs) -> None:
kwargs["prog"] = kwargs.get("prog", get_exe_name())
kwargs["description"] = kwargs.get("description", "pygaindalf CLI options")
kwargs["formatter_class"] = argparse.ArgumentDefaultsHelpFormatter
super().__init__(*args, **kwargs)
self.initialize()
self.parse()
[docs]
@override
def add_argument(self, name: str, *args, default: Any = None, **kwargs) -> argparse.Action:
"""Add a command-line argument to the global parser.
Args:
name (str): The destination variable name.
*args: Argument flags (e.g., '-v', '--verbosity').
default: Default value if not set elsewhere.
**kwargs: Additional argparse options.
"""
env_name = name.upper().replace(".", "_")
return super().add_argument(*args, dest=name, default=os.getenv(f"{ENV_PREFIX}_{env_name}", default), **kwargs)
[docs]
def add(self, *args, **kwargs) -> argparse.Action:
return self.add_argument(*args, **kwargs)
[docs]
@abstractmethod
def initialize(self) -> None:
msg = "Subclasses must implement the 'initialize' method."
raise NotImplementedError(msg)
[docs]
def get_argv(self) -> Sequence[str]:
if is_unit_test():
# In unit tests, we default to reading the config from stdin
return ("-",)
return sys.argv[1:]
[docs]
@override
def parse_args(self, *args, **kwargs) -> argparse.Namespace:
"""Get the parsed command-line arguments.
Returns:
argparse.Namespace: The parsed arguments.
"""
self.namespace = super().parse_args(self.get_argv(), *args, **kwargs)
return self.namespace
[docs]
def parse(self, *args, **kwargs) -> argparse.Namespace:
return self.parse_args(*args, **kwargs)