3
\$\begingroup\$
import sys
import time
import multiprocessing


def change_char_at(s: str, ch: str, i: int, j: int=None):
    '''strings are immutable so i made this handy-little function to 'mutate' strings
    similar to =>
    s[i] = ch    # if j is not specified
    s[i:j] = ch  # if j is specified

    *note*: negative indices does not work!
    '''
    if not j:
        j = i + 1
    return s[:i] + ch + s[j:]


def loader(width: int=20, bar_width: int=3):
    '''
    A simple loading bar which shows no information or whatever
    the function should be run in a different thread and must be killed.
    '''
    s = '[' + ' ' * (width - bar_width - 1) + ']'
    while 1:
        for i in range(1, width - bar_width - 1):
            sys.stdout.write('\r' + change_char_at(s, '===', i))
            sys.stdout.flush()
            time.sleep(0.1)
        for i in range(width - bar_width - 1, 0, -1):
            sys.stdout.write('\r' + change_char_at(s, '===', i))
            sys.stdout.flush()
            time.sleep(0.1)


def loader_with_wait(wait: int=None, width: int=20, bar_width: int=3):
    '''
    A simple loading bar which shows no information or whatever.
    it will quit after `wait` seconds or will *run forever* if wait is not specified

    param: wait: for how much time should the loading bar run.
    '''
    # Start the loader
    p = multiprocessing.Process(target=loader, name='loader', args=(width, bar_width))
    p.start()

    if wait:
        # let the loader run for `wait` seconds
        time.sleep(wait)
        # terminate the loader() function
        p.terminate()
        # Cleanup
        p.join()
        # Start from newline
        sys.stdout.write('\n')


if __name__ == '__main__':
    try:
        loader_with_wait(10)
    except KeyboardInterrupt:
        pass

Hey Guys! I made a simple progress bar in python. The animation is cool! it can wait for a few seconds or it can run forever, the choice is upto you. it can be used in other programs and can run in a separate thread. Implementing the wait function was the hardest thing to do. is there any other way to do it?

Any suggestions will be helpful... :-)

see it in action: https://asciinema.org/a/323180

\$\endgroup\$
3
  • \$\begingroup\$ One thing I notice is you're not following a docstring convention. You should using triple double-quoted strings to declare docstrings, i.e. """ insead of ''' \$\endgroup\$ Commented Apr 23, 2020 at 11:47
  • 1
    \$\begingroup\$ @Srivaths Put answers in answer boxes. \$\endgroup\$ Commented Apr 23, 2020 at 11:52
  • 1
    \$\begingroup\$ I could only think of one point, so I just added a comment, but I'll write a detailed answer now. \$\endgroup\$ Commented Apr 23, 2020 at 11:54

1 Answer 1

2
\$\begingroup\$
  • The variable names in change_char_at are terrible. s for the string, ch for the char? i for the start? j for the end.

    Seriously just write out names.

    def change_char_at(string: str, change: str, start: int, end: int = None):
        return string[:start] + change + string[end or start+1:]
    
  • Your code isn't fully typed:

    • change_char_at has no return type.
    • end in change_char_at and wait in loader_with_wait are assumed to be Optional but not specified to be optional.
    • loader and loader_with_wait have no return types should they be None or NoReturn?
  • The functionallity of change_char_at can be eclipsed by the format mini-language.

    1. You have a standard structure where the bar is surrounded by [] and filled with the contents.

      bar = '[{}]'
      
    2. The content of your bar is left aligned by width.

      bar = '[{: <{width}}]'
      
    3. Each iteration you increase the left hand space by 1.

      bar.format(' ' * i + '=' * bar_width, width=width)
      
  • bar_width doesn't actually change the size of the bar.

  • I would prefer the progress bar to be a generator function or list, so the rest of your code is simpler.
import itertools


def progress_bar(width: int = 20, bar_width: int = 3):
    bar = f'[{{: <{width}}}]'
    for i in itertools.chain(
        range(0, width - bar_width + 1),
        reversed(range(0, width - bar_width)),
    ):
        yield bar.format(' ' * i + '=' * bar_width)
\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.