python contextmanagers, subprocesses, and an ascii spinner

I have a command line script that takes too long to run. I profiled the script and the problem is in some fairly complex third-party code. So instead of fixing that stuff, I’m going to distract users with a pretty ascii spinner.

Run this script to see the spinner in action (you’ll have to kill the process afterward):

$ cat spin_forever.py
# vim: set expandtab ts=4 sw=4 filetype=python:

import sys, time

def draw_ascii_spinner(delay=0.2):
for char in '/-\\\\|': # there should be a backslash in here.
sys.stdout.write(char)
sys.stdout.flush()
time.sleep(delay)
sys.stdout.write('\\\\r') # this should be backslash r.

while "forever":
draw_ascii_spinner()

Next I made a context manager (this is the name of the things you use with the new python “with” keyword) that uses the subprocess module to fork off another process to run the spinner:

$ cat distraction.py
# vim: set expandtab ts=4 sw=4 filetype=python:

import contextlib, subprocess, time

@contextlib.contextmanager
def spinning_distraction():
p = subprocess.Popen(['python', 'spin_forever.py'])
yield
p.terminate()

Finally I added my new context manager to the code that takes so long to run:

def main():

with spinning_distraction():
time.sleep(3) # pretend this is real work here.

if __name__ == '__main__':
main()

If you’re following along at home, you can run python distraction.py and you’ll see the spinner go until the main application finishes sleeping.

The main thing I don’t like is how I’m using an external file named spin_forever.py. I don’t want to worry about the path to where spin_forever.py lives. I would prefer to use some function defined in a module that I can import.

12 thoughts on “python contextmanagers, subprocesses, and an ascii spinner

  1. I really like your solution! I'm going to rewrite my original one to
    use multiprocessing instead, so that I don't need to worry about the
    path to the external script.

    Matt

  2. Hello all,
    Can sonone tell me that what is the function of ts=4 sw=4 in the below linw of the code.
    I did not know whats the funtion of it.Please help me in this matter.
    # vim: set expandtab ts=4 sw=4 filetype=python:

  3. That line is a comment, so python ignores it. My text editor uses
    that line to set some options. Read up on vim modelines if you are
    really interested.

    The important thing to remember is that python ignores comments, so
    that line has no effect on the program.

  4. I really like your solution! I'm going to rewrite my original one to
    use multiprocessing instead, so that I don't need to worry about the
    path to the external script.

Comments are closed.