Is there a way to print a spinning cursor in a terminal using Python?
24 Answers
Something like this, assuming your terminal handles \b
import sys
import time
def spinning_cursor():
while True:
for cursor in '|/-\\':
yield cursor
spinner = spinning_cursor()
for _ in range(50):
sys.stdout.write(next(spinner))
sys.stdout.flush()
time.sleep(0.1)
sys.stdout.write('\b')

- 281
- 1
- 10

- 223,662
- 58
- 417
- 506
-
17You might want to use `spinner = itertools.cycle(['-', '/', '|', '\\'])` instead of creating a generator function (less verbose and more reuse) as shown [here](http://stackoverflow.com/a/22616059/1300775) – Damien Dec 03 '14 at 13:58
-
8Note that with Python 3, `spinner.next()` is replaced by `next(spinner)`; see http://stackoverflow.com/a/1073582/5025060. – CODE-REaD Apr 26 '16 at 04:05
Easy to use API (this will run the spinner in a separate thread):
import sys
import time
import threading
class Spinner:
busy = False
delay = 0.1
@staticmethod
def spinning_cursor():
while 1:
for cursor in '|/-\\': yield cursor
def __init__(self, delay=None):
self.spinner_generator = self.spinning_cursor()
if delay and float(delay): self.delay = delay
def spinner_task(self):
while self.busy:
sys.stdout.write(next(self.spinner_generator))
sys.stdout.flush()
time.sleep(self.delay)
sys.stdout.write('\b')
sys.stdout.flush()
def __enter__(self):
self.busy = True
threading.Thread(target=self.spinner_task).start()
def __exit__(self, exception, value, tb):
self.busy = False
time.sleep(self.delay)
if exception is not None:
return False
Now use it in a with
block anywhere in the code:
with Spinner():
# ... some long-running operations
# time.sleep(3)

- 83
- 1
- 7

- 671
- 5
- 5
-
7this is really nice, until you hit an error in your code that isn't handled. Then you can't force it to stop. – DDuffy Dec 28 '17 at 13:19
-
`float(delay)` will raise if not float, should be `isinstance(delay, Number)`, with `Number` from `numbers`. – levsa Jun 12 '19 at 12:34
-
Hey chief, I am pretty amateur with this, but this seems really nice. Can you give me an example of "with Spinner()"? I am not quite getting it, apparently. @Victor Moyseenko – Mike_Leigh Mar 17 '20 at 11:02
A nice pythonic way is to use itertools.cycle:
import itertools, sys
spinner = itertools.cycle(['-', '/', '|', '\\'])
while True:
sys.stdout.write(next(spinner)) # write the next character
sys.stdout.flush() # flush stdout buffer (actual character display)
sys.stdout.write('\b') # erase the last written char
Also, you might want to use threading to display the spinner during a long function call, as in http://www.interclasse.com/scripts/spin.php

- 1,624
- 2
- 19
- 26
-
5As per CODE-REaD's comment in the other answer, in python 3, use `next(spinner)` instead of `spinner.next()` – Siyh Jun 18 '18 at 13:04
-
4
-
1
-
1
-
it is running forever, I tried it with threading, it is still running crazy, loz. if it is a thread3, how can i make it run with t1 starts, and stop with t2 finishes? any hints? – Mike_Leigh Mar 17 '20 at 06:20
-
Can you replace the `True` condition of the `while` loop with a test that works in your specific case ? Eg. `while not t2.finished`. Alternatively you can manage it in your threading join logic, maybe with a variable that acts as a flag. – Damien Apr 16 '20 at 11:58
For completeness I want to add the great package halo. It offers a lot of preset spinners and higher level customization options.
Extract from their readme
from halo import Halo
spinner = Halo(text='Loading', spinner='dots')
spinner.start()
# Run time consuming work here
# You can also change properties for spinner as and when you want
spinner.stop()
Alternatively, you can use halo with Python's with statement:
from halo import Halo
with Halo(text='Loading', spinner='dots'):
# Run time consuming work here
Finally, you can use halo as a decorator:
from halo import Halo
@Halo(text='Loading', spinner='dots')
def long_running_function():
# Run time consuming work here
pass
long_running_function()

- 2,354
- 3
- 25
- 35
A solution:
import sys
import time
print "processing...\\",
syms = ['\\', '|', '/', '-']
bs = '\b'
for _ in range(10):
for sym in syms:
sys.stdout.write("\b%s" % sym)
sys.stdout.flush()
time.sleep(.5)
The key is to use the backspace character '\b' and flush stdout.

- 4,545
- 6
- 32
- 49
Improved version from @Victor Moyseenko as the original version had few issues
- was leaving spinner's characters after spinning is complete
- and sometimes lead to removing following output's first character too
- avoids a rare race condition by putting threading.Lock() on output
- falls back to simpler output when no tty is available (no spinning)
import sys
import threading
import itertools
import time
class Spinner:
def __init__(self, message, delay=0.1):
self.spinner = itertools.cycle(['-', '/', '|', '\\'])
self.delay = delay
self.busy = False
self.spinner_visible = False
sys.stdout.write(message)
def write_next(self):
with self._screen_lock:
if not self.spinner_visible:
sys.stdout.write(next(self.spinner))
self.spinner_visible = True
sys.stdout.flush()
def remove_spinner(self, cleanup=False):
with self._screen_lock:
if self.spinner_visible:
sys.stdout.write('\b')
self.spinner_visible = False
if cleanup:
sys.stdout.write(' ') # overwrite spinner with blank
sys.stdout.write('\r') # move to next line
sys.stdout.flush()
def spinner_task(self):
while self.busy:
self.write_next()
time.sleep(self.delay)
self.remove_spinner()
def __enter__(self):
if sys.stdout.isatty():
self._screen_lock = threading.Lock()
self.busy = True
self.thread = threading.Thread(target=self.spinner_task)
self.thread.start()
def __exit__(self, exception, value, tb):
if sys.stdout.isatty():
self.busy = False
self.remove_spinner(cleanup=True)
else:
sys.stdout.write('\r')
example of usage of the Spinner class above:
with Spinner("just waiting a bit.. "):
time.sleep(3)
uploaded code to https://github.com/Tagar/stuff/blob/master/spinner.py

- 13,911
- 6
- 95
- 110
Sure, it's possible. It's just a question of printing the backspace character (\b
) in between the four characters that would make the "cursor" look like it's spinning ( -
, \
, |
, /
).

- 117,245
- 29
- 183
- 222
I have found py-spin package on GitHub. It has many nice spinning Styles. Here are some sample about how to use, Spin1
is the \-/
style:
from __future__ import print_function
import time
from pyspin.spin import make_spin, Spin1
# Choose a spin style and the words when showing the spin.
@make_spin(Spin1, "Downloading...")
def download_video():
time.sleep(10)
if __name__ == '__main__':
print("I'm going to download a video, and it'll cost much time.")
download_video()
print("Done!")
time.sleep(0.1)
It is also possible to control the spin manualy:
from __future__ import print_function
import sys
import time
from pyspin.spin import Spin1, Spinner
# Choose a spin style.
spin = Spinner(Spin1)
# Spin it now.
for i in range(50):
print(u"\r{0}".format(spin.next()), end="")
sys.stdout.flush()
time.sleep(0.1)
Other styles in the below gif.

- 1,335
- 2
- 13
- 32
Grab the awesome progressbar
module - http://code.google.com/p/python-progressbar/
use RotatingMarker
.

- 9,483
- 2
- 50
- 58
I built a generic Singleton, shared by the entire application
from itertools import cycle
import threading
import time
class Spinner:
__default_spinner_symbols_list = ['|-----|', '|#----|', '|-#---|', '|--#--|', '|---#-|', '|----#|']
def __init__(self, spinner_symbols_list: [str] = None):
spinner_symbols_list = spinner_symbols_list if spinner_symbols_list else Spinner.__default_spinner_symbols_list
self.__screen_lock = threading.Event()
self.__spinner = cycle(spinner_symbols_list)
self.__stop_event = False
self.__thread = None
def get_spin(self):
return self.__spinner
def start(self, spinner_message: str):
self.__stop_event = False
time.sleep(0.3)
def run_spinner(message):
while not self.__stop_event:
print("\r{message} {spinner}".format(message=message, spinner=next(self.__spinner)), end="")
time.sleep(0.3)
self.__screen_lock.set()
self.__thread = threading.Thread(target=run_spinner, args=(spinner_message,), daemon=True)
self.__thread.start()
def stop(self):
self.__stop_event = True
if self.__screen_lock.is_set():
self.__screen_lock.wait()
self.__screen_lock.clear()
print("\r", end="")
print("\r", end="")
if __name__ == '__main__':
import time
# Testing
spinner = Spinner()
spinner.start("Downloading")
# Make actions
time.sleep(5) # Simulate a process
#
spinner.stop()
You can write '\r\033[K'
to clear the current line. And the following is a example modified from @nos.
import sys
import time
def spinning_cursor():
while True:
for cursor in '|/-\\':
yield cursor
spinner = spinning_cursor()
for _ in range(1, 10):
content = f'\r{next(spinner)} Downloading...'
print(content, end="")
time.sleep(0.1)
print('\r\033[K', end="")
For anyone who interested in nodejs, I also write a nodejs example.
function* makeSpinner(start = 0, end = 100, step = 1) {
let iterationCount = 0;
while (true) {
for (const char of '|/-\\') {
yield char;
}
}
return iterationCount;
}
async function sleep(seconds) {
return new Promise((resolve) => {
setTimeout(resolve, seconds * 1000);
});
}
(async () => {
const spinner = makeSpinner();
for (let i = 0; i < 10; i++) {
content = `\r${spinner.next().value} Downloading...`;
process.stdout.write(content);
await sleep(0.1);
process.stdout.write('\r\033[K');
}
})();

- 1,776
- 2
- 21
- 30
For more advanced console manipulations, on unix you can use the curses python module, and on windows, you can use WConio which provides equivalent functionality of the curses library.

- 9,635
- 5
- 62
- 68
#!/usr/bin/env python
import sys
chars = '|/-\\'
for i in xrange(1,1000):
for c in chars:
sys.stdout.write(c)
sys.stdout.write('\b')
sys.stdout.flush()
CAVEATS: In my experience this doesn't work in all terminals. A more robust way to do this under Unix/Linux, be it more complicated is to use the curses module, which doesn't work under Windows. You probably want to slow it down some how with actual processing that is going on in the background.
curses module. i'd have a look at the addstr() and addch() functions. Never used it though.

- 241
- 1
- 2
- 9
import sys
def DrowWaitCursor(counter):
if counter % 4 == 0:
print("/",end = "")
elif counter % 4 == 1:
print("-",end = "")
elif counter % 4 == 2:
print("\\",end = "")
elif counter % 4 == 3:
print("|",end = "")
sys.stdout.flush()
sys.stdout.write('\b')
This can be also another solution using a function with a parameter.

- 177
- 2
- 9
Here ya go - simple and clear.
import sys
import time
idx = 0
cursor = ['|','/','-','\\'] #frames of an animated cursor
while True:
sys.stdout.write(cursor[idx])
sys.stdout.write('\b')
idx = idx + 1
if idx > 3:
idx = 0
time.sleep(.1)

- 61
- 3
Crude but simple solution:
import sys
import time
cursor = ['|','/','-','\\']
for count in range(0,1000):
sys.stdout.write('\b{}'.format(cursor[count%4]))
sys.stdout.flush()
# replace time.sleep() with some logic
time.sleep(.1)
There are obvious limitations, but again, crude.

- 560
- 7
- 21
I propose a solution using decorators
from itertools import cycle
import functools
import threading
import time
def spinner(message, spinner_symbols: list = None):
spinner_symbols = spinner_symbols or list("|/-\\")
spinner_symbols = cycle(spinner_symbols)
global spinner_event
spinner_event = True
def start():
global spinner_event
while spinner_event:
symbol = next(spinner_symbols)
print("\r{message} {symbol}".format(message=message, symbol=symbol), end="")
time.sleep(0.3)
def stop():
global spinner_event
spinner_event = False
print("\r", end="")
def external(fct):
@functools.wraps(fct)
def wrapper(*args):
spinner_thread = threading.Thread(target=start, daemon=True)
spinner_thread.start()
result = fct(*args)
stop()
spinner_thread.join()
return result
return wrapper
return external
Simple usage
@spinner("Downloading")
def f():
time.sleep(10)

- 499
- 5
- 6
I just started with python about a week ago and found this posting. I've combined a bit of what I found here with stuff I learned about threads and queues elsewhere to provide a much better implementation in my opinion. In my solution, writing to the screen is handled by a thread that checks a queue for content. If that queue has content, the cursor spinning thread knows to stop. On the flipside, the cursor spinning thread uses a queue as a lock so the printing thread knows not to print until a full pass of the spinner code is complete. This prevents race conditions and a lot of excess code people are using to keep the console clean.
See below:
import threading, queue, itertools, sys, time # all required for my version of spinner
import datetime #not required for spinning cursor solution, only my example
console_queue = queue.Queue() # this queue should be initialized before functions
screenlock = queue.Queue() # this queue too...
def main():
threading.Thread(target=spinner).start()
threading.Thread(target=consoleprint).start()
while True:
# instead of invoking print or stdout.write, we just add items to the console_queue
# The next three lines are an example of my code in practice.
time.sleep(.5) # wait half a second
currenttime = "[" + datetime.datetime.now().strftime("%d/%m/%Y %H:%M:%S") + "] "
console_queue.put(currenttime) # The most important part. Substitute your print and stdout functions with this.
def spinner(console_queue = console_queue, screenlock = screenlock):
spinnerlist = itertools.cycle(['|', '/', '-', '\\'])
while True:
if console_queue.empty():
screenlock.put("locked")
sys.stdout.write(next(spinnerlist))
sys.stdout.flush()
sys.stdout.write('\b')
sys.stdout.flush()
screenlock.get()
time.sleep(.1)
def consoleprint(console_queue = console_queue, screenlock = screenlock):
while True:
if not console_queue.empty():
while screenlock.empty() == False:
time.sleep(.1)
sys.stdout.flush()
print(console_queue.get())
sys.stdout.flush()
if __name__ == "__main__":
main()
Having said all I said and written all I've written, I've only been doing python stuff for a week. If there are cleaner ways of doing this or I missed some best practices I'd love to learn. Thanks.
Something super simple: If you know the final metric then this will print the progress and eta as well.
from datetime import datetime
import itertools
def progress(title: str, total):
moon = itertools.cycle(["", "", "", "", "", "", "", ""])
start_time = datetime.now()
def show(current):
curr_time = datetime.now()
time_taken = curr_time - start_time
print(" ", next(moon), title, current, "/", total,
" progress: ", round((100.0 * current) / total, 2), "%",
" eta: ", (time_taken * (total - current)) / current, end="\r ")
return show

- 570
- 4
- 20

- 618
- 7
- 10
import requests
import time
import sys
weathercity = input("What city are you in? ")
weather = requests.get('http://api.openweathermap.org/data/2.5/weather?q='+weathercity+'&appid=886705b4c1182eb1c69f28eb8c520e20')
url = ('http://api.openweathermap.org/data/2.5/weather?q='+weathercity+'&appid=886705b4c1182eb1c69f28eb8c520e20')
def spinning_cursor():
while True:
for cursor in '|/-\\':
yield cursor
data = weather.json()
temp = data['main']['temp']
description = data['weather'][0]['description']
weatherprint ="In {}, it is currently {}°C with {}."
spinner = spinning_cursor()
for _ in range(25):
sys.stdout.write(next(spinner))
sys.stdout.flush()
time.sleep(0.1)
sys.stdout.write('\b')
convert = int(temp - 273.15)
print(weatherprint.format(weathercity, convert, description))
-
Pls be kind with me. i am new here. i am 12 years old. so i cant think logically but this will definately help you. – Oct 04 '20 at 08:48
-
you will get the temperature in celsius here. Pls review how was it. by addin a comment here – Oct 04 '20 at 09:04
-
1This is an exact copy/paste [`def spinning_cursor()...` and `sys.stdout.write(next(spinner)) ....`] of the code in the [9 year old answer of nos](https://stackoverflow.com/a/4995896/7709603). Please don't copy (parts of) other people's answers and pass them off as your own. And when answering older question, please make sure that you provide either a different solution or at least a significantly better explanation than current answers. – Mohnish Oct 04 '20 at 11:25
if you wanna python text spinner you can look picture
Simple:print_spinner("Hayatta en hakiki mürşit ilimdir.")

- 1
- 1
-
3Code should not be posted as an image. It is hard for others to type all the code down themselves, and vision-impaired people can't read the code at all. – Sylvester Kruin Sep 23 '21 at 17:32
Here is the simplest loading spinner for python:
import time
spin=["loading...... ", "|", "/","-", "\"]
for i in spin:
print("\b"+i, end=" ")
time.sleep (0.2)
Output:
loading...... |

- 27,497
- 23
- 70
- 73

- 1
- 2
-
1Please wrap your code in a code block(```). Also the syntax is wrong. Capital letters etc – thealpha93 May 02 '21 at 05:58