From efabdf97f971f50235b23d1c6b8b349f60f86294 Mon Sep 17 00:00:00 2001 From: Andreas Maier Date: Tue, 6 Dec 2016 18:39:56 +0100 Subject: [PATCH] Added support for suppressing spinner when not on a TTY. Signed-off-by: Andreas Maier --- .travis.yml | 1 + click_spinner/__init__.py | 28 ++++++++++++++++-------- setup.py | 3 ++- tests/test_spinner.py | 45 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index cbda1c6..c7e450a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,7 @@ notifications: - yoav@yoavram.com install: - pip install click +- pip install six - python setup.py install script: py.test deploy: diff --git a/click_spinner/__init__.py b/click_spinner/__init__.py index 8d126c6..8500b75 100644 --- a/click_spinner/__init__.py +++ b/click_spinner/__init__.py @@ -7,18 +7,21 @@ import itertools class Spinner(object): spinner_cycle = itertools.cycle(['-', '/', '|', '\\']) - def __init__(self): + def __init__(self, force=False): + self._force = force self.stop_running = None self.spin_thread = None def start(self): - self.stop_running = threading.Event() - self.spin_thread = threading.Thread(target=self.init_spin) - self.spin_thread.start() + if sys.stdout.isatty() or self._force: + self.stop_running = threading.Event() + self.spin_thread = threading.Thread(target=self.init_spin) + self.spin_thread.start() def stop(self): - self.stop_running.set() - self.spin_thread.join() + if self.spin_thread: + self.stop_running.set() + self.spin_thread.join() def init_spin(self): while not self.stop_running.is_set(): @@ -34,9 +37,16 @@ class Spinner(object): self.stop() -def spinner(): +def spinner(force=False): """This function creates a context manager that is used to display a - spinner as long as the context has not exited. + spinner on stdout as long as the context has not exited. + + The spinner is created only if stdout is not redirected, or if the spinner + is forced using the `force` parameter. + + Parameters: + + force (bool): Force creation of spinner even when stdout is redirected. Example usage:: @@ -45,7 +55,7 @@ def spinner(): do_something_else() """ - return Spinner() + return Spinner(force) from ._version import get_versions diff --git a/setup.py b/setup.py index cb20c31..4641edf 100644 --- a/setup.py +++ b/setup.py @@ -18,8 +18,9 @@ setup( description='Spinner for Click', extras_require={ 'test': [ - 'click' + 'click', 'pytest', + 'six', ] } ) diff --git a/tests/test_spinner.py b/tests/test_spinner.py index 6ab3d2a..58212c8 100644 --- a/tests/test_spinner.py +++ b/tests/test_spinner.py @@ -1,3 +1,8 @@ +import sys +import os +import time +import tempfile +from six import StringIO import click from click.testing import CliRunner @@ -33,3 +38,43 @@ def test_spinner_resume(): result = runner.invoke(cli, []) assert result.exception is None + +def test_spinner_redirect(): + @click.command() + def cli(): + stdout_io = StringIO() + saved_stdout = sys.stdout + sys.stdout = stdout_io # redirect stdout to a string buffer + spinner = click_spinner.Spinner() + spinner.start() + time.sleep(1) # allow time for a few spins + spinner.stop() + sys.stdout = saved_stdout + stdout_io.flush() + stdout_str = stdout_io.getvalue() + assert len(stdout_str) == 0 + + runner = CliRunner() + result = runner.invoke(cli, []) + assert result.exception is None + + +def test_spinner_redirect_force(): + @click.command() + def cli(): + stdout_io = StringIO() + saved_stdout = sys.stdout + sys.stdout = stdout_io # redirect stdout to a string buffer + spinner = click_spinner.Spinner(force=True) + spinner.start() + time.sleep(1) # allow time for a few spins + spinner.stop() + sys.stdout = saved_stdout + stdout_io.flush() + stdout_str = stdout_io.getvalue() + assert len(stdout_str) > 0 + + runner = CliRunner() + result = runner.invoke(cli, []) + assert result.exception is None +