From 140e65f13dfe3b4a0be5c69f5799a5cb93697e23 Mon Sep 17 00:00:00 2001 From: Pallab Pain Date: Fri, 4 Aug 2023 22:00:08 +0530 Subject: [PATCH] fix: implements dummy spinner for non-tty environments --- riocli/deployment/execute.py | 10 ++++++--- riocli/device/vpn.py | 9 ++++++-- riocli/parameter/apply.py | 9 ++++++-- riocli/parameter/delete.py | 10 +++++++-- riocli/parameter/upload.py | 9 +++++--- riocli/utils/spinner.py | 42 +++++++++++++++++++++++++++++++++++- 6 files changed, 76 insertions(+), 13 deletions(-) diff --git a/riocli/deployment/execute.py b/riocli/deployment/execute.py index f484ba85..fee280a5 100644 --- a/riocli/deployment/execute.py +++ b/riocli/deployment/execute.py @@ -11,12 +11,16 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - +import sys import typing import click from click_help_colors import HelpColorsCommand -from yaspin import kbi_safe_yaspin + +if sys.stdout.isatty(): + from yaspin import kbi_safe_yaspin as Spinner +else: + from riocli.utils.spinner import DummySpinner as Spinner from riocli.constants import Colors from riocli.deployment.util import name_to_guid, select_details @@ -49,7 +53,7 @@ def execute_command( try: comp_id, exec_id, pod_name = select_details(deployment_guid, component_name, exec_name) - with kbi_safe_yaspin(text='Executing command `{}`...'.format(command)) as spinner: + with Spinner(text='Executing command `{}`...'.format(command)): stdout, stderr = run_on_cloud(deployment_guid, comp_id, exec_id, pod_name, command) if stderr: diff --git a/riocli/device/vpn.py b/riocli/device/vpn.py index f964ef51..6e054382 100644 --- a/riocli/device/vpn.py +++ b/riocli/device/vpn.py @@ -11,11 +11,16 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +import sys import typing import click from click_help_colors import HelpColorsCommand -from yaspin import kbi_safe_yaspin + +if sys.stdout.isatty(): + from yaspin import kbi_safe_yaspin as Spinner +else: + from riocli.utils.spinner import DummySpinner as Spinner from riocli.config import new_client from riocli.constants import Colors @@ -78,7 +83,7 @@ def toggle_vpn(devices: typing.List, enable: bool, click.echo("") # Echo an empty line result = [] - with kbi_safe_yaspin() as spinner: + with Spinner() as spinner: for device in final: spinner.text = 'Updating VPN state on device {}'.format( click.style(device.name, bold=True, fg=Colors.CYAN)) diff --git a/riocli/parameter/apply.py b/riocli/parameter/apply.py index 0db0facb..e02e6a02 100644 --- a/riocli/parameter/apply.py +++ b/riocli/parameter/apply.py @@ -11,11 +11,16 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +import sys import typing import click from click_help_colors import HelpColorsCommand -from yaspin import kbi_safe_yaspin + +if sys.stdout.isatty(): + from yaspin import kbi_safe_yaspin as Spinner +else: + from riocli.utils.spinner import DummySpinner as Spinner from riocli.config import new_client from riocli.constants import Colors, Symbols @@ -79,7 +84,7 @@ def apply_configurations( "Do you want to apply the configurations?", default=True, abort=True) - with kbi_safe_yaspin(text='Applying parameters...') as spinner: + with Spinner(text='Applying parameters...'): response = client.apply_parameters( list(device_ids.keys()), list(tree_names), diff --git a/riocli/parameter/delete.py b/riocli/parameter/delete.py index 0c1d84e2..e9bb64bc 100644 --- a/riocli/parameter/delete.py +++ b/riocli/parameter/delete.py @@ -12,10 +12,16 @@ # See the License for the specific language governing permissions and # limitations under the License. +import sys + import click from click_help_colors import HelpColorsCommand from rapyuta_io.utils.rest_client import HttpMethod -from yaspin import kbi_safe_yaspin + +if sys.stdout.isatty(): + from yaspin import kbi_safe_yaspin as Spinner +else: + from riocli.utils.spinner import DummySpinner as Spinner from riocli.constants import Colors, Symbols from riocli.parameter.utils import _api_call @@ -43,7 +49,7 @@ def delete_configurations( if not silent: click.confirm('Do you want to proceed?', default=True, abort=True) - with kbi_safe_yaspin(text='Deleting...', timer=True) as spinner: + with Spinner(text='Deleting...', timer=True) as spinner: try: data = _api_call(HttpMethod.DELETE, name=tree) if data.get('data') != 'ok': diff --git a/riocli/parameter/upload.py b/riocli/parameter/upload.py index 1cd59157..53835fac 100644 --- a/riocli/parameter/upload.py +++ b/riocli/parameter/upload.py @@ -12,12 +12,16 @@ # See the License for the specific language governing permissions and # limitations under the License. +import sys import typing import click from click_help_colors import HelpColorsCommand -from yaspin import kbi_safe_yaspin +if sys.stdout.isatty(): + from yaspin import kbi_safe_yaspin as Spinner +else: + from riocli.utils.spinner import DummySpinner as Spinner from riocli.config import new_client from riocli.constants import Colors, Symbols from riocli.parameter.utils import filter_trees, display_trees @@ -57,8 +61,7 @@ def upload_configurations( client = new_client() - with kbi_safe_yaspin(text="Uploading configurations...", - timer=True) as spinner: + with Spinner(text="Uploading configurations...", timer=True) as spinner: try: client.upload_configurations( rootdir=path, diff --git a/riocli/utils/spinner.py b/riocli/utils/spinner.py index 0b84c557..822a97e1 100644 --- a/riocli/utils/spinner.py +++ b/riocli/utils/spinner.py @@ -13,10 +13,46 @@ # limitations under the License. import functools +import sys +import click from yaspin import kbi_safe_yaspin +class DummySpinner: + """DummySpinner replaces the yaspin spinner with a dummy one + + This class is useful for cases when the active stream is not a tty + """ + + def __init__(self, *args, **kwargs): + self.text = '' + + def write(self, text): + click.echo(text) + + def hidden(self): + return self + + def fail(self, text='FAIL'): + click.echo('{} {}'.format(text, self.text)) + + def ok(self, text='OK'): + click.echo('{} {}'.format(text, self.text)) + + def __getattr__(self, name): + return self + + def __call__(self): + pass + + def __enter__(self): + return self + + def __exit__(self, *args, **kwargs): + return False + + def with_spinner(**spin_kwargs): """ Decorator for wrapping your function with a spinner @@ -42,7 +78,11 @@ def do_something(arg1, spinner=None): def decorated(func): @functools.wraps(func) def wrapper(*args, **kwargs): - with kbi_safe_yaspin(**spin_kwargs) as spinner: + spinner_class = kbi_safe_yaspin + if not sys.stdout.isatty(): + spinner_class = DummySpinner + + with spinner_class(**spin_kwargs) as spinner: kwargs['spinner'] = spinner return func(*args, **kwargs)