Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

{Issue #47} Synchronous spinner #132

Closed
wants to merge 9 commits into from
26 changes: 23 additions & 3 deletions halo/halo.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ class Halo(object):
SPINNER_PLACEMENTS = ('left', 'right',)

def __init__(self, text='', color='cyan', text_color=None, spinner=None,
animation=None, placement='left', interval=-1, enabled=True, stream=sys.stdout):
animation=None, placement='left', interval=-1, enabled=True,
manual_step=False, stream=sys.stdout):
"""Constructs the Halo object.
Parameters
----------
Expand Down Expand Up @@ -59,6 +60,7 @@ def __init__(self, text='', color='cyan', text_color=None, spinner=None,
"""
self._color = color
self._animation = animation
self.manual_step = manual_step

self.spinner = spinner
self.text = text
Expand All @@ -72,6 +74,7 @@ def __init__(self, text='', color='cyan', text_color=None, spinner=None,
self._text_index = 0
self._spinner_thread = None
self._stop_spinner = None
self._run_spinner = None
self._spinner_id = None
self.enabled = enabled

Expand Down Expand Up @@ -396,10 +399,24 @@ def render(self):
self
"""
while not self._stop_spinner.is_set():
self._render_frame()
if self._run_spinner.is_set():
self._render_frame()
if self.manual_step:
self._run_spinner.clear()
time.sleep(0.001 * self._interval)

return self

def step(self):
"""Runs the render once.
Returns
-------
self
"""
if self._spinner_thread and self._spinner_thread.is_alive():
self._run_spinner.set()

return self

def frame(self):
"""Builds and returns the frame to be rendered
Expand Down Expand Up @@ -469,9 +486,12 @@ def start(self, text=None):
self._hide_cursor()

self._stop_spinner = threading.Event()
self._run_spinner = threading.Event()
self._spinner_thread = threading.Thread(target=self.render)
self._spinner_thread.setDaemon(True)
self._render_frame()
if not self.manual_step:
self._render_frame()
self._run_spinner.set()
self._spinner_id = self._spinner_thread.name
self._spinner_thread.start()

Expand Down
14 changes: 10 additions & 4 deletions halo/halo_notebook.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,18 @@


class HaloNotebook(Halo):
def __init__(self, text='', color='cyan', text_color=None, spinner=None, placement='left',
animation=None, interval=-1, enabled=True, stream=sys.stdout):
def __init__(self, text='', color='cyan', text_color=None, spinner=None,
placement='left', animation=None, interval=-1, enabled=True,
manual_step=False, stream=sys.stdout):
super(HaloNotebook, self).__init__(text=text,
color=color,
text_color=text_color,
spinner=spinner,
placement=placement,
animation=animation,
interval=interval, enabled=enabled,
interval=interval,
enabled=enabled,
manual_step=manual_step,
stream=stream)
self.output = self._make_output_widget()

Expand Down Expand Up @@ -62,9 +65,12 @@ def start(self, text=None):

display(self.output)
self._stop_spinner = threading.Event()
self._run_spinner = threading.Event()
self._spinner_thread = threading.Thread(target=self.render)
self._spinner_thread.setDaemon(True)
self._render_frame()
if not self.manual_step:
self._render_frame()
self._run_spinner.set()
self._spinner_id = self._spinner_thread.name
self._spinner_thread.start()

Expand Down
22 changes: 22 additions & 0 deletions tests/test_halo.py
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,28 @@ def test_redirect_stdout(self):
self._stream = out

self.assertIn('foo', output[0])

def test_manual_step(self):
"""Test manual step
"""
default_spinner = Halo()
self.assertEqual(default_spinner.manual_step, False)
manual_spinner = Halo(spinner='dots', manual_step=True,
stream=self._stream)

texts = ['foo', 'bar', 'baz']

manual_spinner.start()
for text in texts:
manual_spinner.text=text
manual_spinner.step()
time.sleep(1)
manual_spinner.stop()
output = self._get_test_output()['text']

self.assertEqual(output[0], '{} {}'.format(frames[0], texts[0]))
self.assertEqual(output[1], '{} {}'.format(frames[1], texts[1]))
self.assertEqual(output[2], '{} {}'.format(frames[2], texts[2]))

def tearDown(self):
pass
Expand Down