Search code examples
pythonprogress-bartqdm

Python ProgressBar tqdm


I want to have a progressBar wrapper object from the tqdm object which is disabled by default and can be enabled by condition. Furthermore it should work in console and jupyter notebook/lab/ipython. Therefore tqdm has a auto detection. I wrote a class:

class ProgressBar(object):
    import time
    import numpy as np
    from tqdm import tnrange
    from tqdm.auto import tqdm
    def __init__(self,maxValue,minValue=0):
        self.minValue=minValue
        self.maxValue=maxValue
        self.progressBar = self.createProgressBar()
    def updateBar(self,updatedValue):
        self.progressBar.update(updatedValue)
    def createProgressBar(self):
        bar = tqdm(total=self.maxValue,desc='Loading:',disable=True)
        return bar

But if i want to have access to the bar

a = ProgressBar(1000)
a.progressBar.disable=False
while True:
    fileEvaluated = np.random.randint(4,size=1)[0]
    a.updateBar(fileEvaluated)
    time.sleep(0.5)

i get an error message:

AttributeError: 'tqdm_notebook' object has no attribute 'sp'

Any idea what im doing wrong?


Solution

  • I would do something like the following, which was tested and works on Python 3.7 Windows.

    One of the reasons it probably was not working for you is that you were disabling the progress bar bar = tqdm(total=self.maxValue,desc='Loading:',disable=True)but then you tried enabling it with a.progressBar.disable=False but the class you made does not contain a disable attribute.

    In order to wrap it around something it needs to be an iterable as shown in the code I posted. You probably don't need the time.sleep() code, I just put it there so you can see the progress bar in action, otherwise it would finish too quickly.

    Also it is typically not a good idea to put import statements inside a class. If your module will always import another module, imports should be placed at the very top according to PEP 8.

    EDIT: If you only want the progress bar to run after some condition then place the update() call nested after a conditional as shown below.

    from tqdm import tqdm
    import time
    
    
    class ProgressBar(object):  # Python3+ '(object)' can be omitted
        def __init__(self, max_value, disable=True):
            self.max_value = max_value
            self.disable = disable
            self.p = self.pbar()
    
        def pbar(self):
            return tqdm(
                total=self.max_value,
                desc='Loading: ',
                disable=self.disable
            )
    
        def update(self, update_value):
            self.p.update(update_value)
    
        def close(self):
            self.p.close()
    
    
    max_val = 1000
    some_condition = True
    
    p = ProgressBar(max_value=max_val, disable=False)
    
    if some_condition:
        for i in range(max_val):
            time.sleep(0.01)
            p.update(1)
        p.close()
    

    You can also do the same thing as above but without making your own class and shorten the amount of code.

    from tqdm import tqdm
    import time
    
    max_val = 1000
    some_condition = True
    
    p = tqdm(total=max_val, disable=False)
    
    if some_condition:
        for i in range(max_val):
            time.sleep(0.01)
            p.update(1)
        p.close()