chriskiehl / Gooey

Turn (almost) any Python command line program into a full GUI application with one line
MIT License
20.63k stars 1.02k forks source link

Multi-step progress bar with time remaining - how to reset on each step #719

Closed chrisw-thomas closed 2 years ago

chrisw-thomas commented 3 years ago

Hi - converting several of my command-line tools to use Gooey... in most cases I only need a single progress bar.

With one I do several processing steps and would like to have a progress bar for each that shows the elapsed time and time remaining - i.e. a combination of example_progress_bar_3.py and example_progress_bar_4.py

I've tried various things but cannot get the progress bar to reset between steps - pretty sure I'm doing something dumb.

I can see from example_progress_bar_4.py that a value of -1 issues a reset "pulse" but when I try and add this into example_progress_bar_3.py it doesn't work. I've also combined the regex from example 3 into example 4.

Is what I'm trying to do supported?

Thanks.

chriskiehl commented 3 years ago

Could you share some code? I can probably point you in the right direction with a small example demonstrating the problem.

That progress bar will mirror whatever progress regex/expression picks up from the output. So resetting it back to zero should be as easy as what you see in example_progress_bar_4.py

chrisw-thomas commented 3 years ago

Gooey==1.0.8.1

Thanks for the prompt response.

Just to clarify - the graphical visualisation appears to reset OK... i.e. the green animation reaches the right-hand side and then resets to growing from the left-hand side after the reset.

What doesn't change are the numbers... so having created a combination of example_progress_bar_4 and example_time_remaining to have two ~20 second activity phases I end up with a final elapsed time of ~40s, whereas I want each phase of activity to be shown independently.

I updated the definition of progress_regex so that it would accept negative numbers for current and total ... otherwise the progress bar didn't recognise the text being printed and just showed it in the status area.

I then experimented with various value combinations for current and total - i.e. 1/1, -1/1, 1/-1, -1/-1 as well as -1/100.

The code for updateProgressBar checks for progress < 0 so I also tweaked the definition of progress_expr to do the * 100 first before doing the / total to make sure there was nothing funny happening with the calculation.

I think one part of the reset is taking place... the animated bar... but not the numbers.

Also, while I'm here, the output is of the form MM:SS<MM:SS - will it handle elapsed times in hours - i.e. HH:MM:SS? And is there a way to customise the message to something like Elapsed: MM:SS, Remaining: MM:SS?

Example code below:

`from future import unicode_literals from future import print_function

import sys import os

from time import sleep from random import randint from gooey import Gooey, GooeyParser

@Gooey(optional_cols=2, program_name="Elapsed / Remaining Timer on Progress in Gooey", progress_regex=r"^progress: (?P-?\d+)\/(?P-?\d+)$", progress_expr="current * 100 / total", hide_progress_msg=True, timing_options={ 'show_time_remaining':True, 'hide_time_remaining_on_complete':True } ) def parse_args(): prog_descrip = "Elapsed / Remaining Timer on Progress in Gooey" parser = GooeyParser(description=prog_descrip)

sub_parsers = parser.add_subparsers(help='commands', dest='command')

range_parser = sub_parsers.add_parser('range')

range_parser.add_argument('--length',default=10)

return parser.parse_args()

def compute_range(length): print("Start of phase 1")

for i in range(length):

    sleep(randint(1,3))
    print(f"progress: {i}/{length}")

#print("progress: {-1}/{-1}")   # pulse
#print("progress: {1}/{-1}")    # pulse
#print("progress: {-1}/{1}")    # pulse
print(f"progress: {-1}/{100}")  # pulse

sys.stdout.flush()

print("End of phase 1")
sys.stdout.flush()
sleep(2)

print("Start of phase 2")

for i in range(length):
    sleep(randint(1,3))
    print(f"progress: {i}/{length}")

print("End of phase 2")
sys.stdout.flush()

if name == 'main': conf = parse_args() if conf.command == 'range': compute_range(int(conf.length))`

chriskiehl commented 3 years ago

I've read your comment a few times, but I'm not totally sure I follow what you're saying. It sounds like there may be a misunderstanding in how the progress regex and calculations work together. For instance, in your sample code, you're trying to compute an expression using terms which aren't matched as groups in your progress_regex.

will it handle elapsed times in hours - i.e. HH:MM:SS? And is there a way to customise the message to something like Elapsed: MM:SS, Remaining: MM:SS?

Based on this question, my hunch is that you may be over estimating what Gooey does and where the logic for computing progress actually lives. The answer to "can it customize the message" is 100% yes. Why? Because the messages come from your code. Gooey just reads your stdout and, if it happens to find something that looks like a progress message (as specified by the progress_regex), it'll interpret it as such and update the progress bar.

So, you could match an output such as HH:MM:SS with the following regex.

progress_regex=r'^.*?(?P<hours>\d{2}):(?P<minutes>\d{2}):(?P<seconds>\d{2})$'

That would match things like "Time remaining: 00:02:10"

However, in order to update the progress bar, it has to be possible to evaluate the output to some percentage. Meaning, just matching the current time isn't enough, as you need to know what that time means relative to some final target time such that you could turn it into a percentage.

I'm not sure if I'm helping or not, but hopefully that bit of background may point you in the right direction.