From fb7bd8a5fec0f98062fe80b0a6485472a5806ec5 Mon Sep 17 00:00:00 2001 From: kschopmeyer Date: Mon, 4 May 2020 11:40:55 -0500 Subject: [PATCH] Fixes issue # 594 Simplify output and implement TEXT ooutput group Implements a new output format group (TEXT) and modifies two commands to use this group (server interop, and server brand). This removes the table option for these commands. It also implements the text output format as an optional format for namespaces so that the namespace list appears as a comma-separated line of text. In this case the default is table and the optional choice is text. Modified the definition fo possible output formats to use a OrderedDict as the basis for defining the list of formats for each group and the corresponding default keywords. --- docs/changes.rst | 7 + docs/pywbemcli/cmdshelp.rst | 4 +- docs/pywbemcli/generaloptions.rst | 57 +++++-- pywbemtools/pywbemcli/_cmd_class.py | 7 +- pywbemtools/pywbemcli/_cmd_server.py | 37 ++--- pywbemtools/pywbemcli/_common.py | 153 ++++++++++++------- pywbemtools/pywbemcli/pywbemcli.py | 12 +- tests/unit/all_types_method_mock.py | 2 +- tests/unit/simple_mock_invokemethod.py | 2 +- tests/unit/simple_python_mock_script.py | 2 +- tests/unit/test_class_cmds.py | 6 +- tests/unit/test_general_options.py | 194 +++++++++++++++--------- tests/unit/test_instance_cmds.py | 67 +++++--- tests/unit/test_server_cmds.py | 57 ++++--- tests/unit/testmock/wbemserver_mock.py | 2 +- 15 files changed, 393 insertions(+), 216 deletions(-) diff --git a/docs/changes.rst b/docs/changes.rst index 4dfd1606..8ed0ef41 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -28,6 +28,13 @@ Released: not yet archive, and added install tests for various installation methods including this one. (see issues #590, #591). +* Enhance output formats to allow an additional format group TEXT with + a single format ``text``. This format outputs the command result as a + text string to the console and is use for simple commands like + ``server interop`` that only output one piece of data. (see issue #594) + +**Cleanup** + **Known issues:** * See `list of open issues`_. diff --git a/docs/pywbemcli/cmdshelp.rst b/docs/pywbemcli/cmdshelp.rst index c7a129c2..0330b2a7 100644 --- a/docs/pywbemcli/cmdshelp.rst +++ b/docs/pywbemcli/cmdshelp.rst @@ -106,8 +106,8 @@ Help text for ``pywbemcli``: -o, --output-format FORMAT Output format for the command result. The default and allowed output formats are command specific. The default output_format is None so that each command selects its - own default format. FORMAT is either a table format: - [table|plain|simple|grid|psql|rst|html] or CIM object format: [mof|xml|repr|txt]. + own default format. FORMAT is: table formats: [table|plain|simple|grid|psql|rst|html]; + CIM object formats: [mof|xml|repr|txt]]; TEXT formats: [text]. -l, --log COMP[=DEST[:DETAIL]],... Enable logging of the WBEM operations, defined by a list of log configuration strings diff --git a/docs/pywbemcli/generaloptions.rst b/docs/pywbemcli/generaloptions.rst index 9f235e26..f4eda0c3 100644 --- a/docs/pywbemcli/generaloptions.rst +++ b/docs/pywbemcli/generaloptions.rst @@ -185,9 +185,9 @@ Controlling output formats Pywbemcli supports multiple output formats for command results by using the :ref:`--output-format general option`. -The output formats fall into three groups (table formats, CIM object formats, -and a tree format); however, not all formats are supported or applicable for all -commands. For more details, see :ref:`Output formats`. +The output formats fall into several groups (table formats, CIM object formats, +text formats, and a tree format); however, not all formats are supported or +applicable for all commands. For more details, see :ref:`Output formats`. .. _`Other miscellaneous general options`: @@ -838,7 +838,7 @@ Pywbemcli supports multiple output formats to present command results. The outpu format can be selected with the ``--output-format``/``-o`` option. The allowed output formats are different for the various command groups and commands. -The output formats fall into three groups: +The output formats fall into several groups: * **Table formats** - The :ref:`Table formats` format the result as a table with rows and columns. Many of the result types allow table formatted @@ -858,15 +858,19 @@ The output formats fall into three groups: commands that return CIM objects support these output formats. * **ASCII tree format** - The :ref:`ASCII tree format` formats the result - as a tree, using ASCII characters to represent the tree. The only command - supporting the ASCII tree format is ``class tree``, and it supports only - that one output format. The tree format is not supported by any other - command today. + as a tree, using ASCII characters to represent the tree to show the + hierarchial relationship between CIM classes. The only command supporting the + ASCII tree format is ``class tree``, and it supports only that one output + format. The tree format is not supported by any other command today. + +* **TEXT format** - The :ref:`Text formats` is used for commands that output + small quantites of text (ex. the interop namespace name) and that could be + used as part of a command line redirection. When an unsupported output format is specified for a command response, it is -rejected with an exception. For example, the command -``class enumerate`` only supports the CIM object formats and will generate an -exception if the command ``pywbemcli -o table class enumerate`` is entered. +rejected with an exception. For example, the command ``class enumerate`` only +supports the :ref:`CIM object formats` and will generate an exception if the +command ``pywbemcli -o table class enumerate`` is entered. .. index:: single: output formats @@ -927,15 +931,15 @@ table = table|plain|simple|grid|psql|rst|html +----------+---------------+----------+----------------+--------------------------------------------+ | | get | 'mof' | table | | +----------+---------------+----------+----------------+--------------------------------------------+ -|server | brand | 'simple' | table | | +|server | brand | 'text' | text | Alternate is table format | +----------+---------------+----------+----------------+--------------------------------------------+ | |centralinsts | 'simple' | table | | +----------+---------------+----------+----------------+--------------------------------------------+ | | info | 'simple' | table | | +----------+---------------+----------+----------------+--------------------------------------------+ -| | interop | 'simple' | table | | +| | interop | 'text' | text | Alternate is table format | +----------+---------------+----------+----------------+--------------------------------------------+ -| | namespaces | 'simple' | table | | +| | namespaces | 'simple' | table | Alternate is text format | +----------+---------------+----------+----------------+--------------------------------------------+ | | profiles | 'simple' | table | | +----------+---------------+----------+----------------+--------------------------------------------+ @@ -1196,6 +1200,31 @@ This shows a very simple mock repository with 4 classes where CIM_Foo is the top level in the hierarchy, CIM_Foo_sub and CIM_Foo_sub2 are its subclasses, and CIM_Foo_sub_sub is the subclass of CIM_Foo_sub. +.. index:: pair: output formats; text formats + +.. _`Text formats`: + +Text formats +"""""""""""" + +The TEXT format group outputs the data returned from the command as text +to the console without any formatting except for formatting lists and +comma separated strings. It is useful for use with data that might be +redirected to other commands or output that is simple enough that a single +line of output is sufficient. + +.. code-block:: text + + $ pywbemcli --mock-server tests/unit/testmock/wbemserver_mock.py -o table server namespaces + Server Namespaces: + Namespace Name + ---------------- + interop + + $ pywbemcli --mock-server tests/unit/testmock/wbemserver_mock.py -o text server namespaces + interop + + .. _`Pywbemcli defined logging`: diff --git a/pywbemtools/pywbemcli/_cmd_class.py b/pywbemtools/pywbemcli/_cmd_class.py index ee190dc0..87675030 100644 --- a/pywbemtools/pywbemcli/_cmd_class.py +++ b/pywbemtools/pywbemcli/_cmd_class.py @@ -30,7 +30,7 @@ from .pywbemcli import cli from ._common import display_cim_objects, filter_namelist, \ resolve_propertylist, CMD_OPTS_TXT, GENERAL_OPTS_TXT, SUBCMD_HELP_TXT, \ - TABLE_FORMATS, format_table, process_invokemethod, \ + output_format_is_table, format_table, process_invokemethod, \ raise_pywbem_error_exception, warning_msg, validate_output_format from ._common_options import add_options, propertylist_option, \ names_only_option, include_classorigin_class_option, namespace_option, \ @@ -586,7 +586,8 @@ def get_format_group(context, options): # This accounts for the fact that the results of a summary can be # either table or simply a string output - if context.output_format and context.output_format in TABLE_FORMATS: + if context.output_format and \ + output_format_is_table(context.output_format): return ['TABLE'] # Temporary hack. We need another format group, i.e. txt or str @@ -801,7 +802,7 @@ def cmd_class_find(context, classname_glob, options): rows.extend(ns_rows) context.spinner_stop() - if context.output_format in TABLE_FORMATS: + if output_format_is_table(context.output_format): headers = ['Namespace', 'Classname'] click.echo( format_table(rows, headers, diff --git a/pywbemtools/pywbemcli/_cmd_server.py b/pywbemtools/pywbemcli/_cmd_server.py index cb15a348..934b33ec 100644 --- a/pywbemtools/pywbemcli/_cmd_server.py +++ b/pywbemtools/pywbemcli/_cmd_server.py @@ -30,7 +30,8 @@ from .pywbemcli import cli from ._common import format_table, raise_pywbem_error_exception, \ - validate_output_format, CMD_OPTS_TXT, GENERAL_OPTS_TXT, SUBCMD_HELP_TXT + validate_output_format, display_text, output_format_is_table, \ + CMD_OPTS_TXT, GENERAL_OPTS_TXT, SUBCMD_HELP_TXT, DEFAULT_TABLE_FORMAT from ._common_options import add_options, help_option from ._click_extensions import PywbemcliGroup, PywbemcliCommand @@ -226,19 +227,23 @@ def cmd_server_namespaces(context, options): """ Display namespaces in the current WBEM server """ - output_format = validate_output_format(context.output_format, 'TABLE') + output_format = validate_output_format( + context.output_format, + ['TABLE', 'TEXT'], default_format=DEFAULT_TABLE_FORMAT) try: namespaces = context.wbem_server.namespaces namespaces.sort() context.spinner_stop() + if output_format_is_table(output_format): + # create list for each row + rows = [[ns] for ns in namespaces] - # create list for each row - rows = [[ns] for ns in namespaces] - - click.echo(format_table(rows, ['Namespace Name'], - title='Server Namespaces:', - table_format=output_format)) + click.echo(format_table(rows, ['Namespace Name'], + title='Server Namespaces:', + table_format=output_format)) + else: + display_text(", ".join(namespaces)) except Error as er: raise click.ClickException('{}: {}'.format(er.__class__.__name__, er)) @@ -248,17 +253,15 @@ def cmd_server_interop(context): """ Display interop namespace in the current WBEM server """ - output_format = validate_output_format(context.output_format, 'TABLE') + + output_format = validate_output_format(context.output_format, 'TEXT') try: interop_ns = context.wbem_server.interop_ns context.spinner_stop() - rows = [[interop_ns]] + display_text(interop_ns, output_format) - click.echo(format_table(rows, ['Namespace Name'], - title='Server Interop Namespace:', - table_format=output_format)) except Error as er: raise_pywbem_error_exception(er) @@ -267,16 +270,14 @@ def cmd_server_brand(context): """ Display product and version info of the current WBEM server """ - output_format = validate_output_format(context.output_format, 'TABLE') + output_format = validate_output_format(context.output_format, 'TEXT') try: brand = context.wbem_server.brand context.spinner_stop() - rows = [[brand]] - click.echo(format_table(rows, ['WBEM server brand'], - title='Server brand:', - table_format=output_format)) + display_text(brand, output_format) + except Error as er: raise_pywbem_error_exception(er) diff --git a/pywbemtools/pywbemcli/_common.py b/pywbemtools/pywbemcli/_common.py index 5dd54b41..a554cc15 100644 --- a/pywbemtools/pywbemcli/_common.py +++ b/pywbemtools/pywbemcli/_common.py @@ -23,6 +23,12 @@ import re from textwrap import fill from operator import itemgetter +from collections import namedtuple +try: + from collections import OrderedDict +except ImportError: + from ordereddict import OrderedDict # pylint: disable=import-error + import six import click import tabulate @@ -36,38 +42,63 @@ from ._cimvalueformatter import cimvalue_to_fmtd_string +# Definitions of the components of the help Usage line used +# by pywbemcli +GENERAL_OPTS_TXT = '[GENERAL-OPTIONS]' +CMD_OPTS_TXT = '[COMMAND-OPTIONS]' +SUBCMD_HELP_TXT = "COMMAND [ARGS] " + CMD_OPTS_TXT + +DEFAULT_MAX_CELL_WIDTH = 100 + ############################################################## # -# general option output format definitions and support for +# General option output format definitions and support for # validating output formats # ############################################################## +# Definition of the format keywords within each format group TABLE_FORMATS = ('table', 'plain', 'simple', 'grid', 'psql', 'rst', 'html') -CIM_OBJECT_OUTPUT_FORMATS = ('mof', 'xml', 'repr', 'txt') +CIM_OBJECT_FORMATS = ('mof', 'xml', 'repr', 'txt') +TEXT_FORMATS = ('text',) -OUTPUT_FORMATS = TABLE_FORMATS + CIM_OBJECT_OUTPUT_FORMATS +# Definition of the default format for each format group +DEFAULT_CIM_FORMAT = CIM_OBJECT_FORMATS[0] +DEFAULT_TABLE_FORMAT = TABLE_FORMATS[2] +DEFAULT_TEXT_FORMAT = TEXT_FORMATS[0] -DEFAULT_CIM_OUTPUT_FORMAT = 'mof' -DEFAULT_TABLE_OUTPUT_FORMAT = 'simple' -FORMAT_GROUPS = ('CIM', 'TABLE') +# Dictionary that relates group names to list of formats keywords for that +# group and the default format for that group. The order of the dictionary +# entry determines the priority of selecting formats. +GROUPVALUES = namedtuple('GROUPVALUES', 'keywords default') +OUTPUT_FORMAT_GROUPS = OrderedDict( + [('CIM', GROUPVALUES(CIM_OBJECT_FORMATS, DEFAULT_CIM_FORMAT)), + ('TABLE', GROUPVALUES(TABLE_FORMATS, DEFAULT_TABLE_FORMAT)), + ('TEXT', GROUPVALUES(TEXT_FORMATS, DEFAULT_TEXT_FORMAT))]) -# Definitions of the components of the help Usage line used -# by pywbemcli -GENERAL_OPTS_TXT = '[GENERAL-OPTIONS]' -CMD_OPTS_TXT = '[COMMAND-OPTIONS]' -SUBCMD_HELP_TXT = "COMMAND [ARGS] " + CMD_OPTS_TXT - -DEFAULT_MAX_CELL_WIDTH = 100 +# All of the format strings +OUTPUT_FORMATS = tuple(item for fmts in OUTPUT_FORMAT_GROUPS.values() + for item in fmts.keywords) def output_format_is_table(output_format): - """ Return True if output format is a table form""" + """ + Return True if output format is a table form. + + Parameters: + + output_format (:term:`string`): + String containing the output_format keyvalue. + + Returns: + True: if `output_format` is one of the Table format keyword choises + False: if `output_format` is not a Table format. + """ return output_format in TABLE_FORMATS def validate_output_format(output_format, valid_format_groups, - default_format=None,): + default_format=None): """ Tests for valid format groups and provides a default format if the context.output_format is None. @@ -75,70 +106,74 @@ def validate_output_format(output_format, valid_format_groups, Parameters: output_format (:term:`string` or None): - The output format string provided by input (i.e. ContextObj) or - None if there is no defined format for this command execution. + The output format string to be validated (normally provided by input + (i.e. ContextObj)) or None if there is no defined format for this + command execution. valid_format_groups (list of :term:`string` or :term:`string`): - One or more strings in a list where the allowed strings are: - 'CIM', 'TABLE'. An empty list implies any output group if valid. - A single string may be used to designate a single group + One or more strings in a list where the allowed strings are: 'TABLE', + 'CIM', or 'TEXT'. An empty list implies any output group if valid. A + single string may be used to designate a single group default_format (:term:`string` or None): One of the valid format definitions or None. The format must be in the - OUTPUT_FORMAT list. If None, the default format for the first group is - returned + OUTPUT_FORMATS list. If None, the default format for the first group in + `valid_format_groups` is returned. This format keyword is returned if + `output_format` is None. Returns: - :term:`string` containing output format to be used. + :term:`string` containing output format keyword to be used. Raises: click.ClickException if format invalid for command """ + # These are asserts because they are coding errors in the input parameters # for this function if isinstance(valid_format_groups, six.string_types): valid_format_groups = [valid_format_groups] - assert all(element in FORMAT_GROUPS for element in valid_format_groups) + + # Code error if this assert fails + assert all(element in OUTPUT_FORMAT_GROUPS for element in + valid_format_groups) + if default_format: assert default_format in OUTPUT_FORMATS - # If valid = 1 assure that default in that group. - # confirm default matches group. - + # Confirm default matches group. # CIM object type has priority over Table if output_format: - # Do invalid message here but really should be assert??? - if 'CIM' in valid_format_groups: - if output_format in CIM_OBJECT_OUTPUT_FORMATS: - return output_format - if 'TABLE' in valid_format_groups: - if output_format in TABLE_FORMATS: - return output_format + # Do invalid message here but really should be assert because this + # is a error in the data defined for the validate call. + for group, value in OUTPUT_FORMAT_GROUPS.items(): + if group in valid_format_groups: + if output_format in value.keywords: + return output_format if not valid_format_groups: return output_format - else: + + else: # output_format is None if default_format: return default_format if valid_format_groups: - if valid_format_groups[0] == 'CIM': - return DEFAULT_CIM_OUTPUT_FORMAT - if valid_format_groups[0] == 'TABLE': - return DEFAULT_TABLE_OUTPUT_FORMAT - return DEFAULT_CIM_OUTPUT_FORMAT - return DEFAULT_CIM_OUTPUT_FORMAT + for group, value in OUTPUT_FORMAT_GROUPS.items(): + if valid_format_groups[0] == group: + return value.default + return OUTPUT_FORMAT_GROUPS['CIM'].default + return OUTPUT_FORMAT_GROUPS['CIM'].default valid_formats = "" - err_msg = "not allowed for this command" + for name, value in OUTPUT_FORMAT_GROUPS.items(): + fmt_list = value.keywords + if name in valid_format_groups: + if valid_formats: + valid_formats += "; " + valid_formats += '{0} formats: "({1})"'.format( + name, '", "'.join(fmt_list)) - valid_formats = "" - if 'TABLE' in valid_format_groups: - valid_formats += 'TABLE formats ({})'.format(','.join(TABLE_FORMATS)) - if 'CIM' in valid_format_groups: - valid_formats += 'CIM Object formats ({})'.format( - ','.join(CIM_OBJECT_OUTPUT_FORMATS)) - - raise click.ClickException('Output format "{}" {}. Only {} allowed.'. - format(output_format, err_msg, valid_formats)) + raise click.ClickException('Output format "{}" not allowed for this ' + 'command. Only {} allowed.'. + format(output_format, valid_formats)) ###################################################################### @@ -416,7 +451,7 @@ def filter_namelist(pattern, name_list, ignore_case=True): raise click.ClickException('Regex compile error. Regex={}. Er: {}: {}' .format(regex, ex.__class__.__name__, ex)) - new_list = [n for n in name_list for m in[compiled_regex.match(n)] if m] + new_list = [n for n in name_list for m in [compiled_regex.match(n)] if m] return new_list @@ -1027,7 +1062,7 @@ def display_cim_objects(context, cim_objects, output_format, summary=False, if isinstance(cim_objects, (list, tuple)): # Table format output is processed as a group - if output_format in TABLE_FORMATS: + if output_format_is_table(output_format): _print_objects_as_table(context, cim_objects, output_format) else: # Call to display each object @@ -1039,7 +1074,7 @@ def display_cim_objects(context, cim_objects, output_format, summary=False, # Display a single item. object_ = cim_objects # This allows passing single objects to the table formatter (i.e. not lists) - if output_format in TABLE_FORMATS: + if output_format_is_table(output_format): _print_objects_as_table(context, [object_], output_format) elif output_format == 'mof': try: @@ -1149,6 +1184,14 @@ def get_wbemurikeys(obj): return wbem_uri_keys +def display_text(text, output_format=None): # pylint: disable=unused-argument + """ + Display the text output format. Currently this simply outputs to + click.echo + """ + click.echo(text) + + class NoCaseList(object): """ This class simplifies working with lists of strings that are to be tested @@ -1604,7 +1647,7 @@ def format_table(rows, headers, title=None, table_format='simple', table_format = 'table' if table_format == 'table': table_format = 'psql' - if table_format not in TABLE_FORMATS: + if not output_format_is_table(table_format): raise click.ClickException('Invalid table format {}.' .format(table_format)) diff --git a/pywbemtools/pywbemcli/pywbemcli.py b/pywbemtools/pywbemcli/pywbemcli.py index b4d2a71a..c113ebc6 100644 --- a/pywbemtools/pywbemcli/pywbemcli.py +++ b/pywbemtools/pywbemcli/pywbemcli.py @@ -35,8 +35,7 @@ DEFAULT_LOG_DETAIL_LEVEL from ._context_obj import ContextObj, display_click_context -from ._common import GENERAL_OPTS_TXT, SUBCMD_HELP_TXT, TABLE_FORMATS, \ - CIM_OBJECT_OUTPUT_FORMATS +from ._common import GENERAL_OPTS_TXT, SUBCMD_HELP_TXT, OUTPUT_FORMAT_GROUPS from ._common_options import add_options, help_option from ._pywbem_server import PywbemServer from .config import DEFAULT_NAMESPACE, \ @@ -215,10 +214,11 @@ 'specific. ' 'The default output_format is None so that each command ' 'selects its own default format. ' - 'FORMAT is either a table format: [{tb}] or CIM object ' - 'format: [{ob}].'. - format(tb='|'.join(TABLE_FORMATS), - ob='|'.join(CIM_OBJECT_OUTPUT_FORMATS))) + 'FORMAT is: table formats: [{tb}]; CIM object ' + 'formats: [{ob}]]; TEXT formats: [{tx}].'. + format(tb='|'.join(OUTPUT_FORMAT_GROUPS['TABLE'][0]), + ob='|'.join(OUTPUT_FORMAT_GROUPS['CIM'][0]), + tx='|'.join(OUTPUT_FORMAT_GROUPS['TEXT'][0]))) @click.option('-l', '--log', type=str, metavar='COMP[=DEST[:DETAIL]],...', # defaulted in code envvar=PywbemServer.log_envvar, diff --git a/tests/unit/all_types_method_mock.py b/tests/unit/all_types_method_mock.py index a8a2f87d..888c4c82 100644 --- a/tests/unit/all_types_method_mock.py +++ b/tests/unit/all_types_method_mock.py @@ -6,7 +6,7 @@ # test that GLOBALS exist assert "CONN" in globals() assert 'SERVER' in globals() -assert 'VERBOSE'in globals() +assert 'VERBOSE' in globals() def alltypes_callback(conn, object_name, methodname, **params): diff --git a/tests/unit/simple_mock_invokemethod.py b/tests/unit/simple_mock_invokemethod.py index 61864800..efc0dfa7 100644 --- a/tests/unit/simple_mock_invokemethod.py +++ b/tests/unit/simple_mock_invokemethod.py @@ -6,7 +6,7 @@ # test that GLOBALS exist assert "CONN" in globals() assert 'SERVER' in globals() -assert 'VERBOSE'in globals() +assert 'VERBOSE' in globals() def fuzzy_callback(conn, object_name, methodname, **params): diff --git a/tests/unit/simple_python_mock_script.py b/tests/unit/simple_python_mock_script.py index 819ae263..b386c3bf 100644 --- a/tests/unit/simple_python_mock_script.py +++ b/tests/unit/simple_python_mock_script.py @@ -11,7 +11,7 @@ # test that GLOBALS exist assert "CONN" in globals() assert 'SERVER' in globals() -assert 'VERBOSE'in globals() +assert 'VERBOSE' in globals() def build_classes(): diff --git a/tests/unit/test_class_cmds.py b/tests/unit/test_class_cmds.py index 6d3e1604..25e70a6b 100644 --- a/tests/unit/test_class_cmds.py +++ b/tests/unit/test_class_cmds.py @@ -681,7 +681,7 @@ class TST_MemberOfFamilyCollection { ['Verify class command enumerate table output fails).', {'args': ['enumerate'], 'general': ['--output-format', 'table']}, - {'stderr': ['CIM Object formats ', 'not allowed'], + {'stderr': ['Output format "table"', 'not allowed', 'Only CIM formats:'], 'rc': 1, 'test': 'innows'}, SIMPLE_MOCK_FILE, OK], @@ -915,7 +915,7 @@ class TST_MemberOfFamilyCollection { ['Verify class command enumerate table output fails).', {'args': ['get', 'CIM_Foo'], 'general': ['--output-format', 'table']}, - {'stderr': ['CIM Object formats ', 'not allowed'], + {'stderr': ['Output format "table" ', 'not allowed', 'Only CIM formats:'], 'rc': 1, 'test': 'innows'}, SIMPLE_MOCK_FILE, OK], @@ -1398,7 +1398,7 @@ class TST_MemberOfFamilyCollection { ['Verify class command refereces table output fails).', {'args': ['associators', 'TST_Person'], 'general': ['--output-format', 'table']}, - {'stderr': ['CIM Object formats ', 'not allowed'], + {'stderr': ['Output format "table" ', 'not allowed', 'Only CIM formats:'], 'rc': 1, 'test': 'innows'}, SIMPLE_MOCK_FILE, OK], diff --git a/tests/unit/test_general_options.py b/tests/unit/test_general_options.py index a465f45f..14a5e8df 100644 --- a/tests/unit/test_general_options.py +++ b/tests/unit/test_general_options.py @@ -41,8 +41,8 @@ # pylint: disable=line-too-long GENERAL_HELP = """Usage: pywbemcli [GENERAL-OPTIONS] COMMAND [ARGS] [COMMAND-OPTIONS] - Pywbemcli is a command line WBEM client that uses the DMTF CIM-XML protocol to communicate with WBEM servers. - Pywbemcli can: + Pywbemcli is a command line WBEM client that uses the DMTF CIM-XML protocol + to communicate with WBEM servers. Pywbemcli can: * Manage the information in WBEM servers CIM objects using the operations defined in the DMTF specification. It can manage CIM @@ -58,92 +58,146 @@ * Maintain a persistent list of named connections to WBEM servers and execute operations on them by name. - Pywbemcli implements command groups and commands to execute the CIM-XML operations defined by the DMTF CIM - Operations Over HTTP specification (DSP0200). + Pywbemcli implements command groups and commands to execute the CIM-XML + operations defined by the DMTF CIM Operations Over HTTP specification + (DSP0200). - The general options shown below can also be specified on any of the commands, positioned right after the 'pywbemcli' - command name. + The general options shown below can also be specified on any of the + commands, positioned right after the 'pywbemcli' command name. - The width of help texts of this command can be set with the PYWBEMCLI_TERMWIDTH environment variable. + The width of help texts of this command can be set with the + PYWBEMCLI_TERMWIDTH environment variable. For more detailed documentation, see: https://pywbemtools.readthedocs.io/en/stable/ General Options: - -n, --name NAME Use the WBEM server defined by the WBEM connection definition NAME. This option is - mutually exclusive with the --server and --mock-server options, since each defines a - WBEM server. Default: EnvVar PYWBEMCLI_NAME, or none. - - -m, --mock-server FILE Use a mock WBEM server that is automatically created in pywbemcli and populated with - CIM objects that are defined in the specified MOF file or Python script file. See the - pywbemcli documentation for more information. This option may be specified multiple - times, and is mutually exclusive with the --server and --name options, since each - defines a WBEM server. Default: EnvVar PYWBEMCLI_MOCK_SERVER, or none. - - -s, --server URL Use the WBEM server at the specified URL with format: [SCHEME://]HOST[:PORT]. SCHEME - must be "https" (default) or "http". HOST is a short or long hostname or literal - IPV4/v6 address. PORT defaults to 5989 for https and 5988 for http. This option is - mutually exclusive with the --mock-server and --name options, since each defines a - WBEM server. Default: EnvVar PYWBEMCLI_SERVER, or none. - - -u, --user TEXT User name for the WBEM server. Default: EnvVar PYWBEMCLI_USER, or none. - -p, --password TEXT Password for the WBEM server. Default: EnvVar PYWBEMCLI_PASSWORD, or prompted for if - --user specified. - - --verify / --no-verify If --verify, client verifies the X.509 server certificate presented by the WBEM server - during TLS/SSL handshake. If --no-verify client bypasses verification. Default: EnvVar + -n, --name NAME Use the WBEM server defined by the WBEM + connection definition NAME. This option is + mutually exclusive with the --server and + --mock-server options, since each defines a + WBEM server. Default: EnvVar PYWBEMCLI_NAME, + or none. + + -m, --mock-server FILE Use a mock WBEM server that is automatically + created in pywbemcli and populated with CIM + objects that are defined in the specified MOF + file or Python script file. See the pywbemcli + documentation for more information. This + option may be specified multiple times, and is + mutually exclusive with the --server and + --name options, since each defines a WBEM + server. Default: EnvVar PYWBEMCLI_MOCK_SERVER, + or none. + + -s, --server URL Use the WBEM server at the specified URL with + format: [SCHEME://]HOST[:PORT]. SCHEME must be + "https" (default) or "http". HOST is a short + or long hostname or literal IPV4/v6 address. + PORT defaults to 5989 for https and 5988 for + http. This option is mutually exclusive with + the --mock-server and --name options, since + each defines a WBEM server. Default: EnvVar + PYWBEMCLI_SERVER, or none. + + -u, --user TEXT User name for the WBEM server. Default: EnvVar + PYWBEMCLI_USER, or none. + + -p, --password TEXT Password for the WBEM server. Default: EnvVar + PYWBEMCLI_PASSWORD, or prompted for if --user + specified. + + --verify / --no-verify If --verify, client verifies the X.509 server + certificate presented by the WBEM server + during TLS/SSL handshake. If --no-verify + client bypasses verification. Default: EnvVar PYWBEMCLI_VERIFY, or "--verify". - --ca-certs CACERTS Certificates to be used for validating the certificate presented by the WBEM server - during TLS/SSL handshake: FILE: Use the certs in the specified PEM file; DIR: Use the - certs in the PEM files in the specified directory; "certifi" (pywbem 1.0 or later): - Use the certs provided by the certifi Python package; Default: EnvVar - PYWBEMCLI_CA_CERTS, or "certifi" (pywbem 1.0 or later), or the certs in the PEM files - in the first existing directory from from a list of system directories (pywbem before - 1.0). - - -c, --certfile FILE Path name of a PEM file containing a X.509 client certificate that is used to enable - TLS/SSL 2-way authentication by presenting the certificate to the WBEM server during - TLS/SSL handshake. Default: EnvVar PYWBEMCLI_CERTFILE, or none. - - -k, --keyfile FILE Path name of a PEM file containing a X.509 private key that belongs to the certificate - in the --certfile file. Not required if the private key is part of the --certfile - file. Default: EnvVar PYWBEMCLI_KEYFILE, or none. - - -t, --timeout INT Client-side timeout in seconds for operations with the WBEM server. Default: EnvVar + --ca-certs CACERTS Certificates to be used for validating the + certificate presented by the WBEM server + during TLS/SSL handshake: FILE: Use the certs + in the specified PEM file; DIR: Use the certs + in the PEM files in the specified directory; + "certifi" (pywbem 1.0 or later): Use the certs + provided by the certifi Python package; + Default: EnvVar PYWBEMCLI_CA_CERTS, or + "certifi" (pywbem 1.0 or later), or the certs + in the PEM files in the first existing + directory from from a list of system + directories (pywbem before 1.0). + + -c, --certfile FILE Path name of a PEM file containing a X.509 + client certificate that is used to enable + TLS/SSL 2-way authentication by presenting the + certificate to the WBEM server during TLS/SSL + handshake. Default: EnvVar PYWBEMCLI_CERTFILE, + or none. + + -k, --keyfile FILE Path name of a PEM file containing a X.509 + private key that belongs to the certificate in + the --certfile file. Not required if the + private key is part of the --certfile file. + Default: EnvVar PYWBEMCLI_KEYFILE, or none. + + -t, --timeout INT Client-side timeout in seconds for operations + with the WBEM server. Default: EnvVar PYWBEMCLI_TIMEOUT, or 30. - -U, --use-pull [yes|no|either] Determines whether pull operations are used for operations with the WBEM server that - return lists of instances, as follows: "yes" uses pull operations and fails if not - supported by the server; "no" uses traditional operations; "either" (default) uses - pull operations if supported by the server, and otherwise traditional operations. - Default: EnvVar PYWBEMCLI_USE_PULL, or "either". - - --pull-max-cnt INT Maximum number of instances to be returned by the WBEM server in each open or pull - response, if pull operations are used. This is a tuning parameter that does not affect - the external behavior of the commands. Default: EnvVar PYWBEMCLI_PULL_MAX_CNT, or 1000 + -U, --use-pull [yes|no|either] Determines whether pull operations are used + for operations with the WBEM server that + return lists of instances, as follows: "yes" + uses pull operations and fails if not + supported by the server; "no" uses traditional + operations; "either" (default) uses pull + operations if supported by the server, and + otherwise traditional operations. Default: + EnvVar PYWBEMCLI_USE_PULL, or "either". + + --pull-max-cnt INT Maximum number of instances to be returned by + the WBEM server in each open or pull response, + if pull operations are used. This is a tuning + parameter that does not affect the external + behavior of the commands. Default: EnvVar + PYWBEMCLI_PULL_MAX_CNT, or 1000 + + -T, --timestats Show time statistics of WBEM server + operations. - -T, --timestats Show time statistics of WBEM server operations. -d, --default-namespace NAMESPACE - Default namespace, to be used when commands do not specify the --namespace command - option. Default: EnvVar PYWBEMCLI_DEFAULT_NAMESPACE, or root/cimv2. - - -o, --output-format FORMAT Output format for the command result. The default and allowed output formats are - command specific. The default output_format is None so that each command selects its - own default format. FORMAT is either a table format: - [table|plain|simple|grid|psql|rst|html] or CIM object format: [mof|xml|repr|txt]. + Default namespace, to be used when commands do + not specify the --namespace command option. + Default: EnvVar PYWBEMCLI_DEFAULT_NAMESPACE, + or root/cimv2. + + -o, --output-format FORMAT Output format for the command result. The + default and allowed output formats are command + specific. The default output_format is None so + that each command selects its own default + format. FORMAT is: table formats: + [table|plain|simple|grid|psql|rst|html]; CIM + object formats: [mof|xml|repr|txt]]; TEXT + formats: [text]. -l, --log COMP[=DEST[:DETAIL]],... - Enable logging of the WBEM operations, defined by a list of log configuration strings - with: COMP: [api|http|all]; DEST: [file|stderr], default: file; DETAIL: - [all|paths|summary], default: all. Default: EnvVar PYWBEMCLI_LOG, or all. + Enable logging of the WBEM operations, defined + by a list of log configuration strings with: + COMP: [api|http|all]; DEST: [file|stderr], + default: file; DETAIL: [all|paths|summary], + default: all. Default: EnvVar PYWBEMCLI_LOG, + or all. + + -v, --verbose / --no-verbose Display extra information about the + processing. + + --pdb Pause execution in the built-in pdb debugger + just before executing the command within + pywbemcli. Default: EnvVar PYWBEMCLI_PDB, or + false. - -v, --verbose / --no-verbose Display extra information about the processing. - --pdb Pause execution in the built-in pdb debugger just before executing the command within - pywbemcli. Default: EnvVar PYWBEMCLI_PDB, or false. + --version Show the version of this command and the + pywbem package. - --version Show the version of this command and the pywbem package. -h, --help Show this help message. Commands: diff --git a/tests/unit/test_instance_cmds.py b/tests/unit/test_instance_cmds.py index bdf90365..08a0ed29 100644 --- a/tests/unit/test_instance_cmds.py +++ b/tests/unit/test_instance_cmds.py @@ -971,8 +971,17 @@ 'test': 'regex'}, SIMPLE_MOCK_FILE, OK], + ['Verify instance command get with -o txt fails', + {'args': ['enumerate', 'CIM_Foo'], + 'general': ['--output-format', 'text']}, + {'stderr': ['Output format "text"', 'not allowed', 'Only CIM formats:', + 'TABLE formats:'], + 'rc': 1, + 'test': 'innows'}, + SIMPLE_MOCK_FILE, OK], + # - # exhaustive tests for INSTANCENAME parameter (using instance get command) + # Exhaustive tests for INSTANCENAME parameter (using instance get command) # including variations on --namespace and --key options. # @@ -1484,7 +1493,7 @@ [ASSOC_MOCK_FILE, MOCK_PROMPT_0_FILE], OK], # - # get command errors + # instance get command errors # ['instance command get error. no classname', ['get'], @@ -1522,6 +1531,15 @@ 'test': 'lines'}, SIMPLE_MOCK_FILE, OK], + ['Verify instance command get with -o txt fails', + {'args': ['get', 'CIM_Foo.InstanceID="CIM_Foo1"', '--lo'], + 'general': ['--output-format', 'text']}, + {'stderr': ['Output format "text"', 'not allowed', 'Only CIM formats:', + 'TABLE formats:'], + 'rc': 1, + 'test': 'innows'}, + SIMPLE_MOCK_FILE, OK], + # # instance create command # @@ -2234,6 +2252,15 @@ 'test': 'regex'}, ASSOC_MOCK_FILE, OK], + ['Verify instance command references with --output-format text', + {'args': ['references', 'CIM_Foo.InstanceID="CIM_Foo1"'], + 'general': ['--output-format', 'text']}, + {'stderr': ['Output format "text"', 'not allowed', 'Only CIM formats:', + 'TABLE formats:'], + 'rc': 1, + 'test': 'innows'}, + SIMPLE_MOCK_FILE, OK], + # TODO add more invalid references tests # @@ -2661,35 +2688,35 @@ {'stdout': SIMPLE_SHRUB_TREE, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance subcommand shrub, simple tree no namepace', ['shrub', 'TST_Person.name="Mike"', '--fullpath'], {'stdout': SIMPLE_SHRUB_TREE, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance subcommand shrub, simple tree no namepace. short path', ['shrub', 'TST_Person.name="Mike"'], {'stdout': SIMPLE_SHRUB_TREE, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance subcommand shrub, simple tree with --role option 1', ['shrub', 'TST_Person.name="Mike"', '--role', 'parent'], {'stdout': SIMPLE_SHRUB_TREE_ROLE, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance subcommand shrub, simple tree with --role option 2', ['shrub', 'TST_Person.name="Mike"', '--role', 'Parent'], {'stdout': SIMPLE_SHRUB_TREE_ROLE, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance command shrub, simple tree with --role option err', ['shrub', 'TST_Person.name="Mike"', '--role', 'parentx'], @@ -2698,21 +2725,21 @@ 'stdout': SIMPLE_SHRUB_TREE, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance command shrub, simple tree with --assoc-class option1', ['shrub', 'TST_Person.name="Mike"', '--assoc-class', 'TST_Lineage'], {'stdout': SIMPLE_SHRUB_TREE_ASSOC_CLASS, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance command shrub, simple tree with --assoc-class option2', ['shrub', 'TST_Person.name="Mike"', '--assoc-class', 'tst_lineage'], {'stdout': SIMPLE_SHRUB_TREE_ASSOC_CLASS, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance command shrub, simple tree with --assoc-class option err', ['shrub', 'TST_Person.name="Mike"', '--assoc-class', 'TST_Lineagex'], @@ -2720,28 +2747,28 @@ 'stderr': "WARNING", 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance command shrub, simple tree with --result-class option1', ['shrub', 'TST_Person.name="Mike"', '--result-class', 'TST_Person'], {'stdout': SIMPLE_SHRUB_TREE_RESULT_CLASS, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance command shrub, simple tree with --assoc-class option2', ['shrub', 'TST_Person.name="Mike"', '--result-class', 'tst_person'], {'stdout': SIMPLE_SHRUB_TREE_RESULT_CLASS, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance subcommand shrub, simple tree with --assoc-class error', ['shrub', 'TST_Person.name="Mike"', '--result-class', 'TST_Personx'], {'stdout': SIMPLE_SHRUB_TREE_RESULT_CLASS_NO_RTN, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance command shrub, simple table request w ns', {'args': ['shrub', 'root/cimv2:TST_Person.name="Mike"', @@ -2750,7 +2777,7 @@ {'stdout': SIMPLE_SHRUB_TABLE1, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance command shrub, simple tableno ns in request', {'args': ['shrub', 'root/cimv2:TST_Person.name="Mike"'], @@ -2758,21 +2785,21 @@ {'stdout': SIMPLE_SHRUB_TABLE1, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance command shrub, simple tree with namespace', ['shrub', 'TST_Person.name="Mike"', '--fullpath'], {'stdout': SIMPLE_SHRUB_TREE, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], ['Verify instance command shrub, simple tree without namespace', ['shrub', 'TST_Person.name="Mike"', '--fullpath'], {'stdout': SIMPLE_SHRUB_TREE, 'rc': 0, 'test': 'innows'}, - ASSOC_MOCK_FILE, RUN], + ASSOC_MOCK_FILE, OK], # Test with a complex (ternary) association # TODO: Fix the following failed tests. Some minor diff in table I have @@ -2793,7 +2820,7 @@ {'stdout': COMPLEX_SHRUB_TABLE_SUMMARY, 'rc': 0, 'test': 'innows'}, - COMPLEX_ASSOC_MODEL, RUN], + COMPLEX_ASSOC_MODEL, OK], ['Verify instance subcommand shrub, complex tree', {'args': ['shrub', 'TST_EP.InstanceID=1', '--fullpath'], @@ -2801,7 +2828,7 @@ {'stdout': COMPLEX_SHRUB_TREE, 'rc': 0, 'test': 'innows'}, - COMPLEX_ASSOC_MODEL, RUN], + COMPLEX_ASSOC_MODEL, OK], # TODO test results if we have keys that get hidden. This will require # a more complex model with CreationClassName, etc. in paths. diff --git a/tests/unit/test_server_cmds.py b/tests/unit/test_server_cmds.py index 433f0e31..dfc6c714 100644 --- a/tests/unit/test_server_cmds.py +++ b/tests/unit/test_server_cmds.py @@ -200,15 +200,20 @@ # # Verify the individual commands returning data # + ['Verify server command interop default output', + {'args': ['interop'], + 'general': ['-d', 'interop']}, + {'stdout': ['interop'], + 'rc': 0, + 'test': 'innows'}, + MOCK_SERVER_MODEL, OK], + ['Verify server command interop', {'args': ['interop'], - 'general': ['-d', 'interop', '-o', 'simple']}, - {'stdout': ['Server Interop Namespace:', - 'Namespace Name', - '----------------', - 'interop'], + 'general': ['-d', 'interop', '-o', 'text']}, + {'stdout': ['interop'], 'rc': 0, - 'test': 'lines'}, + 'test': 'innows'}, MOCK_SERVER_MODEL, OK], ['Verify server command namespaces', @@ -222,27 +227,37 @@ 'test': 'lines'}, MOCK_SERVER_MODEL, OK], - # TODO: Remove this test once removal of --sort option is agreed. - ['Verify server command namespaces with sort option', - {'args': ['namespaces', '-s'], - 'general': ['-d', 'interop', '-o', 'simple']}, - {'stdout': ['Server Namespaces:', - 'Namespace Name', - '----------------', - 'interop'], + ['Verify server command namespaces, text output', + {'args': ['namespaces'], + 'general': ['-d', 'interop', '-o', 'text']}, + {'stdout': ['interop'], 'rc': 0, 'test': 'lines'}, - MOCK_SERVER_MODEL, FAIL], + MOCK_SERVER_MODEL, OK], + + ['Verify server command namespaces with sort option', + {'args': ['namespaces'], + 'general': ['-d', 'interop']}, + {'stdout': ['interop'], + 'rc': 0, + 'test': 'innows'}, + MOCK_SERVER_MODEL, OK], ['Verify server command brand', {'args': ['brand'], - 'general': ['-d', 'interop', '-o', 'simple']}, - {'stdout': ['Server brand:', - 'WBEM server brand', - '-------------------', - 'OpenPegasus'], + 'general': ['-d', 'interop']}, + {'stdout': ['OpenPegasus'], 'rc': 0, - 'test': 'lines'}, + 'test': 'innows'}, + MOCK_SERVER_MODEL, OK], + + + ['Verify server command brand with --output table fails', + {'args': ['brand'], + 'general': ['-d', 'interop', '-o', 'simple']}, + {'stderr': ['Output format "simple" not allowed for this command'], + 'rc': 1, + 'test': 'innows'}, MOCK_SERVER_MODEL, OK], ['Verify server command profiles', diff --git a/tests/unit/testmock/wbemserver_mock.py b/tests/unit/testmock/wbemserver_mock.py index 0b44fc49..06c068ee 100644 --- a/tests/unit/testmock/wbemserver_mock.py +++ b/tests/unit/testmock/wbemserver_mock.py @@ -20,7 +20,7 @@ # test that GLOBALS exist. They should be provided by pywbemcli assert "CONN" in globals() assert 'SERVER' in globals() -assert 'VERBOSE'in globals() +assert 'VERBOSE' in globals() # Location of DMTF schema directory used by all tests.