verigak / progress

Easy to use progress bars for Python
ISC License
1.41k stars 179 forks source link

Type of Bar based on infinite, or show counts on spinners #97

Open danizen opened 3 years ago

danizen commented 3 years ago

I use this package to show progress on processing large MARC file processing tasks (see http://loc.gov/marc/bibliographic/). We have 1.6 million MARC records, and we do not know how many will change each day. Sometimes, there are large automatic changes. I really appreciate it being around.

However, when I don't know how many MARC records there are in the file, I still want to show how many have been processed. This is because the program may not know the # of records in the file, but I may have received the number via email from the library processing software.

        if args.progress:
            if (count % 100) == 0:
                print('.', end='')
                sys.stdout.flush()
            if (count % 6000) == 0:
                print('{:>8d}'.format(count))

Other scripts are fast enough that I just use a spinner:

        spinner = Spinner() if args.progress else None
        # for main loop:
            spinner and (count % 100) == 0 and spinner.next()

What I'd really like is a spinner that shows a count or a way to roll the infinite bar pattern I've developed into progress.

verigak commented 3 years ago

In version 1.6 that I just released you can use the index in spinners. e.g. Spinner(' %(index)d'). Does that work for you?

danizen commented 2 years ago

Wow, I missed your update. It helps, but it isn't enough. Blocking the output of a line based on a number of chunks to save performance when showing progress is what I have in mind. Here's the subclass I just wrote that illustrates what I am thinking of:

class DotsProgress(Progress):
    def __init__(self, dot='.', width=60, chunk_size=1, **kwargs):
        super().__init__(**kwargs)
        self.dot = dot
        self.width = int(width)
        self.chunk_size = int(chunk_size)

    def next(self, n=1):
        self.index = self.index + n
        # only output if a tty
        if self.file and self.is_tty():
            # only output on a completed chunk
            if (self.index % self.chunk_size) == 0:
                self.file.write(self.dot)
                num_chunks = self.index // self.chunk_size
                if (num_chunks % self.width) == 0:
                    self.file.write(f' {self.index:10d}\n')
                self.file.flush()

    def finish(self):
        # only output if a tty
        if self.file and self.is_tty():
            num_chunks = self.index // self.chunk_size
            # only output if not at end of line
            if (num_chunks % self.width) != 0:
                self.file.write(f' {self.index:10d}\n')

Sample output:

............................................................    1212000
............................................................    1218000
............................................................    1224000
............................................................    1230000
............................................................    1236000
............................................................    1242000
............................................................    1248000
danizen commented 2 years ago

Just finished:

............................................................    1662000
............................................................    1668000
..............    1669411

The above illustrates what I guess I mean by a type of bar based on infinite, and t would be nice to have something like it in the package, but the package still does add so much value even without that.

danizen commented 2 years ago

I will try to submit a pull request without tests to illustrate what I am thinking about later tonight. Feel free to reject, and I can add tests and resubmit once I understand how your tests work. I am a contractor for the feds and my agreement with my boss is that I can file issues on work time, but pull requests, actually fixing things, are not on government time.

This is why I get into the bad habit of providing fixes in comments :)