Package: aphelper
APHelperGetting StartedTo use APHeler, add the following import statement to your codefromaphelperimportcoreThen, make sure your program has a main class with whatever functions you want to the commands to run contained in it. For example, here is a file with aTestclass that has atestfunction inside it which our command will call.fromaphelperimportcoreclassTest:def__init__(self):ah=core.ArgparseHelper(def_file='test/test.jsonc',parent=self)ah.execute()deftest(self,args):print('test')if__name__=='__main__':Test()You'll see that in the class' init function we create acore.ArgparseHelperobject and pass the location of a definition file along with 'self'. You can pass a file location with thedef_filekeyword or you can pass the contents of a file with thedef_datakeyword.
Following the creation of the object, we callah.execute()to create and parse the CLI.The definition file used in this example is below:{
    // the meta section defines information about the parser/subparser
    // for this first meta section you don't need the parser_help key/field
    "meta": {
        "parser_description": "Foo bar",
        "subparser_title": "subcommands",
        "subparser_dest": "command",
        "subparser_description": "valid subcommands"
    },
    // the subparsers key is used to define any parsers that need to be created
    "subparsers": {
        // in this case "hello" is the name of the first command
        "hello": {
            "meta": {
                "parser_description": "hello description",
                "parser_help": "hello help",
                "subparser_title": "subcommands",
                "subparser_dest": "subcommand",
                "subparser_description": "valid subcommands"
            },
            // once again we have a subparsers section which means we want another command
            // underneath "hello" which is not a final subcommand
            "subparsers": {
                "world": {
                    "meta": {
                        "parser_description": "world description",
                        "parser_help": "world help",
                        "subparser_title": "subcommands",
                        "subparser_dest": "subsubcommand",
                        "subparser_description": "valid subcommands"
                    },
                    // subcommands are for defining the "lowest level" commands which actually
                    // have arguments
                    // in this case, we are defining the "test" in the command string "hello world test"
                    "subcommands": {
                        "test": {
                            "meta": {
                                "description": "test help",
                                "help": "test description",
                                "function": {
                                    "name": "test",
                                    "args": {}
                                },
                                "requires": {
                                    "foo1": {
                                        "AND": ["bar1", "bar2"],
                                        "message": "the 'foo1' argument requires '--bar1' and '--bar2'"
                                    },
                                    "foo2": {
                                        "OR": ["bar1", "bar2"],
                                        "message": "the 'foo2' argument requires either '--bar1' or '--bar2'"
                                    },
                                    "foo3": {
                                        "NAND": ["bar1", "bar2"],
                                        "message": "the 'foo3' argument requires either '--bar1' or '--bar2' or neither, but not both"
                                    },
                                    "foo4": {
                                        "NOR": ["bar1", "bar2"],
                                        "message": "the 'foo4' argument requires '--bar1' and '--bar2' to be false"
                                    },
                                    "foo5": {
                                        "NOT": ["bar1"],
                                        "message": "the 'foo5' argument requires '--bar1' to be false"
                                    },
                                    "foo6": {
                                        "XOR": ["bar1", "bar2"],
                                        "message": "the 'foo6' argument requires '--bar1' or '--bar2', but not both"
                                    }
                                }
                            },
                            "args": {
                                "foo1": {
                                    "short": "-f",
                                    "long": "--foo1",
                                    "choices": null,
                                    "default": null,
                                    "help": null,
                                    "action": "store_true",
                                    "nargs": null
                                },
                                "foo2": {
                                    "long": "--foo2",
                                    "choices": null,
                                    "default": null,
                                    "help": null,
                                    "action": "store_true",
                                    "nargs": null
                                },
                                "foo3": {
                                    "long": "--foo3",
                                    "choices": null,
                                    "default": null,
                                    "help": null,
                                    "action": "store_true",
                                    "nargs": null
                                },
                                "foo4": {
                                    "long": "--foo4",
                                    "choices": null,
                                    "default": null,
                                    "help": null,
                                    "action": "store_true",
                                    "nargs": null
                                },
                                "foo5": {
                                    "long": "--foo5",
                                    "choices": null,
                                    "default": null,
                                    "help": null,
                                    "action": "store_true",
                                    "nargs": null
                                },
                                "foo6": {
                                    "long": "--foo6",
                                    "choices": null,
                                    "default": null,
                                    "help": null,
                                    "action": "store_true",
                                    "nargs": null
                                },
                                "bar1": {
                                    "long": "--bar1",
                                    "choices": null,
                                    "default": null,
                                    "help": null,
                                    "action": "store_true",
                                    "nargs": null
                                },
                                "bar2": {
                                    "long": "--bar2",
                                    "choices": null,
                                    "default": null,
                                    "help": null,
                                    "action": "store_true",
                                    "nargs": null
                                }
                            }
                        }
                    }
                } 
            }
        }
    }
}Definition File StructureAPHelperallows for nested definitions within the definition file in order to create a multi-layered command line interface.  The two main object types that can be defined aresubparsersandsubcommands.Subparsersare any CLI level that does not handle arguments directly and instead is a parent to othersubparsersorsubcommands.subcommandsare different in that they are the final children ofsubparsersand cannot contain any othersubcommands, instead they hold the argument definitions for the command.When writing a definition file, you must always start with this template:{
    // the meta section defines information about the parser/subparser
    // for this first meta section you don't need the parser_help key/field
    "meta": {
        "parser_description": "",
        "subparser_title": "",
        "subparser_dest": "",
        "subparser_description": ""
    }
}On the same level as the "meta" command you can then add asubaparsersorsubcommandssection depending on your needs.The structure of asubparserssection is shown below."subparsers": {
    // in this case "hello" is the name of the first command
    "hello": {
        "meta": {
            // these five fields are required for any subparser
            // However, you can always set them to an empty string
            "parser_description": "hello description",
            "parser_help": "hello help",
            "subparser_title": "subcommands",
            "subparser_dest": "subcommand",
            "subparser_description": "valid subcommands"
        },
        // if you want to have sub-subparsers, you can define another subparsers section
        // if not, then just don't add it
        "subparsers": {},
        // if you want to have subcommands, you can define a subcommandssection
        // if not, then just don't add it
        "subcommands": {}
    },
    // if you want more than one command on this level then you can just add another key
    // along with its "meta" section and any desired "subparsers" and "subcommands"
    "hello2": {
        // ...
    },
    // ...
 }The structure of asubcommandssection is shown below."subcommands": {
    // in this case "hello" is the name of the first command
    "world": {
        "meta": {
            // command description (required)
            "description": "",
            // command help (required)
            "help": "",
            "function": { // (required)
                // name of the function inside the class that calls the ArgparseHelper object
                // that you want to call when the command is executed
                "name": ""
            },
            "requires": { // (required, but you can just leave it blank if you want)
                // here we define any arguments that require logic to make sure that combinations of arguments are valid
                // set the argument that you want to trigger the logical check as the key
                "foo1": { 
                    // then define any logical checks you want to be made
                    // The valid operators are:
                    //   - AND
                    //   - NAND
                    //   - NOR
                    //   - NOT
                    //   - OR
                    //   - XOR
                    "AND": ["bar1", "bar2"],
                    // the message to print out if the logical check fails
                    "message": "the 'foo1' argument requires '--bar1' and '--bar2'"
                }
            }
        },
        "args": {
            "foo1": {
                // you need either a "short" key or a "long" key or both
                "short": "-f", // this is the single-letter flag that can be used for this argument
                "long": "--foo1", // this is the long flag that can be used for this argument
                // you can define any argparse keyword for the `add_argument` functio as a key and for an agrument
                // and it will be added to your argument that is created in your applicatoin
                // for example, in this case we set the 'action' keyword to 'store_true' for a boolean flag
                "action": "store_true"
            },
            "bar1": {
                "long": "--bar1",
                "action": "store_true"
            },
            "bar2": {
                "long": "--bar2",
                "action": "store_true"
            }
        }
    },
    // if you want more than one command on this level then you can just add another key
    // along with its "meta" and "args" sections
    "world2": {
        // ...
    },
    // ...
 }You can then nest thesesubcommandsandsubparserssections together to create whatever structure you need