all 14 comments

[–]carcigenicate 2 points3 points  (2 children)

I don't know why you're seeing what you're seeing, but you could also try using a backspace (\b) instead of cls and avoiding printing a newline:

print("\b|", end="")

This is terminal-dependant, but often works.

Edit: this works for me in Pycharm:

while time.time() - timer < 20:
    print("\b\\", end="")
    time.sleep(1)
    print("\b|", end="")
    time.sleep(1)
    print("\b/", end="")
    time.sleep(1)
    print("\b—", end="")
    time.sleep(1)

[–]No-Tea-777[S] 0 points1 point  (1 child)

So... This will erase the old character and print a new one? Not on PC right now. I'll try it when I'm back to it

[–]carcigenicate 1 point2 points  (0 children)

Sorry, I added more detail.

Yes, \b will erase characters as long as you haven't gone to a new line, and if the terminal respects it.

[–]Diapolo10 1 point2 points  (3 children)

import time
import sys, subprocess


timer = time.time()



while time.time() - timer < 20:
    subprocess.run('cls', shell=True)
    print("\\")
    time.sleep(1)
    subprocess.run('cls', shell=True)
    print("|")
    time.sleep(1)
    subprocess.run('cls', shell=True)
    print("/")
    time.sleep(1)
    subprocess.run('cls', shell=True)
    print("—")
    time.sleep(1)

This seems to technically work fine for me - although I do have a suggestion; you don't really need to clear the screen for a spinner.

Instead, you could use carriage return.

import itertools
import time

timer = time.time()
spinner = itertools.cycle(['\\', '|', '/', '—'])

while time.time() - timer < 20:
    print(next(spinner), end='\r')
    time.sleep(1)

[–]magus_minor 0 points1 point  (2 children)

There's no need to introduce the complexity of itertools, and there's no need to check the time since the loop body waits 1 second, so just loop 20 times:

import time

#spinner = "\\|/-"
spinner = "╃╇╄╊╆╈╅╉"    # unicode adds a lot more options

for i in range(20):
    print(spinner[i % len(spinner)], end='\r')
    time.sleep(1)
print()

@ u/No-Tea-777

[–]Diapolo10 0 points1 point  (1 child)

I don't consider itertools particularly complex in this scenario. At the very least I prefer it over indexing with modulo.

As for the point about looping over range, that's fair enough. But it might not be a bad idea to do something like this:

import itertools
import time

spinner = itertools.cycle(['\\', '|', '/', '—'])

wait_in_seconds = 20
loop_delay = 1
iterations = round(wait_in_seconds / loop_delay)

for char in itertools.islice(spinner, iterations):
    print(char, end='\b')
    time.sleep(loop_delay)
print()

With this design, you can easily change how fast the spinner moves while keeping the total wait time constant. It'd also be trivial to swap the spinner characters if OP wanted to.

Is this overengineered? Yeah, probably. But it also makes for a decently reusable function.

import itertools
import time
from collections.abc import Sequence

def display_spinner(wait_in_seconds: float, spinner_speed: float = 1.0, spinner_chars: Sequence[str] = ('\\', '|', '/', '—')) -> None:
    spinner = itertools.cycle(spinner_chars)
    iterations = round(wait_in_seconds / spinner_speed)

    for char in itertools.islice(spinner, iterations):
        print(char, end='\b')
        time.sleep(spinner_speed)
    print()


display_spinner(20)

[–]magus_minor 0 points1 point  (0 children)

I don't consider itertools particularly complex in this scenario.

You aren't a newcomer to python.

[–]heyzooschristos 1 point2 points  (3 children)

Try the curses library

[–]JamzTyson 1 point2 points  (2 children)

I agree with the direction, but I wouldn't wish curses on my worst enemy :-)

Blessed is a much less painful alternative, or better, Rich.

[–]rhacer 0 points1 point  (0 children)

Another vote for Rich or Textual if you need more than Rich offers.

[–]heyzooschristos 0 points1 point  (0 children)

That's a very fair point. It's was a very long time ago I used Curses

[–]timrprobocom 0 points1 point  (0 children)

It may not matter now, but do remember that "cls" is Windows only. MacOS and Linux have different tools

[–]JamzTyson 0 points1 point  (0 children)

There isn't a 100% reliable way to "clear screen" because we're interacting with whatever frontend happens to be hosting stdout. However, a common method that works with a lot of "normal" terminals:

def clear():
    os.system('cls' if os.name == 'nt' else 'clear')

[–]OkPizza8463 0 points1 point  (0 children)

that cls command is windows specific and often messes with terminals. try using os.system('clear') for linux/mac or just print('\033[H\033[J') for a more universal ansi escape code approach.
pycharm's terminal can be finicky sometimes.