diff options
| author | Doug Hellmann <doug@doughellmann.com> | 2017-06-13 15:55:33 -0400 |
|---|---|---|
| committer | Andreas Jaeger <aj@suse.com> | 2017-06-23 11:54:32 +0200 |
| commit | 9599ffe65d9dcd4b3aa780d346eccd1e760890bf (patch) | |
| tree | 9281e521e50b8bed66eca087bc11fa03adf2aed3 /doc/source/contributor/command-options.rst | |
| parent | 19c8cabeca1ea3c83da734ab5269318b27eb5634 (diff) | |
| download | python-openstackclient-9599ffe65d9dcd4b3aa780d346eccd1e760890bf.tar.gz | |
reorganize existing documentation according to the new standard layout
Move existing content around based on the doc-migration specification.
Replace :doc: markup with :ref: to have sphinx keep track of where the
files move and generate valid hyperlinks.
Add a few toctrees and index pages for the new directories.
Depends-On: Ia750cb049c0f53a234ea70ce1f2bbbb7a2aa9454
Change-Id: I253ee8f89d3ec40e39310c18bb87ed1d3d5de330
Signed-off-by: Doug Hellmann <doug@doughellmann.com>
Diffstat (limited to 'doc/source/contributor/command-options.rst')
| -rw-r--r-- | doc/source/contributor/command-options.rst | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/doc/source/contributor/command-options.rst b/doc/source/contributor/command-options.rst new file mode 100644 index 00000000..06623445 --- /dev/null +++ b/doc/source/contributor/command-options.rst @@ -0,0 +1,312 @@ +=============== +Command Options +=============== + +OpenStackClient commands all have a set of zero or more options unique to +the command, however there are of course ways in which these options are +common and consistent across all of the commands that include them. + +These are the set of guidelines for OSC developers that help keep the +interface and commands consistent. + +In some cases (like the boolean variables below) we use the same pattern +for defining and using options in all situations. The alternative of only +using it when necessary leads to errors when copy-n-paste is used for a +new command without understanding why or why not that instance is correct. + +The :ref:`hig` describes the guildelines for option names and usage. +In short: + +* All option names shall be GNU-style long names (two leading dashes). +* Some global options may have short names, generally limited to those defined + in support libraries such as ``cliff``. + +General Command Options +======================= + +Boolean Options +--------------- + +Boolean options for any command that sets a resource state, such as 'enabled' +or 'public', shall always have both positive and negative options defined. +The names of those options shall either be a naturally occurring pair of +words (in English) or a positive option and a negative option with `no-` +prepended (such as in the traditional GNU option usage) like `--share` and +`--no-share`. + +In order to handle those APIs that behave differently when a field is set to +`None` and when the field is not present in a passed argument list or dict, +each of the boolean options shall set its own variable to `True` as part of +a mutually exclusive group, rather than the more common configuration of +setting a single destination variable `True` or `False` directly. This allows +us to detect the situation when neither option is present (both variables will +be `False`) and act accordingly for those APIs where this matters. + +This also requires that each of the boolean values be tested in the +`take_action()` method to correctly set (or not) the underlying API field +values. + +.. option:: --enable + + Enable <resource> (default) + +.. option:: --disable + + Disable <resource> + +Implementation +~~~~~~~~~~~~~~ + +The parser declaration should look like this: + +.. code-block:: python + + enable_group = parser.add_mutually_exclusive_group() + enable_group.add_argument( + '--enable', + action='store_true', + help=_('Enable <resource> (default)'), + ) + enable_group.add_argument( + '--disable', + action='store_true', + help=_('Disable <resource>'), + ) + +An example handler in `take_action()`: + +.. code-block:: python + + # This leaves 'enabled' undefined if neither option is present + if parsed_args.enable: + kwargs['enabled'] = True + if parsed_args.disable: + kwargs['enabled'] = False + +Options with Choices +-------------------- + +Some options have a specific set of values (or choices) that are valid. +These choices may be validated by the CLI. If the underlying API is stable +and the list of choices are unlikely to change then the CLI may validate +the choices. Otherwise, the CLI must defer validation of the choices to +the API. If the option has a default choice then it must be documented. + +Having the CLI validate choices will be faster and may provide a better +error message for the user if an invalid choice is specified +(for example: ``argument --test: invalid choice: 'choice4' (choose from 'choice1', 'choice2', 'choice3')``). +The trade-off is that CLI changes are required in order to take advantage +of new choices. + +Implementation +~~~~~~~~~~~~~~ + +An example parser declaration: + +.. code-block:: python + + choice_option.add_argument( + '--test', + metavar='<test>', + choices=['choice1', 'choice2', 'choice3'], + help=_('Test type (choice1, choice2 or choice3)'), + ) + +Options with Multiple Values +---------------------------- + +Some options can be repeated to build a collection of values for a property. +Adding a value to the collection must be provided via the ``set`` action. +Removing a value from the collection must be provided via an ``unset`` action. +As a convenience, removing all values from the collection may be provided via a +``--no`` option on the ``set`` action and a ``--all`` option on ``unset`` +action. If both ``--no`` option and option are specified, the values specified +on the command would overwrite the collection property instead of appending on +the ``set`` action. The ``--all`` option must be part of a mutually exclusive +group with the related property option on the ``unset`` action, overwrite case +don't exist in ``unset`` action. + +An example behavior for ``set`` action: + +Append: + +.. code-block:: bash + + object set --example-property xxx + +Overwrite: + +.. code-block:: bash + + object set --no-example-property --example-property xxx + +The example below assumes a property that contains a list of unique values. +However, this example can also be applied to other collections using the +appropriate parser action and action implementation (e.g. a dict of key/value +pairs). Implementations will vary depending on how the REST API handles +adding/removing values to/from the collection and whether or not duplicate +values are allowed. + +Implementation +~~~~~~~~~~~~~~ + +An example parser declaration for `set` action: + +.. code-block:: python + + parser.add_argument( + '--no-example-property', + dest='no_example_property', + action='store_true', + help=_('Remove all example properties for this <resource> ' + '(specify both --no-example-property and --example-property' + ' to remove the current properties before setting' + ' new properties.)'), + ) + parser.add_argument( + '--example-property', + metavar='<example-property>', + dest='example_property', + action='append', + help=_('Example property for this <resource> ' + '(repeat option to set multiple properties)'), + ) + +Please make `--no-example-property` be shown in front of `--example-property` +in the help, like above, that help make users aware of the processing order. + +An example handler in `take_action()` for `set` action: + +.. code-block:: python + + if parsed_args.no_example_property and parsed_args.example_property: + kwargs['example_property'] = parsed_args.example_property + elif parsed_args.no_example_property: + kwargs['example_property'] = [] + elif parsed_args.example_property: + kwargs['example_property'] = \ + resource_example_property + parsed_args.example_property + +An example parser declaration for `unset` action: + +.. code-block:: python + + example_property_group = parser.add_mutually_exclusive_group() + example_property_group.add_argument( + '--example-property', + metavar='<example-property>', + dest='example_property', + action='append', + help=_('Example property for this <resource> ' + '(repeat option to remove multiple properties)'), + ) + example_property_group.add_argument( + '--all-example-property', + dest='all_example_property', + action='store_true', + help=_('Remove all example properties for this <resource>'), + ) + +An example handler in `take_action()` for `unset` action: + +.. code-block:: python + + if parsed_args.example_property: + kwargs['example_property'] = \ + list(set(resource_example_property) - \ + set(parsed_args.example_property)) + if parsed_args.all_example_property: + kwargs['example_property'] = [] + +Required Options +---------------- + +Some options have no default value and the API does not allow them to be +`None`, then these options are always required when users use the command +to which these options belong. + +Required options must be validated by the CLI to avoid omissions. The CLI +validation may provide an error message for the user if a required option +is not specified. +(for example: ``error: argument --test is required``) + +.. option:: --test + + Test option (required) + +Implementation +~~~~~~~~~~~~~~ + +The parser declaration should look like this: + +.. code-block:: python + + parser.add_argument( + '--test', + metavar='<test>', + required=True, + help=_('Test option (required)'), + ) + +List Command Options +==================== + +Additional Fields +----------------- + +Most list commands only return a subset of the available fields by default. +Additional fields are available with the `--long` option. All list +commands should allow `--long` even if they return all fields by default. + +.. option:: --long + + List additional fields in output + +Implementation +~~~~~~~~~~~~~~ + +The parser declaration should look like this: + +.. code-block:: python + + parser.add_argument( + '--long', + action='store_true', + default=False, + help='List additional fields in output', + ) + +Pagination +---------- + +There are many ways to do pagination, some OpenStack APIs support it, some +don't. OpenStackClient attempts to define a single common way to specify +pagination on the command line. + +.. option:: --marker <resource> + + Anchor for paging (name or ID) + +.. option:: --limit <num-resources> + + Limit number of <resource> returned (*integer*) + +Implementation +~~~~~~~~~~~~~~ + +The parser declaration should look like this: + +.. code-block:: python + + parser.add_argument( + "--marker", + metavar="<resource>", + help="Anchor for paging (name or ID)", + ) + + parser.add_argument( + "--limit", + metavar="<num-resources>", + type=int, + help="Limit the number of <resource> returned", + ) |
