From cd7cd5eba8cfbb5f1941744ff90cf45e0ebcf422 Mon Sep 17 00:00:00 2001 From: garciadeblas Date: Mon, 26 Jun 2023 17:41:46 +0200 Subject: [PATCH] Refactor -o option to simplify code The change includes the implementation of a click option in print_output module, being used in ns-list, ns-show, vim-list, vim-show, vnf-list and vnf-show commands. It also includes a quick validation that the output format is one of the allowed outputs. It also fixes jsonpath option so that the output is not embedded in a [] list structure. Change-Id: I8c33b5faf341c9a4cdd8d488671f2a81ab3b5a3a Signed-off-by: garciadeblas --- osmclient/cli_commands/ns.py | 28 ++------- osmclient/cli_commands/vim.py | 28 ++------- osmclient/cli_commands/vnf.py | 44 ++++---------- osmclient/common/print_output.py | 100 +++++++++++++++++-------------- osmclient/scripts/osm.py | 5 -- 5 files changed, 79 insertions(+), 126 deletions(-) diff --git a/osmclient/cli_commands/ns.py b/osmclient/cli_commands/ns.py index 441ae05..75054fe 100755 --- a/osmclient/cli_commands/ns.py +++ b/osmclient/cli_commands/ns.py @@ -38,15 +38,9 @@ logger = logging.getLogger("osmclient") is_flag=True, help="get more details of the NS (project, vim, deployment status, configuration status.", ) -@click.option( - "-o", - default="table", - is_eager=True, - callback=print_output.validate_command_output, - help="adapt the output as table, yaml, csv, json, jsonpath", -) +@print_output.output_option @click.pass_context -def ns_list(ctx, filter, long, o): +def ns_list(ctx, filter, long, output): """list all NS instances \b @@ -302,9 +296,7 @@ def ns_list(ctx, filter, long, o): utils.wrap_text(text=error_details, width=40), ] ) - table.align = "l" - # print(table) - print_output.print_output(o, table.field_names, table._rows) + print_output.print_output(output, table.field_names, table._rows) print('To get the history of all operations over a NS, run "osm ns-op-list NS_ID"') print( 'For more details on the current operation, run "osm ns-op-show OPERATION_ID"' @@ -319,15 +311,9 @@ def ns_list(ctx, filter, long, o): multiple=True, help="restricts the information to the fields in the filter", ) -@click.option( - "-o", - default="table", - is_eager=True, - callback=print_output.validate_command_output, - help="adapt the output as table, yaml, csv, json, jsonpath", -) +@print_output.output_option @click.pass_context -def ns_show(ctx, name, literal, filter, o): +def ns_show(ctx, name, literal, filter, output): """shows the info of a NS instance NAME: name or ID of the NS instance @@ -352,9 +338,7 @@ def ns_show(ctx, name, literal, filter, o): for k, v in list(nsr_optdata.items()): if not filter or k in filter: table.add_row([k, utils.wrap_text(json.dumps(v, indent=2), width=100)]) - table.align = "l" - print_output.print_output(o, table.field_names, table._rows) - # print(table) + print_output.print_output(output, table.field_names, table._rows) @click.command(name="ns-create", short_help="creates a new Network Service instance") diff --git a/osmclient/cli_commands/vim.py b/osmclient/cli_commands/vim.py index b2a073d..d74ea7b 100755 --- a/osmclient/cli_commands/vim.py +++ b/osmclient/cli_commands/vim.py @@ -304,15 +304,9 @@ def vim_delete(ctx, name, force, wait): is_flag=True, help="get more details of the NS (project, vim, deployment status, configuration status.", ) -@click.option( - "-o", - default="table", - is_eager=True, - callback=print_output.validate_command_output, - help="get more details of the NS (project, vim, deployment status, configuration status.", -) +@print_output.output_option @click.pass_context -def vim_list(ctx, filter, long, o): +def vim_list(ctx, filter, long, output): """list all VIM accounts""" logger.debug("") if filter: @@ -355,9 +349,7 @@ def vim_list(ctx, filter, long, o): table.add_row( [vim["name"], vim["uuid"], vim["_admin"].get("operationalState", "-")] ) - table.align = "l" - # print(table) - print_output.print_output(o, table.field_names, table._rows) + print_output.print_output(output, table.field_names, table._rows) @click.command(name="vim-show", short_help="shows the details of a VIM account") @@ -368,15 +360,9 @@ def vim_list(ctx, filter, long, o): help="restricts the information to the fields in the filter", ) @click.option("--literal", is_flag=True, help="print literally, no pretty table") -@click.option( - "-o", - default="table", - is_eager=True, - callback=print_output.validate_command_output, - help="adapt the output as table, yaml, csv, json, jsonpath", -) +@print_output.output_option @click.pass_context -def vim_show(ctx, name, filter, literal, o): +def vim_show(ctx, name, filter, literal, output): """shows the details of a VIM account NAME: name or ID of the VIM account @@ -395,6 +381,4 @@ def vim_show(ctx, name, filter, literal, o): for k, v in list(resp.items()): if not filter or k in filter: table.add_row([k, utils.wrap_text(text=json.dumps(v, indent=2), width=100)]) - table.align = "l" - # print(table) - print_output.print_output(o, table.field_names, table._rows) + print_output.print_output(output, table.field_names, table._rows) diff --git a/osmclient/cli_commands/vnf.py b/osmclient/cli_commands/vnf.py index 6c86ff7..974a421 100755 --- a/osmclient/cli_commands/vnf.py +++ b/osmclient/cli_commands/vnf.py @@ -27,7 +27,7 @@ import logging logger = logging.getLogger("osmclient") -def vnf_list(ctx, ns, filter, long, o): +def vnf_list(ctx, ns, filter, long, output): logger.debug("") if ns or filter: if ns: @@ -96,9 +96,7 @@ def vnf_list(ctx, ns, filter, long, o): vnfr["config-status"], ] ) - table.align = "l" - # print(table) - print_output.print_output(o, table.field_names, table._rows) + print_output.print_output(output, table.field_names, table._rows) @click.command(name="vnf-list", short_help="list all NF instances") @@ -112,18 +110,12 @@ def vnf_list(ctx, ns, filter, long, o): help="restricts the list to the NF instances matching the filter.", ) @click.option("--long", is_flag=True, help="get more details") -@click.option( - "-o", - default="table", - is_eager=True, - callback=print_output.validate_command_output, - help="adapt the output as table, yaml, csv, json, jsonpath", -) +@print_output.output_option @click.pass_context -def vnf_list1(ctx, ns, filter, long, o): +def vnf_list1(ctx, ns, filter, long, output): """list all NF instances""" logger.debug("") - vnf_list(ctx, ns, filter, long, o) + vnf_list(ctx, ns, filter, long, output) @click.command(name="nf-list", short_help="list all NF instances") @@ -137,15 +129,9 @@ def vnf_list1(ctx, ns, filter, long, o): help="restricts the list to the NF instances matching the filter.", ) @click.option("--long", is_flag=True, help="get more details") -@click.option( - "-o", - default="table", - # is_eager=True, - # callback=print_output.validate_command_output, - help="adapt the output as table, yaml, csv, json, jsonpath", -) +@print_output.output_option @click.pass_context -def nf_list(ctx, ns, filter, long, o): +def nf_list(ctx, ns, filter, long, output): """list all NF instances \b @@ -194,7 +180,7 @@ def nf_list(ctx, ns, filter, long, o): --filter vnfd-ref=,vdur.ip-address= """ logger.debug("") - vnf_list(ctx, ns, filter, long, o) + vnf_list(ctx, ns, filter, long, output) @click.command(name="vnf-show", short_help="shows the info of a VNF instance") @@ -206,15 +192,9 @@ def nf_list(ctx, ns, filter, long, o): help="restricts the information to the fields in the filter", ) @click.option("--kdu", default=None, help="KDU name (whose status will be shown)") -@click.option( - "-o", - default="table", - is_eager=True, - callback=print_output.validate_command_output, - help="adapt the output as table, yaml, csv, json, jsonpath", -) +@print_output.output_option @click.pass_context -def vnf_show(ctx, name, literal, filter, kdu, o): +def vnf_show(ctx, name, literal, filter, kdu, output): """shows the info of a VNF instance NAME: name or ID of the VNF instance @@ -294,6 +274,4 @@ def vnf_show(ctx, name, literal, filter, kdu, o): for k, v in list(resp.items()): if not filter or k in filter: table.add_row([k, utils.wrap_text(text=json.dumps(v, indent=2), width=100)]) - table.align = "l" - # print(table) - print_output.print_output(o, table.field_names, table._rows) + print_output.print_output(output, table.field_names, table._rows) diff --git a/osmclient/common/print_output.py b/osmclient/common/print_output.py index e5bc7f7..a9364c8 100644 --- a/osmclient/common/print_output.py +++ b/osmclient/common/print_output.py @@ -14,67 +14,79 @@ # See the License for the specific language governing permissions and # limitations under the License. ####################################################################################### +import click +import logging import json import yaml -import click from prettytable import PrettyTable from jsonpath_ng import parse +logger = logging.getLogger("osmclient") + + +def evaluate_output_format(ctx, param, value): + logger.debug("") + if value in ["table", "json", "yaml", "csv"]: + return value + elif value.startswith("jsonpath="): + return value + else: + raise click.BadParameter( + f"{value} is not one of 'table', 'json', 'yaml', 'csv', 'jsonpath'" + ) + + +output_option = click.option( + "-o", + "--output", + default="table", + is_eager=True, + callback=evaluate_output_format, + help="output format (default: table)", +) + + +literal_option = click.option( + "--literal", is_flag=True, help="print literally, no pretty table" +) + + def print_output(format, headers, rows): + logger.debug("") if format == "table": table = PrettyTable(headers) + table.align = "l" for row in rows: table.add_row(row) print(table) - elif format == "json": - data = [] - for row in rows: - data.append(dict(zip(headers, row))) - json_data = json.dumps(data) - print(json_data) elif format == "csv": table = PrettyTable(headers) for row in rows: table.add_row(row) print(table.get_csv_string()) - elif format == "yaml": + elif format == "json" or format == "yaml" or format.startswith("jsonpath="): data = [] for row in rows: - data.append(dict(zip(headers, row))) - yaml_string = yaml.safe_dump(data, sort_keys=False) - print(yaml_string) - elif format.startswith("jsonpath="): - # JSONPath expression - json_path_expression = format.partition("=")[-1] - json_path = parse(json_path_expression) - data = [] - for row in rows: - data.append(dict(zip(headers, row))) - # json_data = json.dumps(data) - # Apply JSONPath expression on the JSON object - results = [match.value for match in json_path.find(data)] - print(results) - else: - print("Valid values for -o are table, yaml, csv, json, jsonpath") - - -def validate_command_output(ctx, param, value): - allowed_commands = [ - "ns-list", - "ns-show", - "vim-list", - "vim-show", - "vnf-list", - "vnf-show", - ] # List of allowed commands - - if ctx.command.name in allowed_commands: - return value - # if param: - # print (value) - else: - raise click.BadParameter( - f'Option "{param.name}" is not allowed for this command.' - ) + item = {} + for i in range(len(row)): + item[headers[i]] = row[i] + data.append(item) + if format == "json": + print(json.dumps(data, indent=4)) + elif format == "yaml": + print( + yaml.safe_dump( + data, indent=4, default_flow_style=False, sort_keys=False + ) + ) + elif format.startswith("jsonpath="): + # JSONPath expression + json_path_expression = format.partition("=")[-1] + logger.debug(f"Jsonpath expression: {json_path_expression}") + json_path = parse(json_path_expression) + # Apply JSONPath expression on the JSON object + results = [match.value for match in json_path.find(data)] + for i in results: + print(i) diff --git a/osmclient/scripts/osm.py b/osmclient/scripts/osm.py index 0a17948..74bb84b 100755 --- a/osmclient/scripts/osm.py +++ b/osmclient/scripts/osm.py @@ -78,11 +78,6 @@ from requests import RequestException count=True, help="increase verbosity (-v INFO, -vv VERBOSE, -vvv DEBUG)", ) -@click.option( - "-o", - "--output", - help="adapt output format (table, yaml, csv, json, jsonpath)", -) @click.option("--all-projects", default=None, is_flag=True, help="include all projects") @click.option( "--public/--no-public", -- 2.25.1