argparse_decorators.py (Source)

import inspect
from argparse import ArgumentParser
def get_main(function):
    """Create a main function for a command.
    The main function will be callable using the command-line arguments:
    `main('--flag', '--option=option')`
    The command will be called according to its argspec using available args.
    """
    parser = get_parser(function)
    def main(*args: str):
        namespace = parser.parse_args(args if args else None)
        return call(function, namespace)
    return main
def get_parser(function):
    """Create a parser for a function.
    The parser description will use the function docstring.
    Example:
    .. code: python
        from argparse_decorators import add_argument, get_parser
        @add_argument("argument")
        def command(argument)
            ...
        parser = get_parser(command)
    It's same as:
    .. code: python
        import argparse
        from argparse_decorators import add_argument, get_parser
        def command(argument)
            ...
        parser = argparse.ArgumentParser(description=command.__doc__)
        parser.add_argument("argument")
    The parser will be configured according to __argparse_annotations__.
    """
    parser = ArgumentParser(description=function.__doc__)
    configure_parser(parser, function)
    return parser
def configure_parser(parser, command):
    """Configure a parser from a decorated function."""
    annotations = getattr(command, "__argparse_annotations__", [])
    for args, kwargs in annotations:
        parser.add_argument(*args, **kwargs)
def call(function, args):
    """Call a function according to its argspec using available cli args.
    Example:
    .. code: python
        import argparse
        from argparse_decorators import add_argument, call
        @add_argument("argument")
        def command(argument)
            assert argument == "value"
        call(command, argparse.Namespace(argument="value"))
    The parser will be configured according to __argparse_annotations__.
    """
    argspec = inspect.getargspec(function)
    call_args = {arg: getattr(args, arg) for arg in argspec.args}
    return function(**call_args)
def add_argument(*args, **kwargs):
    """Build a decorator that will add argparse annotations to a function."""
    return lambda decorated: _add_annotation(decorated, (args, kwargs))
def _add_annotation(function, argument):
    """Add argparse annotations to a function."""
    annotations = getattr(function, "__argparse_annotations__", [])
    annotations.append(argument)
    setattr(function, "__argparse_annotations__", annotations)
    return function