Question

I'm making a progress indicator for some long-running console process with intent to use it like this:

pi = ProgressIndicator()
for x in somelongstuff:
    do stuff
    pi.update()
pi.print_totals()

Basically, it should output some kind of a progress bar with dots and dashes, and something like "234234 bytes processed" at the end.

I thought it would be nice to use it as a context manager:

with ProgressIndicator() as pi:
    for x in somelongstuff:
       do stuff
       pi.update()

However there are a few things that concern me about this solution:

  • extra indentation makes the indicator feature appear more important than it actually is
  • I don't want ProgressIndicator to handle any exceptions that might occur in the loop

Is this a valid use case for a context manager? What other solutions can you suggest?

Was it helpful?

Solution

It definitely seems a valid use case. The context manager doesn't have to handle exceptions if you don't want it to, although you would want to end the line that the progress bar is output on to prevent it being confused with the traceback, and have it not print the totals if it is exited through an exception.

With regard to indentation, I'd argue that letting the user see progress is actually a very important feature so it's fine for it to take up an indentation level.

OTHER TIPS

There's a GUI application which has a very similar ProgressTask API, which you use like this:

def slow_func():
    t = nuke.ProgressTask()
    t.setMessage("Doing something")
    for x in range(100):
        do_something()
        t.setProgress(x+1)

When ProgressTask.__del__ is called, the progress bar UI disappears. This works nicely for the most part, however if an exception is raised (e.g by do_something()), the traceback object keeps a reference to the ProgressTask object, so the progress-bar gets stuck (until another traceback occurs)

The ProgressTask implemented the context-manager protocol, it could use the __exit__ method to ensure the progress bar has been hidden.

For a command-line UI (which is sounds like you are writing), this may not be an issue, but you could do similar cleanup tasks, e.g to display an ######### 100% (error) type bar, and ensure the traceback output isn't messed up etc

There's no reason your progress-bar class couldn't be usable in both manners - most context-managers are perfectly usable as both regular objects and context-managers, e.g:

lock = threading.Lock()
lock.acquire()
lock.release()
# or:
with lock:
    pass
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top