Source code for app.util.config.args.parser

# 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)