ampworks.utils#

The utilities module provides a collection of helper functions and classes to simplify common tasks, such as timing specific portions of code, printing progress bars in the console, and more.

Classes#

ProgressBar

Progress bar.

RichResult

Dict-like results container.

RichTable

DataFrame-like results container.

Timer

Timer utility.

Functions#

alphanum_sort(unsorted[, reverse])

Sort a list alphanumerically.

Package Contents#

class ampworks.utils.ProgressBar(iterable=None, manual=False, desc=None, ncols=80, total=None, **kwargs)[source]#

Progress bar.

Wraps the progress bar from tqdm, with different defaults. Also enables a custom “manual” mode in which the user manually sets the progress as a fraction in [0, 1] using set_progress.

Parameters:
  • iterable (Iterable, optional) – The iterable to use to construct the “automatic” progress bar, by default None. ‘manual’ must be False if ‘iterable’ is not None.

  • manual (bool, optional) – True enables a “manual” mode progress bar, allowing manual updates via ‘set_progress’. If False (default), ‘iterable’ cannot be None.

  • desc (str, optional) – Prefix description, by default None.

  • ncols (int, optional) – Terminal column width, by default 80. The special case of zero will display limited stats and time, with no progress bar.

  • total (int, optional) – Number of expected iterations. Use when ‘iterable’ is a generator, otherwise estimated remaining time and the printed bar are skipped.

  • **kwargs (dict, optional) – Additional keyword arguments to pass through to tqdm.

Raises:

ValueError – Provide exactly one of ‘iterable’ or ‘manual’, not both.

Examples

The examples below demonstrate the two uses of the ProgressBar class: the “automatic” mode with an iterable, and the “manual” mode with custom progress updates. As demonstrated, the set_progress method should be called once per “iteration” in the “manual” mode, and that the instance should be closed when finished.

import time

from ampworks.utils import ProgressBar

# Automatic mode with an iterable
for i in ProgressBar(range(5), desc='Iterable'):
    time.sleep(0.5)

# Manual mode with custom progress updates
progbar = ProgressBar(manual=True, desc='Manual')

for i in range(5):
    time.sleep(0.5)
    progbar.set_progress((i + 1) / 5)

progbar.close()
close()[source]#

Closes the progress bar and releases resources. Should be called when finished with the progress bar, especially in manual mode.

reset()[source]#

Resets the iteration count to zero for repeated use. Only works for manual mode. For iterables you will need to create a new instance.

set_progress(progress)[source]#

Updates the progress bar percentage and increments the tracked total number of iterations for the “manual” mode. Should be called once per “iteration”, based on the user’s definition of an iteration.

Parameters:

progress (float) – Progress fraction in [0, 1].

class ampworks.utils.RichResult(**kwargs)[source]#

Dict-like results container.

A container class based off the _RichResult class in the scipy library. It combines a series of formatting functions to make the printed ‘repr’ easy to read. Use this class directly by passing in any number of keyword arguments, or use it as a base class to have custom classes for different result types.

Inheriting classes should define the class attribute _order_keys which is a list of strings that defines how output fields are sorted when an instance is printed.

Parameters:

**kwargs (dict, optional) – User-specified keyword arguments. Any number of arguments can be given as input. The class simply stores the key/value pairs, makes them accessible as attributes, and provides pretty printing.

Examples

The example below demonstrates how to define the _order_keys class attribute for custom sorting. If arguments are not in the list, they are placed at the end based on the order they were given. Note that _order_keys only provides sorting support and that no errors are raised if an argument is not present, e.g., third below.

from ampworks.utils import RichResult

class CustomResult(RichResult):
    _order_keys = ['first', 'second', 'third',]

result = CustomResult(second=None, last=None, first=None)

print(result)

RichResult can also be used directly, without any custom sorting. Arguments will print based on the order they were input. Instances will still have a fully formatted ‘repr’, including formatted arrays.

import numpy as np

from ampworks.utils import RichResult

t = np.linspace(0, 1, 1000)
y = np.random.rand(1000, 5)

y[0] = np.inf
y[-1] = np.nan

result = RichResult(message='Example.', status=0, t=t, y=y)

print(result)

After initialization, all key/value pairs are accessible as instance attributes.

from ampworks.utils import RichResult

result = RichResult(a=10, b=20, c=30)

print(result.a*(result.b + result.c))
copy()[source]#

Returns a copy of the instance.

Returns:

result (Self) – A deep copy of the current instance. Does not share any memory with the original instance.

class ampworks.utils.RichTable(df)[source]#

DataFrame-like results container.

Provides a structured way to store data using a pd.DataFrame with additional validation and formatting features. Use this class directly by passing in a pd.DataFrame, or subclass it to define custom containers with required columns.

Inheriting classes should define the class attribute _required_cols which is a list of column names that must be present in the input. If any are missing, initialization will raise a ValueError.

Parameters:

df (pd.DataFrame) – The input dataframe to store. Columns are validated against the _required_cols attribute and then stored.

Notes

While this container is meant to act as a simplified dataframe, access to the full pd.DataFrame is provided via the df property. While the entire dataframe cannot be replaced, it can be manipulated in place through this property.

Examples

A minimal example using RichTable directly:

import pandas as pd

from ampworks.utils import RichTable

df = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]})
table = RichTable(df)

print(table)

Subclassing to enforce required columns:

import pandas as pd

from ampworks.utils import RichTable

class CustomTable(RichTable):
    _required_cols = ['Seconds', 'Volts']

df = pd.DataFrame({'Seconds': [0, 1], 'Volts': [3.8, 3.7]})
table = CustomTable(df)  # valid, no errors raised
copy()[source]#

Returns a copy of the instance.

Returns:

table (Self) – A deep copy of the instance. Does not share memory with original.

classmethod from_csv(path)[source]#

Create a new instance from a CSV file.

Parameters:

path (str or Path) – Path to the CSV file.

Returns:

table (Self) – A new instance initialized with data from the file.

to_csv(path)[source]#

Write the table to a CSV file.

Parameters:

path (str or Path) – Path to the output file.

property df: pandas.DataFrame#

The underlying DataFrame stored in the container.

class ampworks.utils.Timer(name='Elapsed time', units='s', display=True)[source]#

Timer utility.

Measures elapsed time for a series of steps and prints results to the console. Initialize with a name to tell what steps each print statement is associated with when timing multiple blocks. Also has control to print in different units of time.

Parameters:
  • name (str, optional) – Code block name used in print. The default is ‘Elapsed time’.

  • units (str, optional) – Printing units, from {‘s’, ‘min’, ‘h’}. The default is ‘s’.

  • display (bool, optional) – Whether to print the elapsed time when exiting a context block. The default is True.

Notes

If you want to print in multiple units, you can call print_elapsed() directly after exiting a context block. If your units are not seconds, minutes, or hours, you can also perform your own conversion using the elapsed_time property, which always returns seconds.

A timer can be reused for multiple context blocks if desired, but the elapsed_time property will only return the most recent elapsed time because each time you enter a context block the start time is reset. So, make sure to print or store intermediate values if you want to keep track of multiple context blocks with a single timer.

Examples

The Timer works as a context manager and is accessed using with blocks. For example:

import time

from ampworks.utils import Timer

def function(sleep_time: float) -> None:
    time.sleep(sleep_time)

with Timer():
    function(2.)

If you want to silence the print statement and just store the elapsed time, set display=False and access the elapsed_time property:

with Timer(display=False) as timer:
    function(2.)

print(f"Elapsed time: {timer.elapsed_time:.5f} s")
print_elapsed(units='s')[source]#

Print the elapsed time.

Parameters:

units (str, optional) – Printing units, from {‘s’, ‘min’, ‘h’}. The default is ‘s’.

property elapsed_time: float#

Return the elapsed time in seconds.

Returns:

elapsed (float) – Time difference between entering and exiting a ‘with’ block. Will return zero if it has not yet been used.

ampworks.utils.alphanum_sort(unsorted, reverse=False)[source]#

Sort a list alphanumerically.

This sorting function ensures that numerical substrings are compared based on their integer values. For example, “item2” comes before “item10”, unlike standard string sorting where “item10” would come before “item2”.

Parameters:
  • unsorted (list[str]) – Original unsorted list of strings.

  • reverse (bool, optional) – Flag to reverse the sorted list. The default is False.

Returns:

sorted (list[str]) – An alphanumerically sorted list of strings.