Sometimes we have long running functions, say from a library we don't control, but an estimated time for it can be provided. Is there a way to show a progress bar for it?
I'm thinking about sth like:
return_value = tqdm(long_running_function(), estimated_time='10s')
This requires some extra work, but I've just created a wrapper function (very much like what you requested) and a decorator.
#/usr/bin/env python3
import time
import threading
import functools
import tqdm
def long_running_function(*args, **kwargs):
# print("Running with args:%s and kwargs:%s" % (args, kwargs))
time.sleep(5)
return "success"
def provide_progress_bar(function, estimated_time, tstep=0.2, tqdm_kwargs={}, args=[], kwargs={}):
"""Tqdm wrapper for a long-running function
args:
function - function to run
estimated_time - how long you expect the function to take
tstep - time delta (seconds) for progress bar updates
tqdm_kwargs - kwargs to construct the progress bar
args - args to pass to the function
kwargs - keyword args to pass to the function
ret:
function(*args, **kwargs)
"""
ret = [None] # Mutable var so the function can store its return value
def myrunner(function, ret, *args, **kwargs):
ret[0] = function(*args, **kwargs)
thread = threading.Thread(target=myrunner, args=(function, ret) + tuple(args), kwargs=kwargs)
pbar = tqdm.tqdm(total=estimated_time, **tqdm_kwargs)
thread.start()
while thread.is_alive():
thread.join(timeout=tstep)
pbar.update(tstep)
pbar.close()
return ret[0]
def progress_wrapped(estimated_time, tstep=0.2, tqdm_kwargs={}):
"""Decorate a function to add a progress bar"""
def real_decorator(function):
@functools.wraps(function)
def wrapper(*args, **kwargs):
return provide_progress_bar(function, estimated_time=estimated_time, tstep=tstep, tqdm_kwargs=tqdm_kwargs, args=args, kwargs=kwargs)
return wrapper
return real_decorator
@progress_wrapped(estimated_time=5)
def another_long_running_function(*args, **kwargs):
# print("Running with args:%s and kwargs:%s" % (args, kwargs))
time.sleep(5)
return "success"
if __name__ == '__main__':
# Basic example
retval = provide_progress_bar(long_running_function, estimated_time=5)
print(retval)
# Full example
retval = provide_progress_bar(long_running_function,
estimated_time=5, tstep=1/5.0,
tqdm_kwargs={"bar_format":'{desc}: {percentage:3.0f}%|{bar}| {n:.1f}/{total:.1f} [{elapsed}<{remaining}]'},
args=(1, "foo"), kwargs={"spam":"eggs"}
)
print(retval)
# Example of using the decorator
retval = another_long_running_function()
print(retval)
https://gist.github.com/duckythescientist/c06d87617b5d6ac1e00a622df760709d
Thanks @duckythescientist , my suggestion would also be a wrapper function or inheritance.
Thank you @duckythescientist, @casperdcl ! Will try that out.
Thanks @duckythescientist , that decorator is amazing
Most helpful comment
This requires some extra work, but I've just created a wrapper function (very much like what you requested) and a decorator.
https://gist.github.com/duckythescientist/c06d87617b5d6ac1e00a622df760709d