From 05ab8e6c6f7757ebba71a8e7b38243b177260c65 Mon Sep 17 00:00:00 2001 From: Dave Barnow Date: Mon, 18 Jul 2022 14:03:38 -0400 Subject: [PATCH 1/3] feat: add examples from OAS to --help prompt --- linodecli/__init__.py | 10 ++++++++++ linodecli/cli.py | 2 ++ linodecli/operation.py | 6 +++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/linodecli/__init__.py b/linodecli/__init__.py index 2da84752f..bcee50e31 100755 --- a/linodecli/__init__.py +++ b/linodecli/__init__.py @@ -547,6 +547,7 @@ def main(): print(operation.summary) print() if operation.args: + examples = [] print("Arguments:") for arg in sorted(operation.args, key=lambda s: not s.required): print( @@ -558,6 +559,15 @@ def main(): arg.description, ) ) + arg_example = f' --{arg.path}="{arg.example}"' + examples.append(arg_example) + example = "".join(examples) + print() + print("Example:") + print( + f" linode-cli {parsed.command} {parsed.action} {example}", end="" + ) + elif operation.method == "get" and parsed.action == "list": filterable_attrs = [ attr for attr in operation.response_model.attrs if attr.filterable diff --git a/linodecli/cli.py b/linodecli/cli.py index eb8909197..e353da65e 100644 --- a/linodecli/cli.py +++ b/linodecli/cli.py @@ -107,6 +107,7 @@ def _parse_args(self, node, prefix=[], args=None): args[path] = { "type": info.get("type") or "string", "desc": info.get("description") or "", + "example": info.get("example") or "", "name": arg, "format": info.get("x-linode-cli-format", info.get("format", None)), } @@ -317,6 +318,7 @@ def bake(self, spec): info["desc"].split(".")[0] + ".", arg, info["format"], + info["example"], list_item=info.get("list_item"), ) diff --git a/linodecli/operation.py b/linodecli/operation.py index ea9c16bba..80a52dfaf 100644 --- a/linodecli/operation.py +++ b/linodecli/operation.py @@ -99,11 +99,14 @@ class CLIArg: are defined in a requestBody in the api spec. """ - def __init__(self, name, arg_type, description, path, arg_format, list_item=None): + def __init__( + self, name, arg_type, description, path, arg_format, example, list_item=None + ): self.name = name self.arg_type = arg_type self.arg_format = arg_format self.description = description.replace("\n", "").replace("\r", "") + self.example = example self.path = path self.arg_item_type = None # populated during baking for arrays self.required = False # this is set during baking @@ -178,6 +181,7 @@ def parse_args(self, args): parser = argparse.ArgumentParser( prog="linode-cli {} {}".format(self.command, self.action), description=self.summary, + example=self.example, ) for param in self.params: parser.add_argument( From 0b3d59cbfecf11324c21cf0b30c33fdf622aa064 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Mon, 18 Jul 2022 15:34:55 -0400 Subject: [PATCH 2/3] Still haven't dropped python2 support yet :( --- linodecli/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linodecli/__init__.py b/linodecli/__init__.py index bcee50e31..4b7aee6fd 100755 --- a/linodecli/__init__.py +++ b/linodecli/__init__.py @@ -559,13 +559,13 @@ def main(): arg.description, ) ) - arg_example = f' --{arg.path}="{arg.example}"' + arg_example = ' --{}="{}"'.format(arg.path, arg.example) examples.append(arg_example) example = "".join(examples) print() print("Example:") print( - f" linode-cli {parsed.command} {parsed.action} {example}", end="" + " linode-cli {} {} {}".format(parsed.command, parsed.action, example) ) elif operation.method == "get" and parsed.action == "list": From 8f9f8e0715580ace6492e5eb27e649f309860e8b Mon Sep 17 00:00:00 2001 From: Will Smith Date: Mon, 18 Jul 2022 15:42:13 -0400 Subject: [PATCH 3/3] Use examples from the API Docs if present Expands on https://github.com/linode/linode-cli/pull/299 Generating meaningful examples is tricky, and it's also not needed - the docs already have CLI examples for most operations. This change grabs the examples provided in the API spec, where present, and prints them alongside the help for actions in the CLI. --- linodecli/__init__.py | 13 ++++--------- linodecli/cli.py | 10 ++++++++-- linodecli/operation.py | 5 +++-- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/linodecli/__init__.py b/linodecli/__init__.py index 4b7aee6fd..00bb6b677 100755 --- a/linodecli/__init__.py +++ b/linodecli/__init__.py @@ -547,7 +547,6 @@ def main(): print(operation.summary) print() if operation.args: - examples = [] print("Arguments:") for arg in sorted(operation.args, key=lambda s: not s.required): print( @@ -559,14 +558,10 @@ def main(): arg.description, ) ) - arg_example = ' --{}="{}"'.format(arg.path, arg.example) - examples.append(arg_example) - example = "".join(examples) - print() - print("Example:") - print( - " linode-cli {} {} {}".format(parsed.command, parsed.action, example) - ) + if operation.example: + print() + print("Example:") + print(operation.example) elif operation.method == "get" and parsed.action == "list": filterable_attrs = [ diff --git a/linodecli/cli.py b/linodecli/cli.py index e353da65e..7dddffd5d 100644 --- a/linodecli/cli.py +++ b/linodecli/cli.py @@ -107,7 +107,6 @@ def _parse_args(self, node, prefix=[], args=None): args[path] = { "type": info.get("type") or "string", "desc": info.get("description") or "", - "example": info.get("example") or "", "name": arg, "format": info.get("x-linode-cli-format", info.get("format", None)), } @@ -210,6 +209,13 @@ def bake(self, spec): continue summary = data[m].get("summary") or "" + example = None + + if "x-code-samples" in data[m]: + for c in data[m]["x-code-samples"]: + if "lang" in c and c["lang"].lower() == "cli" and "source" in c: + example = c["source"] + break use_servers = ( [c["url"] for c in data[m]["servers"]] @@ -318,7 +324,6 @@ def bake(self, spec): info["desc"].split(".")[0] + ".", arg, info["format"], - info["example"], list_item=info.get("list_item"), ) @@ -358,6 +363,7 @@ def bake(self, spec): use_params, use_servers, allowed_defaults=allowed_defaults, + example=example, ) # remove any empty commands (those that have no actions) diff --git a/linodecli/operation.py b/linodecli/operation.py index 80a52dfaf..f958e95c2 100644 --- a/linodecli/operation.py +++ b/linodecli/operation.py @@ -100,13 +100,12 @@ class CLIArg: """ def __init__( - self, name, arg_type, description, path, arg_format, example, list_item=None + self, name, arg_type, description, path, arg_format, list_item=None ): self.name = name self.arg_type = arg_type self.arg_format = arg_format self.description = description.replace("\n", "").replace("\r", "") - self.example = example self.path = path self.arg_item_type = None # populated during baking for arrays self.required = False # this is set during baking @@ -150,6 +149,7 @@ def __init__( params, servers, allowed_defaults=None, + example=None, ): self.command = command self.action = action @@ -161,6 +161,7 @@ def __init__( self.params = params self.servers = servers self.allowed_defaults = allowed_defaults + self.example = example @property def url(self):