Annotate a function by adding the args/kwargs to the meta-data.

    This appends an Argparse "argument" to the function's
    ``ARGPARSE_ARGS_LIST`` attribute, creating ``ARGPARSE_ARGS_LIST`` if it
    does not already exist.  Aside from that, it returns the decorated function
    unmodified, and unwrapped.

    The "arguments" are simply ``(args, kwargs)`` tuples which will be passed
    to the Argparse parser created from the function as
    ``parser.add_argument(*args, **kwargs)``.

    `argparse.ArgumentParser.add_argument
    <https://docs.python.org/2/library/argparse.html#the-add-argument-method>`_
    should be consulted for up-to-date documentation on the accepted arguments.
    For convenience, a list has been included here.

    Args
    ----
    name/flags : str or list
        Either a name or a list of (positional) option strings, e.g. ('foo') or
        ('-f', '--foo').
    action : str
        The basic type of action to be taken when this argument is encountered
        at the command line.
    nargs : str
        The number of command-line arguments that should be consumed.
    const
        A constant value required by some action and nargs selections.
    default
        The value produced if the argument is absent from the command line.
    type : type
        The type to which the command-line argument should be converted.
    choices
        A container of the allowable values for the argument.
    required : bool
        Whether or not the command-line option may be omitted (optionals only).
    help : str
        A brief description of what the argument does.
    metavar : str
        A name for the argument in usage messages.
    dest : str
        The name of the attribute to be added to the object returned by
        parse_args().

    Example
    -------
    .. testsetup::

       mycommand = Command(name='mycommand')

    .. testcode::

        @command(name='echo')
        @arg('-n', '--num', type=int, default=42)
        @arg('-s', '--some-switch', action='store_false')
        @arg('foo')
        def echo(foo, num, some_switch):
            print foo, num

    .. doctest::

       >>> echo_subcommand = mycommand.add_subcommand(echo)
       >>> mycommand.init()
       >>> mycommand.parse_args(['echo', 'hi', '-n', '42'])
       hi 42

    See also
    --------
    `argparse.ArgumentParser.add_argument
    <https://docs.python.org/2/library/argparse.html#the-add-argument-method>`_

def arg(*args, **kwargs):
    """Annotate a function by adding the args/kwargs to the meta-data.

    This appends an Argparse "argument" to the function's
    ``ARGPARSE_ARGS_LIST`` attribute, creating ``ARGPARSE_ARGS_LIST`` if it
    does not already exist.  Aside from that, it returns the decorated function
    unmodified, and unwrapped.

    The "arguments" are simply ``(args, kwargs)`` tuples which will be passed
    to the Argparse parser created from the function as
    ``parser.add_argument(*args, **kwargs)``.

    `argparse.ArgumentParser.add_argument
    <https://docs.python.org/2/library/argparse.html#the-add-argument-method>`_
    should be consulted for up-to-date documentation on the accepted arguments.
    For convenience, a list has been included here.

    Args
    ----
    name/flags : str or list
        Either a name or a list of (positional) option strings, e.g. ('foo') or
        ('-f', '--foo').
    action : str
        The basic type of action to be taken when this argument is encountered
        at the command line.
    nargs : str
        The number of command-line arguments that should be consumed.
    const
        A constant value required by some action and nargs selections.
    default
        The value produced if the argument is absent from the command line.
    type : type
        The type to which the command-line argument should be converted.
    choices
        A container of the allowable values for the argument.
    required : bool
        Whether or not the command-line option may be omitted (optionals only).
    help : str
        A brief description of what the argument does.
    metavar : str
        A name for the argument in usage messages.
    dest : str
        The name of the attribute to be added to the object returned by
        parse_args().

    Example
    -------
    .. testsetup::

       mycommand = Command(name='mycommand')

    .. testcode::

        @command(name='echo')
        @arg('-n', '--num', type=int, default=42)
        @arg('-s', '--some-switch', action='store_false')
        @arg('foo')
        def echo(foo, num, some_switch):
            print foo, num

    .. doctest::

       >>> echo_subcommand = mycommand.add_subcommand(echo)
       >>> mycommand.init()
       >>> mycommand.parse_args(['echo', 'hi', '-n', '42'])
       hi 42

    See also
    --------
    `argparse.ArgumentParser.add_argument
    <https://docs.python.org/2/library/argparse.html#the-add-argument-method>`_

    """
    def annotate(func):
        # Get the list of argparse args already added to func (if any).
        argparse_args_list = getattr(func, 'ARGPARSE_ARGS_LIST', [])
        # Since we're only annotating (not wrapping) the function, appending
        # the argument to the list would result in the decorators being applied
        # in reverse order.  To prevent that, we simply add to the beginning.
        argparse_args_list.insert(0, (args, kwargs))
        setattr(func, 'ARGPARSE_ARGS_LIST', argparse_args_list)
        return func
    return annotate