Tqdm: Show progress bar for long-running function without loop

Created on 3 Oct 2017  Â·  4Comments  Â·  Source: tqdm/tqdm

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')

p4-enhancement-future 🧨 questiodocs ‽

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.

#/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

All 4 comments

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

Was this page helpful?
0 / 5 - 0 ratings

Related issues

demiangomez picture demiangomez  Â·  4Comments

lrq3000 picture lrq3000  Â·  5Comments

andreasbaumann picture andreasbaumann  Â·  5Comments

phillies picture phillies  Â·  3Comments

sergeysprogis picture sergeysprogis  Â·  4Comments