.. default-domain:: chpl .. module:: ArgumentParser :synopsis: A module to be used for defining and parsing command line arguments. ArgumentParser ============== **Usage** .. code-block:: chapel use ArgumentParser; or .. code-block:: chapel import ArgumentParser; .. warning:: ArgumentParser is unstable. A module to be used for defining and parsing command line arguments. .. note:: You must declare your main method to take an array of string arguments in order to get values from the command line. See the :ref:`quickstart example` below or the technote about :ref:`getting arguments from main()`. .. note:: Chapel programs can make use of :ref:`configuration constants and variables `. The ArgumentParser module can be used in place of, or in addition to, configuration variables and constants. In particular, it is common for Chapel programs to rely solely upon configuration variables and for such programs the ArgumentParser is not needed. .. note:: This module is in the initial stages of development and should be expected to change in future releases. Terminology ----------- Descriptions of each argument type are given below. **Arguments** These are also known as positional values and do not have any identifiers aside from the relative order and count of values entered. Example: .. code-block:: shell $ myExecutable filename1 filename2 filename3 **Options** These are values that follow some indicator, typically ``--option`` is used as a long option and ``-o`` might be the short indicator. Typically, 0 or more arguments may follow. Examples: .. code-block:: shell $ myExecutable --foo value1 $ myExecutable -f value1 **Flags** These are boolean indicators whose presence alone can be used to derive a true/false value. Example: .. code-block:: shell $ myExecutable --debug $ myExecutable -d **Subcommands** These are values that can be used to trigger execution of other methods which take their own arguments. A subcommand typically consumes the remaining values from the command line. Example: .. code-block:: shell $ myExecutable build --force otherProgram **PassThrough** This is a delimiter value which designates that all the values which follow should be collected for later use by the developer. Typically this value is a double dash ``--``. Example: .. code-block:: shell $ myExecutable build --force otherProgram -- --flags --for --compiling otherProgram .. _argumentParser-quickstart: Quickstart Example ------------------- .. code-block:: chapel module M { use ArgumentParser; proc main(args:[]string) throws { var parser = new argumentParser(); var simpleArg = parser.addArgument(name="positional"); var optionArg = parser.addOption(name="optional"); var flagArg = parser.addFlag(name="debug", defaultValue=false); parser.parseArgs(args); var debug = flagArg.valueAsBool(); // we are assured a value here or else the parser would have thrown an error var foo = simpleArg.value(); var bar:string; if optionArg.hasValue() then bar = optionArg.value(); } } This program would accept any of the following command line arguments (and other combinations): .. code-block:: shell $ quickStart myFile $ quickStart myFile --optional valueA $ quickStart myFile --debug $ quickStart myFile --optional valueA --debug $ quickStart --optional val1 --debug myFile And will not accept any of the following (reason given below): .. code-block:: shell $ quickStart --debug positional argument is missing $ quickStart myFile --debug=true debug flag does not accept values $ quickStart myFile --debug --optional optional expects 1 value If a user asks for help with either ``-h`` or ``--help``, the following output would be automatically generated and displayed: .. code-block:: shell $ quickStart -h USAGE: quickStart [-h, --help] [--debug] [--optional ] ARGUMENTS: POSITIONAL OPTIONS: -h, --help Display this message and exit --debug --optional .. _argumentParser-customizingHelp: Customizing Help Output ------------------------ There are various levels of support for help handling that you can request when initializing an ``argumentParser``. By default, an ``argumentParser`` handles help requests in the form of ``-h`` and ``--help``, builds a help message, builds a usage message, prints the combined help and usage message when either invalid input or help request is detected, and then exits. These actions are mostly customizable through arguments set when initializing an ``argumentParser`` or individual arguments, options, and flags. The text that describes each argument can be defined by setting a value for the ``help`` argument in the various `add` methods on the ``argumentParser``. Example usage: .. code-block:: chapel // to set the help text on an argument, flag, etc. var myArg = parser.addArgument(name="myArg", help="This text describes myArg for the user"); To take full control over what happens when a user requests help, create a new class that inherits the ``HelpHandler`` and override the ``printHelp()`` method. Then, create a new instance of your custom class and set it as the ``helpHandler`` argument when initializing the ``argumentParser``. This is designed to ease adoption when a program has existing functions to print its help messages. Example usage: .. code-block:: chapel class MyHelpHandler : HelpHandler { override proc printHelp() { // call some custom functions like ... // printMyCustomHelp(); // maybe other things? } } var parser = new argumentParser(helpHandler=new MyHelpHandler()); All help requests will now execute whatever is defined in ``printHelp()`` and then exit, as the parser's ``exitOnError`` is `true` by default. For existing programs where the help text is defined in a string, the ``argumentParser`` can accept a value in the ``helpMessage`` argument during initialization. Example usage: .. code-block:: chapel const myHelpMessage = "A customized message that should be displayed\n" + "instead of the usual help and usage message.\n" var parser = new argumentParser(helpMessage=myHelpMessage); To turn off help handling completely, set the ``addHelp`` argument to `false` when initializing the ``argumentParser``. .. record:: argumentParser A parser that performs the following functions: 1. Stores definitions of valid arguments/flags/options 2. Parses an array of arguments as passed from the command line (where args[0] is typically the name of the executable) 3. Throws an ArgumentError if invalid or unrecognized arguments are encountered The parser can process command line arguments that include or omit an equals sign ``=``, with short ``-`` or long ``--`` indicators. We can declare a new argumentParser like so: .. code-block:: chapel var parser = new argumentParser(); **Limitations** * Cannot place short flags together. That is, if a parser has defined short flags ``-c``, ``-a`` and ``-t``, we cannot handle ``-cat``. * Short options must be separated from their values with an equals sign or spaces. That is, ``-cValue`` is not supported and should be entered as either ``-c Value`` or ``-c=Value``. * Numeric types are not supported and will be passed as strings. * Chapel programs currently do config variable processing on the arguments. If you have arguments that conflict with config variables, you can place them after ``--`` on the command line in order to skip the config variable processing. If a passthrough is also specified as ``--``, then these arguments will also be captured by the passthrough. If that is not desired, you can create a different passthrough delimiter, e.g. ``++``. * Counting the number of times a flag is found on the command line is not supported. * The argument parser doesn't support checking for mutually exclusive arguments or arguments that are conditionally required. Instead, you can check after parsing the arguments that the provided arguments are acceptable. .. method:: proc init(addHelp = true, exitOnError = true, exitAfterHelp = true, in helpHandler: ?h = none, helpMessage: ?t = none) Initialize an instance of argumentParser. :arg addHelp: Determines if the ArgumentParser adds help flags and handles their presence in the command line arguments. Flag values are set to ``-h`` and ``--help``. Defaults to `true`. :arg exitOnError: Determines if ArgumentParser exits with error info when an error occurs. Defaults to `true`. :arg exitAfterHelp: Determines if ArgumentParser exits after it finds a help flag and prints the help message. Defaults to `true`. :arg helpHandler: Allows a user to define a custom HelpHandler to perform printing of the help message and additional operations. Defaults to a new instance of HelpHandler. Cannot be set in conjunction with `helpMessage`. :arg helpMessage: Allows a user to set a customized message to display as help output. Defaults to a help message generated by the argumentParser. Cannot be used in conjunction with `helpHandler`. .. method:: proc ref addArgument(name: string, numArgs = 1, defaultValue: ?t = none, help = "", visible = true, valueName: ?v = none): shared Argument throws Add an argument to the parser. Arguments are also commonly known as "positional arguments" and are not indicated by anything other than a value. For example, defining an argument like this: .. code-block:: chapel var fileArg = parser.addArgument(name="filename"); we would expect command line arguments like this: .. code-block:: shell $ programName myFile.ext :arg name: a friendly name to give this argument. This would typically be displayed in the `help` or `usage` message. :arg defaultValue: a value to assign the argument when it is not provided on the command line. If `numArgs` is greater than 1, an array or list may be passed. Defaults to `none`. :arg numArgs: an exact number of values expected from the command line. An ArgumentError will be thrown if more or fewer values are entered. :arg help: a message to display for this argument when help is requested :arg visible: determines if this argument should be displayed in the help and usage messages. Defaults to `true`. :arg valueName: an alternative display name for the value in the help and usage messages for this argument. Defaults to the uppercase representation of the `name` field. :returns: a shared `Argument` where parsed values will be placed :throws: `ArgumentError` in any of the following conditions: * `name` is already defined for this parser * `defaultValue` is something other than a string, array or list of strings. .. method:: proc ref addArgument(name: string, numArgs: range(?), defaultValue: ?t = none, help = "", visible = true, valueName: ?v = none): shared Argument throws An overload of ``addArgument``, described above, that accepts a range for `numArgs`. For example, defining an argument like this: .. code-block:: chapel var filesArg = parser.addArgument(name="filenames", numArgs=1..); we would expect command line arguments like either of these: .. code-block:: shell $ programName myFile1.ext myFile2.ext myFile3.ext ... $ programName myFile1.ext :arg name: a friendly name to give this argument. This would typically be displayed in the `help` or `usage` message. :arg defaultValue: a value to assign the argument when it is not provided on the command line. If `numArgs` is greater than 1, an array or list may be passed. Defaults to `none`. :arg numArgs: a range of values expected from the command line. If using a range, the argument must be the only positional that accepts a range, and must be specified last relative to other positional arguments to avoid ambiguity. An ArgumentError will be thrown if more or fewer values are entered. :arg help: a message to display for this argument when help is requested :arg visible: determines if this argument should be displayed in the help and usage messages. Defaults to `true`. :arg valueName: an alternative display name for the value in the help and usage messages for this argument. Defaults to the uppercase representation of the `name` field. :returns: a shared `Argument` where parsed values will be placed :throws: `ArgumentError` in any of the following conditions: * `name` is already defined for this parser * `defaultValue` is something other than a string, array or list of strings. * `numArgs` is neither low-bound nor fully-bound .. method:: proc ref addOption(name: string, opts: [] string = _processNameToOpts(name), numArgs = 1, required = false, defaultValue: ?t = none, help = "", visible = true, valueName: ?v = none): shared Argument throws Add an option to the parser. Options are typically indicated by one or two leading dashes ``-`` and may be followed by 0 or more values. For example, defining an option like this: .. code-block:: chapel var fileArg = parser.addOption(name="filename"); we would expect command line arguments like either of these: .. code-block:: shell $ programName --filename=myFile1.ext $ programName --filename myFile1.ext :arg name: a friendly name to give this option, or a pattern to use to indicate this option from the command line. If providing a pattern, use a leading single dash ``-`` or double dash ``--``. :arg opts: an array of string values that can be used to indicate this option. Defaults to a long version of the `name` field with leading double dashes ``--``. :arg required: a bool to set this option as a required command line argument. If set to `true`, an ArgumentError will be thrown if the user fails to enter the option on the command line. Defaults to `false`. :arg defaultValue: a value to assign the argument when an option is not required, and a is not entered on the command line. If `numArgs` is greater than 1, an array or list may be passed. Defaults to `none`. :arg numArgs: the exact number of values expected to follow the option on the command line. An ArgumentError will be thrown if more or fewer values are entered. :arg help: a message to display for this option when help is requested :arg visible: determines if this option should be displayed in the help and usage messages. Defaults to `true`. :arg valueName: an alternative display name for the value in the help and usage messages when an option accepts values. Defaults to the uppercase representation of the `name` field. :returns: a shared `Argument` where parsed values will be placed :throws: `ArgumentError` in any of the following conditions: * `name` or `opts` are already defined for this parser * values in `opts` do not begin with a dash ``-`` * `defaultValue` is something other than a string, array or list of strings. .. method:: proc ref addOption(name: string, opts: [] string = _processNameToOpts(name), numArgs: range(?), required = false, defaultValue: ?t = none, help = "", visible = true, valueName: ?v = none): shared Argument throws An overload of ``addOption`` described above that accepts a range of expected values for `numArgs`. For example, defining an option like this: .. code-block:: chapel var filesArg = parser.addOption(name="filenames", numArgs=1..); we would expect command line arguments like any of these: .. code-block:: shell $ programName --filenames myFile1.ext myFile2.ext myFile3.ext ... $ programName --filenames=myFile1.ext $ programName --filenames myFile1.ext --filenames myFile2.ext ... :arg name: a friendly name to give this option, or a pattern to use to indicate this option from the command line. If providing a pattern, use a leading single dash ``-`` or double dash ``--``. :arg opts: an array of string values that can be used to indicate this option. Defaults to a long version of the `name` field with leading double dashes ``--``. :arg required: a bool to set this option as a required command line argument. If set to `true`, an ArgumentError will be thrown if the user fails to enter the option on the command line. Defaults to `false`. :arg defaultValue: a value to assign the argument when an option is not required, and a is not entered on the command line. If `numArgs` is greater than 1, an array or list may be passed. Defaults to `none`. :arg numArgs: a range of values expected to follow the option on the command line. This may be a fully-bound range like ``1..10`` or a lower-bound range like ``1..``. An ArgumentError will be thrown if more or fewer values are entered. :arg help: a message to display for this option when help is requested :arg visible: determines if this option should be displayed in the help and usage messages. Defaults to `true`. :arg valueName: an alternative display name for the value in the help and usage messages when an option accepts values. Defaults to the uppercase representation of the `name` field. :returns: a shared `Argument` where parsed values will be placed :throws: `ArgumentError` in any of the following conditions: * `name` or `opts` are already defined for this parser * values in `opts` do not begin with a dash ``-`` * `defaultValue` is something other than a string, array or list of strings. * `numArgs` does not have a low-bound .. method:: proc ref addFlag(name: string, opts: [?optsD] = _processNameToOpts(name), required = false, defaultValue: ?t = none, flagInversion = false, numArgs = 0, help = "", visible = true, valueName: ?v = none): shared Argument throws Add a flag to the parser. Flags may be setup in several ways depending on the user's needs. For example, defining a flag like this: .. code-block:: chapel var debugArg = parser.addFlag(name="debug"); we would expect command line arguments like this: .. code-block:: shell $ programName --debug :arg name: a friendly name to give this flag, or a pattern to use to indicate this flag from the command line. If providing a pattern, use a leading single dash ``-`` or double dash ``--``. :arg opts: an array of string values that can be used to indicate this flag. Defaults to a long version of the `name` field with leading double dashes ``--``. :arg required: a bool to set this flag as a required command line argument. If set to `true`, an ArgumentError will be thrown if the user fails to enter the flag on the command line. Defaults to `false`. :arg defaultValue: a value to assign the argument when a flag is not required, and a is not entered on the command line. Defaults to `none`. :arg flagInversion: a bool to indicate if the parser should automatically create a ``--no-`` version of this flag to mean `false` when entered from the command line. i.e. ``--[no-]build`` :arg numArgs: the number of values expected to follow the flag on the command line. Defaults to 0 and has a max value of 1. when 0, then ``--flag`` is accepted while ``--flag=true`` is rejected when 1, then ``--flag`` is rejected while ``--flag=true`` is accepted :arg help: a message to display for this flag when help is requested :arg visible: determines if this flag should be displayed in the help and usage messages. Defaults to `true`. :arg valueName: an alternative display name for the value in the help and usage messages when a flag accepts a value. Defaults to the uppercase representation of the `name` field. :returns: a shared `Argument` where parsed values will be placed :throws: `ArgumentError` in any of the following conditions: * `name` or `opts` are already defined for this parser * `numArgs` > 1 * `flagInversion` is true and `numArgs` > 0 * `flagInversion` is false and `defaultValue` is true and flag is required and `numArgs` < 1 (in this case the flag is meaningless because it will always be true) * values in `opts` do not begin with a dash ``-`` .. method:: proc ref addFlag(name: string, opts: [?optsD] = _processNameToOpts(name), required = false, defaultValue: ?t = none, flagInversion = false, numArgs: range, help = "", visible = true, valueName: ?v = none): shared Argument throws An overload of ``addFlag`` described above, which accepts a range for `numArgs`. If a range of ``0..1`` is used, then either ``--flag true`` or ``--flag`` is acceptable from the command line. For example, defining a flag like this: .. code-block:: chapel var debugArg = parser.addFlag(name="debug", numArgs=0..1, defaultValue=false); we would expect command line arguments like either of these: .. code-block:: shell $ programName --debug $ programName --debug=true :arg name: a friendly name to give this flag, or a pattern to use to indicate this flag from the command line. If providing a pattern, use a leading single dash ``-`` or double dash ``--``. :arg opts: an array of string values that can be used to indicate this flag. Defaults to a long version of the `name` field with leading double dashes ``--``. :arg required: a bool to set this flag as a required command line argument. If set to `true`, an ArgumentError will be thrown if the user fails to enter the flag on the command line. Defaults to `false`. :arg defaultValue: a value to assign the argument when a flag is not required, and a is not entered on the command line. Defaults to `none`. :arg flagInversion: a bool to indicate if the parser should automatically create a `--no-` version of this flag to mean `false` when entered from the command line. i.e. (--[no-]build) :arg numArgs: the range of values expected to follow the flag on the command line. when 0..1, then ``--flag`` or ``--flag=true`` are accepted :arg help: a message to display for this flag when help is requested :arg visible: determines if this flag should be displayed in the help and usage messages. Defaults to `true`. :arg valueName: an alternative display name for the value in the help and usage messages when a flag accepts a value. Defaults to the uppercase representation of the `name` field. :returns: a shared `Argument` where parsed values will be placed :throws: `ArgumentError` in any of the following conditions: * `name` or `opts` are already defined for this parser * `numArgs` high-bound > 1 * `flagInversion` is true and `numArgs` > 0 * `flagInversion` is false and `defaultValue` is true and flag is required and `numArgs` < 1 (in this case the flag is meaningless because it will always be true) * `numArgs` does not have a lower-bound or lower-bound < 0 * values in `opts` do not begin with a dash ``-`` .. method:: proc ref addSubCommand(cmd: string, help = "", visible = true): shared Argument throws Add a subcommand to the parser. A subcommand is typically indicated with an action word, like `commit` in `git commit`. The subcommand name and all values after the subcommand are collected in the returned shared `Argument` object. For example, a defining a subcommand like this: .. code-block:: chapel var subCmdRun = parser.addSubCommand("run"); we would expect command line arguments like this: .. code-block:: shell $ programName run :arg cmd: a keyword that is recognized as indicating the subcommand from the command line. For example, `commit` in `git commit`. :arg help: a message to display for this subcommand when help is requested :arg visible: determines if this subcommand should be displayed in the help and usage messages. Defaults to `true`. :returns: a shared `Argument` where parsed values will be placed :throws: `ArgumentError` if `cmd` is already defined for this parser .. method:: proc ref addPassThrough(delimiter = "--"): shared Argument throws Add a delimiter to indicate all following values should not be parsed, but collected for later use by the developer. Convention dictates this is a double-dash ``--``, but the developer may choose to use something else. For example, defining a passthrough delimiter like this: .. code-block:: chapel var passedArgs = parser.addPassThrough(); we would expect command line arguments like this: .. code-block:: shell $ programName -- --preserved-flags --options etc :arg delimiter: the pattern to use as the passthrough indicator :returns: a shared `Argument` where collected values will be placed for use by the developer :throws: `ArgumentError` if `delimiter` is already defined for this parser .. method:: proc ref parseArgs(arguments: [?argsD] string) throws Parses an array of arguments as collected from the command line Example usage: .. code-block:: chapel proc main(args:[]string) throws { // after parser and arguments defined parser.parseArgs(args); } :arg arguments: The array of values passed from the command line to `main(args:[]string)` :throws: `ArgumentError` if argumentParser is initialized with `exitOnError=false`, and invalid or undefined command line arguments are found in `arguments`. .. method:: proc helpFlagPresent(): (bool, string) Check if the parser identified a help flag from the command line :returns: a tuple with the first component being a boolean indicating if a help flag was found and the second element being the flag found. Second element will be the empty string if no help flag was found. .. class:: Argument Stores the result of argument parsing. .. method:: proc value(): string Return the single value collected from the command line, if any. If no value was collected, the program will halt as result of calling ``list.first`` on an empty list. .. warning:: This can only be called safely if you are sure a value was collected, either because the argument was required or there was a default value set. Calling `value()` when no argument was collected will cause the program to halt. To be safe, check the return of `hasValue()` before calling `value()`. Example usage: .. code-block:: chapel var argVal:string; if myArg.hasValue() then argVal = myArg.value(); :returns: The string value for this argument as parsed from the command line .. itermethod:: iter values(): string Return an iterator over the values collected from the command line, if any. Typically collect these into a new list or var them into an array. Example usage: .. code-block:: chapel // to get an array of strings var argValues = myArg.values(); // create a list of strings var argList = new list(myArg.values()); :returns: An iterator over the parsed values .. method:: proc hasValue(): bool Check to see if a value was collected from the command line :returns: * `true` -- when at least one value was parsed * `false` -- when the argument wasn't provided and no default was defined .. method:: proc valueAsBool(): bool throws Interpret the value collected from the command line as a bool :returns: * `true` -- for true, 1, yes, y * `false` -- for false, 0, no, n :throws: `ArgumentError` if value cannot be interpreted as a bool .. class:: HelpHandler The HelpHandler class is meant to be inheritable so a user can implement their own behavior when the help flag is recognized by the parser. Typically, there is no need to make a custom version of HelpHandler, as a default is supplied. .. method:: proc printHelp() Prints the help message by default. Inherit this class and override this method to customize the operations.