python-progressbar icon indicating copy to clipboard operation
python-progressbar copied to clipboard

FormatCustomText not updated

Open wabiloo opened this issue 3 years ago • 2 comments

Description

I've modified the format_custom_text example to use a with... as... context. The progress bar does not update when I do that, and I can't quite figure out why

Code

def format_custom_text():
    format_custom_text = progressbar.FormatCustomText(
        'Spam: %(spam).1f kg, eggs: %(eggs)d',
        dict(
            spam=0.25,
            eggs=3,
        ),
    )

    with progressbar.ProgressBar(widgets=[
        format_custom_text,
        ' :: ',
        progressbar.Percentage(),
    ]).start() as bar:
        for i in range(25):
            format_custom_text.update_mapping(eggs=i * 2)
            time.sleep(0.1)

The output only updates at the end, to show:

Spam: 0.2 kg, eggs: 48 :: N/A%

I also tried with adding a bar.update() after the last line within the loop, but with no success

Versions

  • Python version: 3.9
  • Operating System: Mac OS X
  • Package version: 4.0.0

wabiloo avatar Feb 01 '22 11:02 wabiloo

I've also tried:

    format_custom_text = progressbar.FormatCustomText(
        'Spam: %(spam).1f kg, eggs: %(eggs)d',
        dict(
            spam=0.25,
            eggs=3,
        ),
    )

    bar = progressbar.ProgressBar(widgets=[format_custom_text])
    bar.start()
    for i in range(25):
        format_custom_text.update_mapping(eggs=i * 2)
        time.sleep(0.1)
        bar.update(i)

wabiloo avatar Feb 01 '22 11:02 wabiloo

The issue is that the progressbar is optimized for speed and it doesn't notice a big enough change.

By default it will update either:

  • When the update would be visible in a bar (i.e. on a 80 character screen, if 1 character has changed)
  • when a timed widget has reached its update interval

Note that a bar needs a maximum value to be able to calculate the width so the progressbar cannot know this in your case as you haven't specified the maximum value. Since neither of those widgets is timed, that isn't an option either.

Luckily, we have a simple workaround for this, just tell the progressbar to update every 0.1 second (or more often if you wish):

import time
import progressbar

format_custom_text = progressbar.FormatCustomText(
    'Spam: %(spam).1f kg, eggs: %(eggs)d',
    dict(
        spam=0.25,
        eggs=3,
    ),
)

with progressbar.ProgressBar(
    poll_interval=0.1,
    widgets=[
        format_custom_text,
        ' :: ',
        progressbar.Percentage(),
    ],
) as bar:
    for i in bar(range(25)):
        format_custom_text.update_mapping(eggs=i * 2)
        time.sleep(0.1)

wolph avatar Feb 01 '22 15:02 wolph