summaryrefslogtreecommitdiff
path: root/doc/source/contributor/command-options.rst
diff options
context:
space:
mode:
authorDoug Hellmann <doug@doughellmann.com>2017-06-13 15:55:33 -0400
committerAndreas Jaeger <aj@suse.com>2017-06-23 11:54:32 +0200
commit9599ffe65d9dcd4b3aa780d346eccd1e760890bf (patch)
tree9281e521e50b8bed66eca087bc11fa03adf2aed3 /doc/source/contributor/command-options.rst
parent19c8cabeca1ea3c83da734ab5269318b27eb5634 (diff)
downloadpython-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.rst312
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",
+ )