Source code for heavyedge.cli.parser

"""Argument parser."""

import argparse

import yaml

__all__ = [
    "ConfigFileAction",
    "ConfigArgumentParser",
]


class ConfigFileAction(argparse.Action):
    """Action for an argument to load values from YAML config file.

    The config file consists of key-value pairs for arguments.
    Explicitly passed argument overloads the config file value.
    """

    def __call__(self, parser, namespace, values, option_string=None):
        if isinstance(parser, ConfigArgumentParser):
            config_args = [arg.dest for arg in parser.config_arguments()]
        else:
            config_args = []
        if values is None:
            return
        with values as f:
            data = {
                key.replace("-", "_"): val for (key, val) in yaml.full_load(f).items()
            }
        for k, v in vars(namespace).items():
            if v is None and k in config_args and k in data:
                setattr(namespace, k, data[k])


[docs] class ConfigArgumentParser(argparse.ArgumentParser): """Argument parser which can read config file. Use :meth:`add_config_argument` to add an argument which can be read from the config file. When the first config argument is added, the ``--config`` option is automatically added. Examples -------- >>> from heavyedge.cli import ConfigArgumentParser >>> parser = ConfigArgumentParser("foo") >>> _ = parser.add_config_argument("--bar") >>> parser.print_help() usage: foo [-h] [--config CONFIG] [--bar BAR] <BLANKLINE> options: -h, --help show this help message and exit --config CONFIG YAML file specifying config options. <BLANKLINE> config options: --bar BAR """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._config_argument_group = self.add_argument_group("config options") self._config_argument = [] def config_arguments(self): return self._config_argument
[docs] def add_config_argument(self, name, **kwargs): """Add argument which can be read from the config file. Parameters ---------- name : str Name of the argument. kwargs : dict Additional arguments passed to :meth:`argparse.ArgumentParser.add_argument`. """ kwargs.update(required=False, default=None) if len(self.config_arguments()) == 0: # First config argument: add config parser first self.add_argument( "--config", type=open, action=ConfigFileAction, help="YAML file specifying config options.", ) ret = self._config_argument_group.add_argument(name, **kwargs) self._config_argument.append(ret) return ret