3

This is the code for the progress spinner:

import sys
import time

def spinning_cursor():
    while True:
        for cursor in '|/-\\':
            yield cursor

spinner = spinning_cursor()
for _ in range(50):
    sys.stdout.write(spinner.next())
    sys.stdout.flush()
    time.sleep(10)
    sys.stdout.write('\b')

Output

python2.7 test.py
|

It is spinning very slowly since the loop sleeps for 10 seconds...

How do I keep rotating the spinner while the process is sleeping?

martineau
  • 119,623
  • 25
  • 170
  • 301
meteor23
  • 267
  • 3
  • 6
  • 11
  • Your question is not clear. Do you want your cursor to turn slightly each time `cmd` is run once (which is what your code does), or do you want it to spin quickly while `cmd` is running? – Rory Daulton Feb 18 '18 at 17:40
  • @ It spining very slow and cmd execution is not completing – meteor23 Feb 18 '18 at 17:45
  • Possible duplicate of [How to create a spinning command line cursor using python?](https://stackoverflow.com/questions/4995733/how-to-create-a-spinning-command-line-cursor-using-python) – ndmeiri Feb 18 '18 at 17:54
  • If `cmd` is not completing, that is a separate issue from the spinning cursor. So what *exactly* are you asking? – Rory Daulton Feb 18 '18 at 17:58
  • @Rory Daulton, edited question now. – meteor23 Feb 18 '18 at 18:34

3 Answers3

7

You'll have to create a separate thread. The example below roughly shows how this can be done. However, this is just a simple example.

import sys
import time

import threading


class SpinnerThread(threading.Thread):

    def __init__(self):
        super().__init__(target=self._spin)
        self._stopevent = threading.Event()

    def stop(self):
        self._stopevent.set()

    def _spin(self):

        while not self._stopevent.isSet():
            for t in '|/-\\':
                sys.stdout.write(t)
                sys.stdout.flush()
                time.sleep(0.1)
                sys.stdout.write('\b')


def long_task():
    for i in range(10):
        time.sleep(1)
        print('Tick {:d}'.format(i))


def main():

    task = threading.Thread(target=long_task)
    task.start()

    spinner_thread = SpinnerThread()
    spinner_thread.start()

    task.join()
    spinner_thread.stop()


if __name__ == '__main__':
    main()
Stefan Falk
  • 23,898
  • 50
  • 191
  • 378
  • Is there some way to use the [asyncio.to_thread](https://docs.python.org/3/library/asyncio-task.html#running-in-threads) function instead of inheriting from Thread? – Snap May 06 '23 at 20:44
4

You could sleep in smaller steps until you reach 10 seconds:

import sys, time

def spinning_cursor():
    while True:
        for cursor in '|/-\\':
            yield cursor

spinner = spinning_cursor()
end_time = time.time() + 10
while time.time() < end_time:
    sys.stdout.write(spinner.next())
    sys.stdout.flush()
    time.sleep(0.2) # adjust this to change the speed
    sys.stdout.write('\b')

But this will block your main thread, so it will only be useful if you want to wait for 10 seconds without doing anything else in your Python program (e.g., waiting for some external process to complete).

If you want to run other Python code while the spinner is spinning, you will need two threads -- one for the spinner, one for the main work. You could set that up like this:

import sys, time, threading

def spin_cursor():
    while True:
        for cursor in '|/-\\':
            sys.stdout.write(cursor)
            sys.stdout.flush()
            time.sleep(0.1) # adjust this to change the speed
            sys.stdout.write('\b')
            if done:
                return

# start the spinner in a separate thread
done = False
spin_thread = threading.Thread(target=spin_cursor)
spin_thread.start()

# do some more work in the main thread, or just sleep:
time.sleep(10)

# tell the spinner to stop, and wait for it to do so;
# this will clear the last cursor before the program moves on
done = True
spin_thread.join()

# continue with other tasks
sys.stdout.write("all done\n")
Matthias Fripp
  • 17,670
  • 5
  • 28
  • 45
0

Spawn two threads, A and B. Thread A runs cmd to completion. Thread B displays the spinning cursor and waits for thread A to exit, which will happen when cmd completes. At that point, thread B clears the spinning cursor and then exit.

Or use an existing library instead of re-inventing the wheel. Consider the progressbar library. You'll want the RotatingMarker progress indicator.

ndmeiri
  • 4,979
  • 12
  • 37
  • 45
  • I am using python2.7 and progressbar is not available. End users cannot install modules. So it would be great if i get custom script – meteor23 Feb 18 '18 at 17:49
  • 1
    I will not write the code for you. I pointed you in the right direction, now it's your turn to attempt to update your code. There is a sister library to progressbar that supports Python 3. A simple search would have shown you that. Stack Overflow is not a code writing service. – ndmeiri Feb 18 '18 at 17:53