pytb.itertools module

Flexibly test a number possible configurations of a function

Assume you have a function that takes a number of parameters:

>>> def my_func(a, b, c=2, **kwargs):
...    print(' '.join((a, b, c)), kwargs)

And you want to call it with multiple parameter combinations

>>> my_params = {
...     'a': 'a1',
...     'b': ('b1','b2'),
...     'c': ('c1', 'c2'),
...     'additional_arg': 'val'
... }

You can use the named_tuple() function of this module to create any possible combination of the provided parameters

>>> for params in named_product(my_params):
...     my_func(**params)
a1 b1 c1 {'additional_arg': 'val'}
a1 b1 c2 {'additional_arg': 'val'}
a1 b2 c1 {'additional_arg': 'val'}
a1 b2 c2 {'additional_arg': 'val'}

Excluding some combinations

If some parameter combinations are not allowed, you can use the functions ability to work with nested dicts to overwrite values defined in an outer dict

>>> my_params = {
...     'a': 'a1',
...     'b': ('b1','b2'),
...     'c': {
...         'c1': {'b': 'b1'},
...         'c2': {},
...         'c3': {
...             'additional_arg': 'other val',
...             'another arg': 'yet another val'}
...     },
...     'additional_arg': 'val'
... }
>>> for params in named_product(my_params):
...     my_func(**params)
a1 b1 c1 {'additional_arg': 'val'}
a1 b1 c2 {'additional_arg': 'val'}
a1 b2 c2 {'additional_arg': 'val'}
a1 b1 c3 {'additional_arg': 'other val', 'another arg': 'yet another val'}
a1 b2 c3 {'additional_arg': 'other val', 'another arg': 'yet another val'}

Note that for c='c1' only b='b1' was used. You can also define new variables inside each dict that only get used for combinations in this branch.

API Documentation

Methods to work with iterables conveniently. (methods that could be in the python stdlib itertools package)

pytb.itertools.named_product(values: Optional[Mapping[Any, Any]] = None, repeat: int = 1, **kwargs) → Generator[Any, None, None][source]

Return each possible combination of the input parameters (cartesian product), thus this provides the same basic functionality of :meth:itertools.product. However this method provides more flexibility as it:

  1. returns dicts instead of tuples
>>> list(named_product(a=('X', 'Y'), b=(1, 2)))
[{'a': 'X', 'b': 1}, {'a': 'X', 'b': 2}, {'a': 'Y', 'b': 1}, {'a': 'Y', 'b': 2}]
  1. accepts either a dict or kwargs
>>> list(named_product({ 'a':('X', 'Y') }, b=(1, 2)))
[{'a': 'X', 'b': 1}, {'a': 'X', 'b': 2}, {'a': 'Y', 'b': 1}, {'a': 'Y', 'b': 2}]
  1. accepts nested dicts
>>> list(named_product(
...     a=(
...             {'X': {'b':(1,2)}},
...             {'Y': {
...                     'b': (3, 4),
...                     'c': (5, )
...                   }
...             }
...     )
... ))
[{'a': {'X': {'b': (1, 2)}}}, {'a': {'Y': {'b': (3, 4), 'c': (5,)}}}]
  1. accepts scalar values
>>> list(named_product(b='Xy', c=('a', 'b')))
[{'b': 'Xy', 'c': 'a'}, {'b': 'Xy', 'c': 'b'}]
Parameters:
  • values – a dict of iterables used to create the cartesian product
  • repeat – repeat iteration of the product N-times
  • **kwargs – optional keyword arguments. The dict of keyword arguments is merged with the values dict, with kwargs overwriting values in values