printtools

This module implements features for printing additional information and for modifying how information is printed.

Module printtools implements the following members:

  • print_progress() Add print commands time to the given function informing about execution time.

  • progressbar() Print a simple progress bar while processing the given iterable.


hydpy.core.printtools.print_progress(wrapper=None, enabled=None, adapter=None, proxy=<class 'FunctionWrapper'>) None[source]

Add print commands time to the given function informing about execution time.

To show how the print_progress() decorator works, we need to modify the functions used by print_progress() to gain system time information available in module time.

First, we mock the functions strftime() and perf_counter():

>>> import time
>>> from unittest import mock
>>> strftime = time.strftime
>>> perf_counter = time.perf_counter
>>> strftime_mock = mock.MagicMock()
>>> time.strftime = strftime_mock
>>> time.perf_counter = mock.MagicMock()

The mock of strftime() shall respond to two calls, as if the first call to a decorated function occurs at quarter past eight, and the second one two seconds later:

>>> time.strftime.side_effect = "20:15:00", "20:15:02"

The mock of perf_counter() shall respond to four calls, as if the subsequent calls by decorated functions occur at second 1, 3, 4, and 7:

>>> time.perf_counter.side_effect = 1, 3, 4, 7

Now we decorate two test methods. The first one does nothing; the second one only calls the first one:

>>> from hydpy.core.printtools import print_progress
>>> class Test:
...     @print_progress
...     def test1(self):
...         pass
...     @print_progress
...     def test2(self):
...         self.test1()

The first example shows that the output is appropriately indented, that the returned times are at the right place, that the calculated execution the is correct, and that the mock of strftime() received a valid format string:

>>> from hydpy import pub
>>> pub.options.printprogress = True
>>> Test().test2()
method Test.test2 started at 20:15:00
    method Test.test1 started at 20:15:02
        seconds elapsed: 1
    seconds elapsed: 6
>>> strftime_mock.call_args
call('%H:%M:%S')

The second example verifies that resetting the indentation works:

>>> time.strftime.side_effect = "20:15:00", "20:15:02"
>>> time.perf_counter.side_effect = 1, 3, 4, 7
>>> Test().test2()
method Test.test2 started at 20:15:00
    method Test.test1 started at 20:15:02
        seconds elapsed: 1
    seconds elapsed: 6

The last example shows that disabling the printprogress option works as expected:

>>> pub.options.printprogress = False
>>> Test().test2()
>>> time.strftime = strftime
>>> time.perf_counter = perf_counter
hydpy.core.printtools.progressbar(iterable: Iterable[T], length: int = 23) Iterator[T][source]

Print a simple progress bar while processing the given iterable.

Function progressbar() does print the progress bar when option printprogress is activted:

>>> from hydpy import pub
>>> pub.options.printprogress = True

You can pass an iterable object. Say you want to calculate the the sum of all integer values from 1 to 100 and print the progress of the calculation. Using function range, one just has to interpose function progressbar():

>>> from hydpy.core.printtools import progressbar
>>> x_sum = 0
>>> for x in progressbar(range(1, 101)):
...     x_sum += x
    |---------------------|
    ***********************
>>> x_sum
5050

To prevent possible interim print commands from dismembering the status bar, they are delayed until the status bar is complete. For intermediate print outs of each fiftieth calculation, the result looks as follows:

>>> x_sum = 0
>>> for x in progressbar(range(1, 101)):
...     x_sum += x
...     if not x % 50:
...         print(x, x_sum)
    |---------------------|
    ***********************
50 1275
100 5050

The number of characters of the progress bar can be changed:

>>> for i in progressbar(range(100), length=50):
...     continue
    |------------------------------------------------|
    **************************************************

But its maximum number of characters is restricted by the length of the given iterable:

>>> for i in progressbar(range(10), length=50):
...     continue
    |--------|
    **********

The smallest possible progress bar has two characters:

>>> for i in progressbar(range(2)):
...     continue
    ||
    **

For iterables of length one or zero, no progress bar is plottet:

>>> for i in progressbar(range(1)):
...     continue

The same is True when the printprogress option is inactivated:

>>> pub.options.printprogress = False
>>> for i in progressbar(range(100)):
...     continue