Getting started

How to use the progression package will be demonstrated in the following examples. If you are solely interested usage it should suffice to go through the following. If you are searching for the actual doc look here.

The function to monitor

Let’s use factorial as an example function.

def factorial(N, c):
    f = 1
    for i in range(2, N+1):   # becasue the multiplication of two
        f *= i                # integers is faster than
        if i % 1000 == 0:     # settings the value of an sharedctype
            c.value = i       # c gets updated only every 1000 steps
    return f

Any function that is supposed to be monitored by one of the classes of the progression package needs to have at least one argument that serves as a counter (for factorial denoted by c). It needs to be a sharedctype because one the one hand factorial is going to change its value according to its state and the progress class (which runs in a subprocess) needs to access this value. For convenience progression provides progression.progress.UnsignedIntValue() which instantiates a shared unsigned int with value 0.

ProgressBar

Let’s use progress.ProgressBar to monitor the calculation.

In general the following steps are necessary:

  1. setup the shared value for the counter

  2. create a ProgressBar

    • count: the shared counter
    • max_count: the maximum value counter will reach
    • interval: the refresh interval in seconds

    using the context manager ensures that everything gets shutdown on exit

  3. start the ProgressBar via start()

  4. trigger the calculation where c is passed to the calculating function

def run_example_ProgressBar():
    import progression as pr
    N = 200000
    c = pr.UnsignedIntValue()            # counter for factorial
    with pr.ProgressBar(count     = c,   # (shared uint)
                        max_count = N,
                        interval  = 0.3  # the refresh time in secs.
                                         # the default is 1s
                        ) as pb:
        pb.start()                       # start progress process
        factorial(N, c)                  # doing stuff and

The output will look like this (here without colors):

2.41s [39078.4c/s] [=================>                    ] TTG 3.00s

  ^            ^                                                ^
elapsed time   speed estimation in counts per second       time to go

ProgressBarFancy

Now we use ProgressBarFancy which provides slightly more information.

Further the example shows how to use a shared type for the maximum value of counter, which allows to set max_count after the ProgressPar has started, even by the calculating function.

def run_example_ProgressBarFancy():
    import progression as pr
    N = 200000
    c = pr.UnsignedIntValue()        # counter (shared uint)
    m = pr.UnsignedIntValue()        # the maximum value for
                                     # counter, now also shared
    with pr.ProgressBarFancy(count = c, max_count = m) as pb:
        pb.start()
        m.value = N                  # set the max_count at runtime
        factorial(N, c)

The output reads something like this:

[TET-2s-[42877.4c/s]-TTG-3s--> 43.0%  ETA 20161008_14:04:31 ORT 5s]

TET: total elapsed time
TTG: time to go
ETA: estimated time of arrival
ORT: estimated overall running time

ProgressBar Decorator

To quickly add a ProgressBar to an existing function the decorators from the progression.decorators module ease things.

Modification of the original factorial function as follows

def factorial_dec(N,
                  c = pr.UnsignedIntValue(),
                  m = pr.UnsignedIntValue()):
    # for the decorator to work the function needs to have
    # 'c' and 'm' as arguments
    # when using default values for 'c' and 'm' the
    # function call remains the same
    m.value = N
    f = 1
    for i in range(2,N+1):
        f *= i
        if i % 1000 == 0:
            c.value = i
    return f

and decorating this function with

@pr.decorators.ProgressBar

allows for a call as in the unmonitored case

factorial_dec(N = 200000)

resulting in the following output

factorial_dec 1.01s [61584.8c/s] [=====>    ] TTG 3.00s

ProgressBar with no max_count value

When the max_count argument of the ProgressBar is None only the elapsed time, the current speed and the value of count will be shown.

def run_example_max_count_is_none():
    import progression as pr
    c = pr.UnsignedIntValue()             # counter (shared uint)
    with pr.ProgressBar(count     = c,
                        max_count = None  # no maximum value of count
                                          # known
                        ) as pb:
        pb.start()
        factorial(100000, c)
2.47s [38535.8c/s] #95000

ProgressBarCounter

Suppose we want to let a time consuming function run several times for example with different parameters. Then the ProgressBarCounter class counts the individual runs and estimates the speed concerning the runs. Everything on top of the usual monitoring.

For doing so choose ProgressBarCounter or ProgressBarFancyCounter and trigger reset() every time the functions returns.

def run_example_ProgressBarCounter():
    import progression as pr
    import time

    c = pr.UnsignedIntValue()       # ... the usual set up
    with pr.ProgressBarCounter(count     = c,
                               max_count = 10) as pb:
        pb.start()
        for outer_loop in [1,3,5]:        # lets crunsh the
                                          # innerloop 3 times

            for iner_loop in range(1,11): # change the counter
                c.value = iner_loop       # according to the state
                time.sleep(0.3)           # of the inner loop

            pb.reset()                    # reset the ProgressBar
7.76s [20.0c/min] #2 - 1.75s [3.4c/s] [========>       ] TTG 2.00s
  ^       ^        ^      ^       ^                            ^
  1       2        3      4       5                            6

1) total elapsed time
2) speed of the 'resets'
3) number of 'resets'
4) elapsed time of current run
5) speed of the current run
6) time to go for the current run

A multi ProgressBarFancy

When monitoring several processes in parallel simply replace count and max_count by lists of sharedctypes.

def run_example_ProgressBarFancy_multi():
    import progression as pr
    import random
    import time

    def tocrunch(c, m):
        for x in range(400):
            i = random.randint(0, n - 1)
            with c[i].get_lock():        # as += operator is not
                c[i].value += 1          # atomic we need a lock
                                         # see docs.python.org
                                         # -> shared-ctypes-objects
            if c[i].value > m[i].value:  # once max_count is reached
                sbm.reset(i)             # reset the bar
            time.sleep(0.01)


    n = 4
    max_count_value = 25

    count = []          # list of shared uint
    max_count = []      # list of shared uint
    prepend = []        # list of text to prepend each bar
    for i in range(n):  # fill the lists
        count.append(pr.UnsignedIntValue(0))
        max_count.append(pr.UnsignedIntValue(max_count_value))
        prepend.append('_{}_:'.format(i + 1))

    # note: count and max_count are now lists of scharedctypes
    with pr.ProgressBarFancy(count     = count,
                             max_count = max_count,
                             interval  = 0.3,
                             prepend   = prepend,
                             width     = 60) as sbm:
        sbm.start()
        tocrunch(count, max_count)
_1_:[E-589.07ms----[20.1c/s]-G-1.00s        44.0%         O 1.59s]
_2_:[E-906.49ms----[19.7c/s]-G-1.00s--------68.0%>        O 1.91s]
_3_:[E-947.64ms----[20.0c/s]-G-1.00s--------76.0%------>  O 1.95s]
_4_:[E-160.46ms--->[31.2c/s] G 1.00s        20.0%         O 1.16s]

ProgressBar and IPython notebook

Running any kind of ProgressBar in an IPython notebook will result in new lines for each status message as moving the cursor is not supported. This problem can be circumvented by selecting a special PipeHandler.

progression.choose_pipe_handler('ipythonhtml')

Doing so will forward the output from ProgressBar (any subclass of Loop) to an ipywidget HTML object. Such an object will be created and displayed whenever a ProgressBar gets started. The terminal style and coloring is converted to pure HTML.

_1_:[E-588.75ms----[23.8c/s]-G-1.00s--> 56.0% O 1.59s] _2_:[E-907.35ms----[17.6c/s]-G-1.00s-----64.0% O 1.91s] _3_:[E-161.35ms [12.4c/s] G 2.00s 8.0% O 2.16s] _4_:[E-183.51ms [21.8c/s] G 1.00s 16.0% O 1.18s]