Package: argParseFromDoc
argParseFromDocA simple python package for creating/updatingargparseArgumentParser(s) given a type hinted and documented function.ContentInstallation[Quick overview](#Quick overview)Supported featuresAssumptionsUsageInstallationOption 1. Cloning this repository:git clone https://github.com/rsanchezgarc/argParseFromDoc.git
cd argParseFromDoc
pip install .Option 2. Installing with pippip install argParseFromDocOr if you want the latest updatepip install git+https://github.com/rsanchezgarc/argParseFromDocQuick overviewargParseFromDoc allows you to create argument parsers directly from the type hints and the docstring of a function.
The most common use case of creating a parser for a main function and calling it can be implemented in 2 lines if you
have previously documented your functiondef add(a: int, b: int):
    '''
    @param a: first number. 
    @param b: second number.
    '''
    return a + b
    
if __name__ == "__main__":
    from argParseFromDoc import parse_function_and_call
    out = parse_function_and_call(add)
    print(out)argParseFromDoc also support more advanced features via the classAutoArgumentParserand the functionget_parser_from_function.
See below for more detailsSupported featuresThe following features are currently supportedFunction argument types:int,str,floatandbool(Homogeneous) Lists of any of the previous types (defined astyping.List[primitive_type])Files (defined astyping.TextIOandtyping.BinaryIO)Ignoring/selecting a subset of the arguments of the functionUsemyarg:typing.Optional[VALID_TYPE]=Noneto set it as not required parameter orargs_optional=["myarg"]Creating a new parser or adding new arguments to it. You can also use parser groupsSeveral docsctring formats (seedocstring_parser)Support for methods assuming first argument in definition isselfAssumptionsPositional arguments. Functions can have positional arguments, but the parser will consider all them as
if they were keyword/optional (always--argname VALUE)If no default value is provided for an argument in the function signature, argument will be considered as
required (parser.add_argument(..., required=True)). The same applies todefault=Noneexcept if the
name of the argument is included inargs_optionalor it is declared astyping.Optional.E.gget_parser_from_function(..., args_optional=[name1, name2...])Boolean arguments:Boolean arguments must be provided with default value.If a boolean argument defaults to False (name:bool=False), the parser sets
the argumentname=Trueif--nameflag provided.If a boolean argument defaults to True (name:bool=True), the parser sets
the argumentname=Falseif--NOT_nameflag provided. Please notice that the name of
the argument in the argument parser has been changed fromnameto--NOT_nameto reflect that
but the argument is stored using the original name, so no further changes in the code are requiredMultiple arguments can be provided if usingtyping.List. For example:def fun(several_strings: List[str]):Setting deafult values fortyping.TextIOandtyping.BinaryIOis not advisable, as they should be opened files.
If you are only employing the function for the argument parser, you could default it to
string values pointing files, but again, this is not encouraged. Instead, if you want to set a default filename,
use typestr. The main purpose oftyping.TextIOandtyping.BinaryIOin the parser is to allow pipes. For example:#These two commands are equivalent
python count_lines --inputFile /etc/passwd 
cat /etc/passwd | python count_lines --inputFile -Methods, including__init__, are supported providingselfis always used as the first
argument in the definitionWhen defining functions,*argand**kwargsare ignored for the parser. No other*or**argument
is supported.UsageYou only need to document the type and possible default values for the arguments of your functions
withtypingand add the description of each within the docstring.
Examples of documented functions are:def add(a: int, b: int):
    '''
    @param a: first number. Mandatory
    @param b: second number. Mandatory
    '''
    return a + b
    
def printYourAge(age: int, name: str = "Unknown"):
    '''
    @param age: your age
    @param name: your name. This is optional
    '''
    return str(a) + " "+ b
    
def addList(several_nums: List[int], b: int=1):
    '''
    @param several_nums: first number
    @param b: second number
    '''
    return [a + b for a in several_nums]Then, obtaining an ArgumentParser for any of these functions (sayadd) is as easy as:if __name__ == "__main__":
    from argParseFromDoc import get_parser_from_function
    parser = get_parser_from_function(add)
    args = parser.parse_args()
    print(add(**vars(args)))Or you can directly use the AutoArgumentParser classif __name__ == "__main__":
    from argParseFromDoc import AutoArgumentParser
    parser = AutoArgumentParser()
    parser.add_args_from_function(add)Finally, for convenience, you can create the parser, parse the argument and call the function
in one line usingif __name__ == "__main__":
    from argParseFromDoc import parse_function_and_call
    out = parse_function_and_call(add)If you want to add to a previously instantiated parser the arguements of the function,
you just need to provide the original parser (or group) to theget_parser_from_functionfunction.if __name__ == "__main__":
    from argParseFromDoc import get_parser_from_function
    #standard ArgumentParser
    from argparse import ArgumentParser
    parser = ArgumentParser(prog="Add_example")
    parser.add_argument("--other_type_of_argument", type=str, default="Not provided")
    #####################################################
    # ### If you prefer a group instead of a whole parser
    # group = parser.add_argument_group()
    # get_parser_from_function(add, parser=group)
    #####################################################
    #provide the original parser to get_parser_from_function that will add the new options to the parser
    get_parser_from_function(add, parser=parser)
    args = parser.parse_args()
    print(add(**vars(args)))Finally, if your function has some arguments that you do not want to include
to the parser, you can use theargs_to_ignoreoption. If you want to use only a subset,
use theargs_to_includeoption.def manyArgsFun(a: int, b: int, c: int = 1, d: int = 2, e: str = "oneStr"):
    '''

    :param a: a
    :param b: b
    :param c: c
    :param d: d
    :param e: e
    :return:
    '''
    print(e)
    return sum([a, b, c, d])


if __name__ == "__main__":
    from argParseFromDoc import get_parser_from_function
    # parser = get_parser_from_function(manyArgsFun, args_to_ignore=["c", "d", "e"])
    parser = get_parser_from_function(manyArgsFun, args_to_include=["a", "b"])
    args = parser.parse_args()
    print(manyArgsFun(**vars(args)))You can use argParseFromDoc with subparsers easily. For instance:if __name__ == "__main__":
    from argParseFromDoc import AutoArgumentParser, get_parser_from_function
    parser = AutoArgumentParser("programName")

    subparsers = parser.add_subparsers(help='command: this is to select a command', required=True, dest='command')
    
    parser1 = subparsers.add_parser('command1_name', help='')
    get_parser_from_function(function1, parser=parser1)

    parser2 = subparsers.add_parser('command2_name', help='')
    get_parser_from_function(function2, parser=parser2)

    arguments = parser.parse_args()
    if arguments.command == "command1_name":
        del arguments.command
        function1(**vars(arguments))
    elif arguments.command == "command2_name":
        del arguments.command
        function2(**vars(arguments))
    else:
        raise ValueError(f"Command not valid {arguments.command}")Some additional examples can be found inexamples folderor intest_argParseFromDoc.py