Spaces:
Running
Running
| import sys | |
| class Progress(object): | |
| def __init__(self, | |
| first: int = 1, # the initial iteration | |
| last: int = 10, # the final iteration | |
| string: str = 'Processing iteration', # the string prefix that is returned | |
| fraction: bool = True, # whether to output the fraction of things completed | |
| rng: bool = False, # whether to output the range that the iterations span | |
| percent: bool = True, # whether to show percent completion | |
| hash: bool = False, # whether to have a hash bar for progress | |
| hashnum: int = 20, # width of the hash progress bar | |
| endmsg: str = 'DONE', # end message | |
| writeevery: int = 1, # write output every n calls | |
| ): | |
| """ | |
| A progress output object for use when performing a large number of | |
| repititions of the same process and informing the user of progress | |
| is desired. | |
| :param first: The first iteration of the process. | |
| :param last: The last iteration of the process. | |
| :param string: The string prefix that is written (this is usually information about | |
| the process. | |
| :param fraction: Whether the fractional progress should be written in the printed string. e.g. 1/10. | |
| :param rng: Whether the iteration range should be written in the printed string. | |
| e.g. (1-10) | |
| :param percent: Whether the percent progress should be written in the printed string. | |
| e.g. 10.0% | |
| :param hash: Whether a hash-type progress bar should be written in the printed | |
| string. e.g. |##### | Default: False | |
| :param hashnum: If *hashes* is True, this is the width of the hash-type progress bar. | |
| :param endmsg: The message that is printed when the `fin()` method is called. | |
| :param writeevery: Write an output every n calls. This can be used if an iteration is | |
| rapid and printing every output is not particularly useful. | |
| **Examples** | |
| :: | |
| >>> prog = Progress() | |
| >>> prog.write(1) | |
| Processing iteration #1/10 0.0% | |
| >>> prog.write(7) | |
| Processing iteration #7/10 66.7% | |
| >>> for i in range(1,11): | |
| prog.write(i) | |
| prog.fin() | |
| Processing iteration #10/10 100.0% DONE | |
| """ | |
| self.first = first | |
| self.last = last | |
| self.string = string | |
| self.fraction = fraction | |
| self.rng = rng | |
| self.percent = percent | |
| self.hash = hash | |
| self.hashnum = hashnum | |
| self.endmsg = endmsg | |
| self.writeevery = writeevery | |
| self.wr = sys.stdout.write | |
| self.fl = sys.stdout.flush | |
| self.count = 0 | |
| self.strlen = 0 | |
| self.current = 0 # current state | |
| self.spinner = ['|', '/', '-', '\\'] | |
| def __str__(self): | |
| """returns the progress string at the current iteration""" | |
| return self.write(self.current, True) | |
| def __repr__(self): | |
| return f'{self.__class__.__name__}({self.string} {self.first}-{self.last})' | |
| def __getitem__(self, x): | |
| """ | |
| Prints and returns the progress string at iteration x | |
| This accomplishes the same thing as write() | |
| """ | |
| return self.write(x) | |
| def perc(self): | |
| try: | |
| return round( | |
| (float(self.current) - self.first) | |
| / float(self.last - self.first) | |
| * 100., | |
| 1 | |
| ) | |
| except ZeroDivisionError: | |
| return 0. | |
| def write(self, current, suppress=False): | |
| """ | |
| Writes the progress of the iteration | |
| :param current: current iteration | |
| :param suppress: suppress output | |
| :return: formatted output string | |
| """ | |
| self.count += 1 # keep count | |
| if self.writeevery != 1: | |
| # if the counter does not match the write, bail out | |
| if self.count != self.last and self.count % self.writeevery != 0: | |
| return None | |
| self.current = current # saves the current state | |
| string = f'{self.string}' # begin the string | |
| if self.fraction is True: | |
| string += f' #{current - self.first + 1}/{self.last - self.first + 1}' | |
| if self.rng is True: | |
| string += f' ({self.first}-{self.last})' | |
| if self.percent is True: | |
| string += f' {self.perc}%' | |
| if self.hash is True: | |
| string += self.hashes() | |
| # create space filler if output has somehow shrunk below the length of the previous output | |
| if len(string) < self.strlen: | |
| string += ' ' * (self.strlen - len(string)) | |
| self.strlen = len(string) | |
| # does not write string to terminal, instead returns the generated progress string | |
| if suppress is True: | |
| return string | |
| try: | |
| self.wr(f'\r{string}') | |
| # a catch for I/O errors that sometimes pop up for large iteration processes | |
| except ValueError: | |
| pass | |
| return string | |
| def hashes(self): | |
| """generates the hash-type progress bar if called for""" | |
| out = ' |' | |
| num = int(self.perc / 100. * self.hashnum) | |
| out += '#' * num # add completed | |
| if num < self.hashnum: # add spinner | |
| out += self.spinner[self.count % 4] | |
| out += ' ' * (self.hashnum - len(out) + 2) # add still to go | |
| out += '|' | |
| return out | |
| def fin(self, msg=None): | |
| """ | |
| writes the completion message of the object and starts a new line | |
| if msg is specified, that message will be written instead of the object's | |
| completion message | |
| """ | |
| if msg is None: | |
| msg = self.endmsg | |
| self.wr(f' {msg}\n') | |
| self.fl() # flush output | |
| if __name__ == '__main__': # for testing and troubleshooting | |
| first = 1 | |
| finish = 255 | |
| prog = Progress( | |
| first=first, | |
| last=finish, | |
| # hashes = True, | |
| ) | |
| import time | |
| for i in range(first, finish + 1): | |
| prog.write(i) | |
| time.sleep(0.01) | |
| prog.fin() | |