# Advanced features The Command Line Interface created with `clig` can be customized in some ways. Some of these ways are already provided by the [argparse](https://docs.python.org/3/library/argparse.html) module, but other additional parameters can be used to add extra customization. ## Parameters for `clig.run()` function The first parameter of the [`clig.run()`](clig.run) function is typically a function that will be turned into a command. The second positional parameter could be a [list of strings to pass to the commad inside the code](https://docs.python.org/3/library/argparse.html#args) (which is defaulted to `sys.argv`). On top of that, other parameters can be passed as keyword arguments. They are the parameters of the original [`ArgumentParser()`](https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser) constructor and some new [extra parameters](#extra-parameters-specific-of-the-cligrun-function), as detailed below. ### Parameters of the original [`ArgumentParser()`](https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser) object All of these parameters should be passed as keyword arguments to the [`clig.run()`](clig.run) function. Refer to the [original `argparse` documentation](https://docs.python.org/3/library/argparse.html#argumentparser-objects) for details. Some parameters has predefined values assumed by `clig` (which can be modified), as detailed in the short descriptions below: - [`prog`](clig.CommandArguments.prog): The name of the new created program command. The default value is the name of the input function, with hyphens `-` replacing underscores `_`: ```python >>> import clig ... >>> def my_program(): ... """Short description""" ... pass ... >>> clig.run(my_program, ["-h"]) usage: my-program [-h] Short description options: -h, --help show this help message and exit ``` ```python >>> clig.run(my_program, ["-h"], prog="myNewProgram") usage: myNewProgram [-h] Short description options: -h, --help show this help message and exit ``` - [`description`](clig.CommandArguments.description): A text to display before the arguments help. By default, `clig` tries to get this parameter as the first line of the function docstring, [which can be customized](#docstring-templates). ```python >>> clig.run(my_program, ["-h"], description="The description of my program") usage: my-program [-h] The description of my program options: -h, --help show this help message and exit ``` - [`epilog`](clig.CommandArguments.epilog): A text to display after the command help. By default, `clig` tries to get this parameter from the function docstring after its first line, but [this also can be customized](#docstring-templates). ```python >>> clig.run(my_program, ["-h"], epilog="Text displayed after, with additional info.") usage: my-program [-h] Short description options: -h, --help show this help message and exit Text displayed after, with additional info. ``` Other [`ArgumentParser()`](https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser) parameters behave the same as in the original object. For instance, you can change the [`add_help`](https://docs.python.org/3/library/argparse.html#add-help) parameter to `False` (This parameter adds a `-h/--help` option to the command and the default is `True`) ```python >>> clig.run(my_program, ["-h"], add_help=False) usage: my-program my-program: error: unrecognized arguments: -h ``` ### Extra parameters specific of the [`clig.run()`](clig.run) function The [`clig.run()`](clig.run) function has some extra parameters that help to customize the interface. #### Metavar modifiers The parameter [`metavarmodifier`](clig.CommandArguments.metavarmodifier) lets you input a function that changes the [`metavar`](https://docs.python.org/3/library/argparse.html#metavar) keyword argument for all command arguments. The defined function can receive the argument `name` (not uppercased) and must return a string, ```python # ex01.py import clig def main(foo: str, bar: int = 32): return locals() clig.run(main, metavarmodifier=lambda name: f"<<{name}>>") ``` ```none > python ex01.py -h usage: main [-h] [--bar <>] <> positional arguments: <> options: -h, --help show this help message and exit --bar <> ``` To specify different modifiers for positional and optional arguments, use [`posmetavarmodifier`](clig.CommandArguments.posmetavarmodifier) and [`optmetavarmodifier`](clig.CommandArguments.optmetavarmodifier), which takes precedence over [`metavarmodifier`](clig.CommandArguments.metavarmodifier). ```python # ex02.py import clig def main(foo: str, bar: int = 32): return locals() clig.run(main, optmetavarmodifier=lambda s: f"<<<{s}>>>") ``` ```none > python ex02.py -h usage: main [-h] [--bar <<>>] foo positional arguments: foo options: -h, --help show this help message and exit --bar <<>> ``` #### Help modifiers Similarly to [`metavarmodifier`](clig.CommandArguments.metavarmodifier), [`helpmodifier`](clig.CommandArguments.helpmodifier) lets you define functions that change the [`help`](https://docs.python.org/3/library/argparse.html#help) keyword argument for all command arguments. The function should receive the already set [`help`](https://docs.python.org/3/library/argparse.html#help) argument and return a new string. This can be useful to include [format specifiers, already available in the original `help`](https://docs.python.org/3/library/argparse.html#help) keyword argument, for example. To specify different modifiers for positional and optional arguments, you can use [`poshelpmodifier`](clig.CommandArguments.poshelpmodifier) and [`opthelpmodifier`](clig.CommandArguments.opthelpmodifier) (which takes precedence over [`helpmodifier`](clig.CommandArguments.helpmodifier)). ```python # ex03.py import clig def myprogram(foo: str, bar: int = 32): """Summary Args: foo: Description of foo. bar: Description of bar. """ return locals() posmodifier = lambda h: "The '%(dest)s' argument of '%(prog)s'. " + h optmodifier = lambda h: "The '%(dest)s' argument of '%(prog)s'. " + h + " Defaults to %(default)s" clig.run(myprogram, poshelpmodifier=posmodifier, opthelpmodifier=optmodifier) ``` ```none > python ex03.py -h usage: myprogram [-h] [--bar BAR] foo Summary positional arguments: foo The 'foo' argument of 'myprogram'. Description of foo. options: -h, --help show this help message and exit --bar BAR The 'bar' argument of 'myprogram'. Description of bar. Defaults to 32 ``` #### Help flags and messages As you may know, [`argparser`](https://docs.python.org/3/library/argparse.html)'s objects add an option by default, which simply displays the command's help message (Normally "`-h, --help show this help message and exit`") that can be disabled with [`add_help=False`](https://docs.python.org/3/library/argparse.html#add-help). Occasionally, you may not want to disable the help option, but simply change its flags or message: that can be achieved by disabling the help option and adding a new function argument with parameter [`action="help"`](https://docs.python.org/3/library/argparse.html#action) in the command line. However, you may not want to add any new extra argument in the function to just handle help messages, but still want to change them. For these cases, there are two extra arguments, [`help_flags`](clig.CommandArguments.help_flags) and [`help_msg`](clig.CommandArguments.help_msg), which do exactly that: Set different help flags or different help message. ```python # ex04.py import clig def main(): pass clig.run(main, help_flags=["-?", "--show-help"]) ``` ```none > python ex04.py -? usage: main [-?] options: -?, --show-help show this help message and exit ``` The parameter [`help_msg`](clig.CommandArguments.help_msg) could be used as a simple way to change the help message, maybe to a different language: ```python # ex05.py import clig def main(): pass clig.run(main, help_msg="Diese Hilfe Meldung anzeigen und beenden") ``` ```none > python ex05.py -h usage: main [-h] options: -h, --help Diese Hilfe Meldung anzeigen und beenden ``` #### Version Normally, you can add a new function argument with parameter [`action="version"`](https://docs.python.org/3/library/argparse.html#action) in the command line, which expects a `version=` keyword argument in the [`data()`](./userguide.md#argument-specification) call, prints version information and exits when invoked. However, you may not want to add any new extra argument in the function to just handle version information, but still want to use that feature. For these cases, there the extra arguments: [`version`](clig.CommandArguments.version), [`versionmodifier`](clig.CommandArguments.versionmodifier) and [`version_msg`](clig.CommandArguments.version_msg). ```python # ex06.py import clig def my_program(): pass clig.run(my_program, version='%(prog)s 2.0') ``` ```none > python ex06.py -h usage: my-program [-h] [--version] options: -h, --help show this help message and exit --version show program's version number and exit ``` ```none > python ex06.py --version my-program 2.0 ``` The [`version`](clig.CommandArguments.version) argument accepts a string like in the original [argparse](https://docs.python.org/3/library/argparse.html#action) module (as shown above) but also accepts a boolean. If `version=True`, `clig` tries to find the version information from the function's package metadata. ```python # ex07.py import clig import yaml clig.run(yaml.add_constructor, version=True) ``` ```none > python ex07.py --version 6.0.3 ``` Similarly to [`metavarmodifier`](clig.CommandArguments.metavarmodifier) and [`helpmodifier`](clig.CommandArguments.helpmodifier), [`versionmodifier`](clig.CommandArguments.versionmodifier) lets you define a function that change the version string. The function should receive the version string and return a new string. ```python # ex08.py import clig import yaml clig.run(yaml.add_constructor, version=True, versionmodifier=lambda s: f"addconstructor v{s}") ``` ```none > python ex08.py --version addconstructor v6.0.3 ``` The option [`versionhelp`](clig.CommandArguments.versionhelp) lets you change the default help message for the `--version` argument (the default is `show program's version number and exit`). ```python # ex09.py import clig def main(): pass clig.run(main, version="1.2.3", versionhelp="Show the AWESOME information about version!") ``` ```none > python ex09.py --help usage: main [-h] [--version] options: -h, --help show this help message and exit --version Show the AWESOME information about version! ``` #### Automatic argument flags As you may know, you can add extra _flags_ (options with prefix, normally `-` or `--`) to arguments [using the `data()` function in the argument annotation](./userguide.md#name-or-flags) (on the function signature). However, you may want to add/change argument flags automatically, without touching the function signature. For these cases, you can use the booleans [`make_flags`](clig.CommandArguments.make_flags) or [`make_shorts`](clig.CommandArguments.make_shorts). ##### Using `make_flags` Setting `make_flags=True` creates flags even for required arguments ```python # ex10.py import clig def main(foo: str, bar: int): pass clig.run(main, make_flags=True) ``` ```none > python ex10.py -h usage: main [-h] --foo FOO --bar BAR options: -h, --help show this help message and exit --foo FOO --bar BAR ``` For non-required arguments, `make_flags=False` turns them into required arguments. ```python # ex11.py import clig def main(foo: str = "baz", bar: int = 42): pass clig.run(main, make_flags=False) ``` ```none > python ex11.py -h usage: main [-h] foo bar positional arguments: foo bar options: -h, --help show this help message and exit ``` For non-required arguments, `make_flags=True` creates the regular flags from the argument names in the cases where they are not present in the data. ```python # ex12.py import clig def main( foo: clig.Arg[str, clig.data("--foobar")] = "baz", bar: clig.Arg[int, clig.data("--barfoo")] = 42, ): pass clig.run(main, make_flags=True) # forces creation of --foo and --bar ``` ```none > python ex12.py -h usage: main [-h] [--foobar FOO] [--barfoo BAR] options: -h, --help show this help message and exit --foobar FOO, --foo FOO --barfoo BAR, --bar BAR ``` ##### Using `make_shorts` Setting `make_shorts=True` creates "short flags" only for the non-required arguments. ```python # ex13.py import clig def main(foo: str, bar: int = 42): pass clig.run(main, make_shorts=True) ``` ```none > python ex13.py -h usage: main [-h] [-b BAR] foo positional arguments: foo options: -h, --help show this help message and exit -b BAR, --bar BAR ``` To force the creation of "short flags" for required arguments, pass both `make_flags=True` and `make_shorts=True`: ```python # ex14.py import clig def main(foo: str, bar: int = 42): pass clig.run(main, make_shorts=True, make_flags=True) ``` ```none > python ex14.py -h usage: main [-h] -f FOO [-b BAR] options: -h, --help show this help message and exit -f FOO, --foo FOO -b BAR, --bar BAR ``` The strategy to create "short flags" uses the following order: - First letter of the argument name (the simplest case) - First letter of the argument name UPPERCASED (when there are two names starting with same letter) - First letter of the each argument name part if it has TWO_PARTS (separated by underscores) If the rules above produce ambiguous flags, the strategy starts searching again using first and second letters. If ambiguity is found again, shearch for first, second and third letters, and so on. ```python # ex15.py import clig def main( file: str = ".", filename: str = ".", filedir: str = ".", filepath: str = ".", file_name: str = ".", file_dir: str = ".", file_path: str = ".", folder: str = ".", foldername: str = ".", folderdir: str = ".", folderpath: str = ".", folder_name: str = ".", folder_dir: str = ".", folder_path: str = ".", ): pass clig.run(main, make_shorts=True) ``` ```none > python ex15.py -h usage: main [-h] [-f FILE] [-F FILENAME] [-fi FILEDIR] [-FI FILEPATH] [-fn FILE_NAME] [-fd FILE_DIR] [-fp FILE_PATH] [-fo FOLDER] [-FO FOLDERNAME] [-fol FOLDERDIR] [-FOL FOLDERPATH] [-fona FOLDER_NAME] [-fodi FOLDER_DIR] [-fopa FOLDER_PATH] options: -h, --help show this help message and exit -f FILE, --file FILE -F FILENAME, --filename FILENAME -fi FILEDIR, --filedir FILEDIR -FI FILEPATH, --filepath FILEPATH -fn FILE_NAME, --file-name FILE_NAME -fd FILE_DIR, --file-dir FILE_DIR -fp FILE_PATH, --file-path FILE_PATH -fo FOLDER, --folder FOLDER -FO FOLDERNAME, --foldername FOLDERNAME -fol FOLDERDIR, --folderdir FOLDERDIR -FOL FOLDERPATH, --folderpath FOLDERPATH -fona FOLDER_NAME, --folder-name FOLDER_NAME -fodi FOLDER_DIR, --folder-dir FOLDER_DIR -fopa FOLDER_PATH, --folder-path FOLDER_PATH ``` #### Docstring templates Getting information from docstrings is a central feature in `clig`. The parameter `docstring_template` takes a "string template" and tries to match it with the docstring given in the function. The searched fields in the template are the following: - `{{description}}` - `{{epilog}}` - `{{parameter_name}}` - `{{parameter_description}}` After the first pair of `{{parameter_name}}`/`{{parameter_description}}`, the pattern repeats. Set this explicitly to skip auto-detection and enforce a specific format. ```python # ex16.py import clig my_template = """ {{description}} Arguments: * {{parameter_name}} -- {{parameter_description}} """ def main(a, b, c): """Summary of function Arguments: * a -- Description of parameter a * b -- Description of parameter b * c -- Description of parameter c """ pass clig.run(main, docstring_template=my_template) ``` ```none > python ex16.py -h usage: main [-h] a b c Summary of function positional arguments: a Description of parameter a b Description of parameter b c Description of parameter c options: -h, --help show this help message and exit ``` If not given, a [list of default templates](../docstrings_templates.md) is shearched by default. You can use a [`DocStr`](clig.DocStr) enum member that has those default templates. ```python # ex17.py import clig def main(a, b, c): """Summary of function with Google style. Args: a: Description of parameter a b: Description of parameter b c: Description of parameter c """ pass clig.run(main, docstring_template=clig.DocStr.GOOGLE_DOCSTRING_NOTYPES) ``` ```none > python ex17.py -h usage: main [-h] a b c Summary of function with Google style. positional arguments: a Description of parameter a b Description of parameter b c Description of parameter c options: -h, --help show this help message and exit ``` #### Description, epilog and usage modifiers Similarly to other modifiers [`descriptionmodifier`](clig.CommandArguments.descriptionmodifier), [`epilogmodifier`](clig.CommandArguments.epilogmodifier) and [`usagemodifier`](clig.CommandArguments.usagemodifier) let you define a function that change the [`description`](clig.CommandArguments.description), [`epilog`](clig.CommandArguments.epilog) and [`usage`](clig.CommandArguments.usage) strings. The functions should receive strings and return new strings. ```python # ex18.py import clig def main(): """My awesome command description""" pass clig.run(main, descriptionmodifier=lambda s: f"{'-'*len(s)}\n{s}\n{'-'*len(s)}") ``` ```none > python ex18.py -h usage: main [-h] ------------------------------ My awesome command description ------------------------------ options: -h, --help show this help message and exit ``` ```python # ex19.py import clig def main(a, b, c): """This command had usage modified""" pass clig.run(main, usagemodifier=lambda s: s.replace("[", "[inserted after PROG and -h] [")) ``` ```none > python ex19.py --help usage: main [inserted after PROG and -h] [-h] a b c This command had usage modified positional arguments: a b c options: -h, --help show this help message and exit ``` #### Keep prefix for keywords variadic arguments (`**kwargs`) As [described in the Userguide](./userguide.md#kwargs), unspecified arguments passed with _flags_ will be wrapped up in a dictionary of arbitrary keyword arguments in the form `**kwargs`. ```python # ex20.py import clig def main(foo, **kwargs): print(locals()) clig.run(main) ``` ```none > python ex20.py bar --name adam -f myfile --title mister {'foo': 'bar', 'kwargs': {'name': 'adam', 'f': 'myfile', 'title': 'mister'}} ``` With [`keepvariadicprefixchars=True`](clig.CommandArguments.keepvariadicprefixchars) the prefix chars (normally `--` or `-`) will be preserved in the resulting dictionary: ```python # ex21.py import clig def main(foo, **kwargs): print(locals()) clig.run(main, keepvariadicprefixchars=True) ``` ```none > python ex21.py bar --name adam -f myfile --title mister {'foo': 'bar', 'kwargs': {'--name': 'adam', '-f': 'myfile', '--title': 'mister'}} ``` ### Calling `clig.run()` without a function It is possible to call the `clig.run()` without any arguments, even without the function argument. To do this, a `Command` instance must have been created first, using the [`clig.command()` function as a function decorator](./subcommands.md#subcommands-using-function-decorators). ```python # ex22.py import clig @clig.command def main(foo: str, bar: int): pass clig.run() ``` ```none > python ex22.py -h usage: main [-h] foo bar positional arguments: foo bar options: -h, --help show this help message and exit ``` ## Parameters for `clig.Command()` constructor The `clig.Command()` constructor accepts [all arguments of the `clig.run()`](#parameters-for-cligrun-function) function. It also accepts some other arguments related to subcommands. The first parameter of the `clig.Command()` constructor is typically a function that will be turned into a command. Additionally, other parameters can be passed. They are the [extra parameters of the `clig.run()` function](#extra-parameters-specific-of-the-cligrun-function), parameters of the original [`ArgumentParser()` constructor](https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser), some parameters of the [`ArgumentParser.add_subparsers()` method](https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.add_subparsers) (to control subcommands) and parameters of the [`add_parser()`](https://github.com/python/cpython/blob/1ed98a6b5155dd239d35f3c9dd35477feded9e1c/Lib/argparse.py#L1246) method, as detailed below. The parameters of the original [`ArgumentParser()`](https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser) constructor can be passed in their original form (as _positional_ or _keyword_ arguments). Some default values follow the [description in the previous section describing the `clig.run()` function](./advancedfeatures.md#parameters-of-the-original-argumentparser-object). The parameters of the original [`ArgumentParser.add_subparsers()` method](https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.add_subparsers) have to be passed only as _keyword_ arguments, with names prefixed by `subcommands_` and has some default values, detailed in the following. The parameters of the [original `add_parser()` method](https://github.com/python/cpython/blob/1ed98a6b5155dd239d35f3c9dd35477feded9e1c/Lib/argparse.py#L1246) might be passed to the methods that create subcommands ([`new_subcommand()`](clig.Command.new_subcommand), [`add_subcommand()`](clig.Command.add_subcommand) and [`end_subcommand()`](clig.Command.end_subcommand)) and not directly to the [`Command()`](clig.Command) constructor. ### Parameters of the original [`add_subparsers()`](https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.add_subparsers) method Except for some arguments (like [`action`](https://docs.python.org/3/library/argparse.html#action) and [`dest`](https://docs.python.org/3/library/argparse.html#dest)) all parameter of the [original `ArgumentParser.add_subparsers()` method](https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.add_subparsers) can be specified in the [`Command()`](clig.Command) constructor, for whose the names are prepended by `subcommands_`. The supported parameters are the following: - [`subcommands_title`](clig.Command.subcommands_title): title for the sub-parser group in help output. By default it is `"subcommands"` if a [`description`](clig.Command.subcommands_description) is provided, otherwise it uses the title for `positional arguments:`, like the original behavior in `argparse`. ```python >>> from clig import Command ... >>> def main(): ... pass ... >>> def foo(): ... pass ... >>> def bar(): ... pass ... >>> cmd = Command(main, subcommands_title="My subcommands") >>> cmd.add_subcommand(foo) >>> cmd.add_subcommand(bar) ... >>> cmd.print_help() usage: main [-h] {foo,bar} ... options: -h, --help show this help message and exit My subcommands: {foo,bar} ``` - [`subcommands_description`](clig.Command.subcommands_description): description for the sub-commands group in help output. By default, it is not passed to the underlying `add_subparsers()` method. When either [`subcommands_title`](clig.Command.subcommands_title) or [`subcommands_description`](clig.Command.subcommands_description) is present, the subcommands will appear in their own group in the help output. If only [`description`](clig.Command.subcommands_description) is provided, [`subcommands_title`](clig.Command.subcommands_title) will be `"subcommands"` by default. ```python >>> from clig import Command ... >>> def main(): ... pass ... >>> def foo(): ... pass ... >>> def bar(): ... pass ... >>> cmd = Command(main, subcommands_description="additional help") >>> cmd.add_subcommand(foo) >>> cmd.add_subcommand(bar) ... >>> cmd.print_help() usage: main [-h] {foo,bar} ... options: -h, --help show this help message and exit subcommands: additional help {foo,bar} ``` > [!NOTE] > Like in `argparse`, when `subcommands_description` is provided, an empty line > is added between this description and the subcommands list, as you can see > above. - [`subcommands_prog`](clig.Command.subcommands_prog): Usage information that will be displayed with subcommand help, by default the name of the program and any positional arguments before the subparser argument. - [`subcommands_required`](clig.Command.subcommands_required): Whether or not a subcommand must be provided, by default `False`. - [`subcommands_help`](clig.Command.subcommands_help): Help for sub-parser group in help output, by default `None`. - [`subcommands_metavar`](clig.Command.subcommands_metavar): String presenting available subcommands in help; by default it is `None` and presents subcommands in form `{cmd1, cmd2, ..}`. ### The parameters of the original [`add_parser()`](https://github.com/python/cpython/blob/1ed98a6b5155dd239d35f3c9dd35477feded9e1c/Lib/argparse.py#L1246) method The parameters of the original [`add_parser()`](https://github.com/python/cpython/blob/1ed98a6b5155dd239d35f3c9dd35477feded9e1c/Lib/argparse.py#L1246) method are passed only to the methods [`new_subcommand()`](clig.Command.new_subcommand), [`add_subcommand()`](clig.Command.add_subcommand) or [`end_subcommand()`](clig.Command.end_subcommand), not directly to the [`Command()`](clig.Command) constructor. The following are supported: - [`name`](clig.Command.name): Name of the subcommand, taken by the `add_parser()` method. The default is generated from the function name. ```python >>> from clig import Command ... >>> def main(): ... pass ... >>> def foobar(): ... pass ... >>> cmd = Command(main) >>> sub = cmd.new_subcommand(foobar, name="bazham") ... >>> cmd.print_help() usage: main [-h] {bazham} ... positional arguments: {bazham} options: -h, --help show this help message and exit ``` - [`help`](clig.Command.help): A help message for the subcommand. By default, it is taken from the subcommand's function description. ```python >>> from clig import Command ... >>> def main(): ... pass ... >>> def foo(): ... """Subcommand description""" ... pass ... >>> cmd1 = Command(main) >>> cmd1.new_subcommand(foo) ... >>> cmd1.print_help() usage: main [-h] {foo} ... positional arguments: {foo} foo Subcommand description options: -h, --help show this help message and exit ``` ```python >>> cmd2 = Command(main) >>> cmd2.new_subcommand(foo, help="Overwritten help") ... >>> cmd2.print_help() usage: main [-h] {foo} ... positional arguments: {foo} foo Overwritten help options: -h, --help show this help message and exit ``` - [`aliases`](clig.Command.aliases): List that allows multiple strings to refer to the same subcommand. ```python >>> from clig import Command ... >>> def main(): ... pass ... >>> def foo(): ... pass ... >>> cmd1 = Command(main) >>> cmd1.new_subcommand(foo, aliases=['fo', 'fooham']) ... >>> cmd1.print_help() usage: main [-h] {foo,fo,fooham} ... positional arguments: {foo,fo,fooham} options: -h, --help show this help message and exit ``` ### Calling `clig.Command()` without a function It is possible to call the `clig.Command()` without any arguments, even without the function argument. This may be usefull when you want to create an object not associated with any function, and add subcommands after: ```python # ex23.py from clig import Command cmd = Command() def foo(): pass def bar(): pass cmd.add_subcommand(foo).add_subcommand(bar).run() ``` ```none > python ex23.py -h usage: ex23.py [-h] {foo,bar} ... positional arguments: {foo,bar} options: -h, --help show this help message and exit ```