Skip to content

iterfilters

Class info

🛈 DocStrings

batched

batched(iterable: Iterable[T], n: int) -> Generator[tuple[T, ...], None, None]

Batch data into tuples of length n. The last batch may be shorter.

Note: this function was added to Py3.12 itertools

Examples:

batched('ABCDEFG', 3)  # returns ABC DEF G

Parameters:

Name Type Description Default
iterable Iterable[T]

The iterable to yield as batches

required
n int

The batch size

required
Source code in src/jinjarope/iterfilters.py
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
def batched(iterable: Iterable[T], n: int) -> Generator[tuple[T, ...], None, None]:
    """Batch data into tuples of length n. The last batch may be shorter.

    Note: this function was added to Py3.12 itertools

    Examples:
        ``` py
        batched('ABCDEFG', 3)  # returns ABC DEF G
        ```

    Args:
        iterable: The iterable to yield as batches
        n: The batch size
    """
    if n < 1:
        msg = "n must be at least one"
        raise ValueError(msg)
    it = iter(iterable)
    while batch := tuple(itertools.islice(it, n)):
        yield batch

chain

chain(*iterables: Iterable[T]) -> chain[T]

Chain all given iterators.

Make an iterator that returns elements from the first iterable until it is exhausted, then proceeds to the next iterable, until all of the iterables are exhausted. Used for treating consecutive sequences as a single sequence.

Examples:

chain('ABC', 'DEF') --> A B C D E F

Args: iterables: The iterables to chain

Source code in src/jinjarope/iterfilters.py
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
def chain(*iterables: Iterable[T]) -> itertools.chain[T]:
    """Chain all given iterators.

    Make an iterator that returns elements from the first iterable until it is
    exhausted, then proceeds to the next iterable, until all of the iterables
    are exhausted. Used for treating consecutive sequences as a single sequence.

    Examples:
        ``` py
        chain('ABC', 'DEF') --> A B C D E F
        ```
    Args:
        iterables: The iterables to chain
    """
    return itertools.chain(*iterables)

do_any

do_any(seq: Iterable[Any], attribute: str | None = None) -> bool

Check if at least one of the item in the sequence evaluates to true.

The any builtin as a filter for Jinja templates.

Parameters:

Name Type Description Default
seq Iterable[Any]

An iterable object.

required
attribute str | None

The attribute name to use on each object of the iterable.

None
Source code in src/jinjarope/iterfilters.py
281
282
283
284
285
286
287
288
289
290
291
292
def do_any(seq: Iterable[Any], attribute: str | None = None) -> bool:
    """Check if at least one of the item in the sequence evaluates to true.

    The `any` builtin as a filter for Jinja templates.

    Args:
        seq: An iterable object.
        attribute: The attribute name to use on each object of the iterable.
    """
    if attribute is None:
        return any(seq)
    return any(getattr(i, attribute) for i in seq)

do_zip

do_zip(*items: Iterable[T]) -> zip[tuple[T, ...]]

Zip iterables into a single one.

Parameters:

Name Type Description Default
items Iterable[T]

The iterables to zip

()
Source code in src/jinjarope/iterfilters.py
139
140
141
142
143
144
145
def do_zip(*items: Iterable[T]) -> zip[tuple[T, ...]]:
    """Zip iterables into a single one.

    Args:
        items: The iterables to zip
    """
    return zip(*items)

flatten_dict

flatten_dict(dct: Mapping, sep: str = '/', _parent_key: str = '') -> Mapping

Flatten a nested dictionary to a flat one.

The individual parts of the "key path" are joined with given separator.

Parameters:

Name Type Description Default
dct Mapping

The dictionary to flatten

required
sep str

The separator to use for joining

'/'
Source code in src/jinjarope/iterfilters.py
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
def flatten_dict(dct: Mapping, sep: str = "/", _parent_key: str = "") -> Mapping:
    """Flatten a nested dictionary to a flat one.

    The individual parts of the "key path" are joined with given separator.

    Args:
        dct: The dictionary to flatten
        sep: The separator to use for joining
    """
    items: list[tuple[str, str]] = []
    for k, v in dct.items():
        new_key = _parent_key + sep + k if _parent_key else k
        if isinstance(v, Mapping):
            flattened = flatten_dict(v, _parent_key=new_key, sep=sep)
            items.extend(flattened.items())
        else:
            items.append((new_key, v))
    return dict(items)

groupby

groupby(
    data: Iterable[T],
    key: Callable[[T], Any] | str | None = None,
    *,
    sort_groups: bool = True,
    natural_sort: bool = False,
    reverse: bool = False
) -> dict[str, list[T]]

Group given iterable using given group function.

Parameters:

Name Type Description Default
data Iterable[T]

Iterable to group

required
key Callable[[T], Any] | str | None

Sort function or attribute name to use for sorting

None
sort_groups bool

Whether to sort the groups

True
natural_sort bool

Whether to use a natural sort algorithm

False
reverse bool

Whether to reverse the value list

False
Source code in src/jinjarope/iterfilters.py
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
def groupby(
    data: Iterable[T],
    key: Callable[[T], Any] | str | None = None,
    *,
    sort_groups: bool = True,
    natural_sort: bool = False,
    reverse: bool = False,
) -> dict[str, list[T]]:
    """Group given iterable using given group function.

    Args:
        data: Iterable to group
        key: Sort function or attribute name to use for sorting
        sort_groups: Whether to sort the groups
        natural_sort: Whether to use a natural sort algorithm
        reverse: Whether to reverse the value list
    """
    if key is None:

        def keyfunc(x):
            return x

    elif isinstance(key, str):
        keyfunc = operator.attrgetter(key)  # pyright: ignore
    else:
        keyfunc = key
    if sort_groups or natural_sort:
        if natural_sort:
            import natsort

            data = natsort.natsorted(data, key=keyfunc)
        else:
            data = sorted(data, key=keyfunc)
    if reverse:
        data = reversed(list(data))
    return {k: list(g) for k, g in itertools.groupby(data, keyfunc)}

groupby_first_letter

groupby_first_letter(
    data: Iterable[T], keyfunc: Callable[..., Any] | None = None
) -> dict[str, list[T]]

Group given iterable by first letter.

Parameters:

Name Type Description Default
data Iterable[T]

Iterable to group

required
keyfunc Callable[..., Any] | None

Optional alternative sort function

None
Source code in src/jinjarope/iterfilters.py
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
def groupby_first_letter(
    data: Iterable[T],
    keyfunc: Callable[..., Any] | None = None,
) -> dict[str, list[T]]:
    """Group given iterable by first letter.

    Args:
        data: Iterable to group
        keyfunc: Optional alternative sort function
    """
    data = sorted(data, key=keyfunc or (lambda x: x))

    def first_letter(x: Any) -> Any:
        return keyfunc(x)[0].upper() if keyfunc else x[0].upper()

    return {k.upper(): list(g) for k, g in itertools.groupby(data, first_letter)}

islice

islice(iterable: Iterable[T], *args: int | None) -> islice[T]

Make an iterator that returns selected elements from the iterable.

If start is non-zero, then elements from the iterable are skipped until start is reached. Afterward, elements are returned consecutively unless step is set higher than one which results in items being skipped. If stop is None, then iteration continues until the iterator is exhausted, if at all; otherwise, it stops at the specified position.

If start is None, then iteration starts at zero. If step is None, then the step defaults to one.

Unlike regular slicing, islice() does not support negative values for start, stop, or step. Can be used to extract related fields from data where the internal structure has been flattened (for example, a multi-line report may list a name field on every third line).

Examples:

islice('ABCDEFG', 2) --> A B
islice('ABCDEFG', 2, 4) --> C D
islice('ABCDEFG', 2, None) --> C D E F G
islice('ABCDEFG', 0, None, 2) --> A C E G

Parameters:

Name Type Description Default
iterable Iterable[T]

Iterable to slice

required
args int | None

Arguments passed to itertools.islice

()
Source code in src/jinjarope/iterfilters.py
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
def islice(iterable: Iterable[T], *args: int | None) -> itertools.islice[T]:
    """Make an iterator that returns selected elements from the iterable.

    If start is non-zero, then elements from the iterable are skipped until start
    is reached. Afterward, elements are returned consecutively unless step is set
    higher than one which results in items being skipped. If stop is None,
    then iteration continues until the iterator is exhausted, if at all;
    otherwise, it stops at the specified position.

    If start is None, then iteration starts at zero. If step is None,
    then the step defaults to one.

    Unlike regular slicing, islice() does not support negative values
    for start, stop, or step. Can be used to extract related fields from data
    where the internal structure has been flattened (for example, a multi-line report
    may list a name field on every third line).

    Examples:
        ``` py
        islice('ABCDEFG', 2) --> A B
        islice('ABCDEFG', 2, 4) --> C D
        islice('ABCDEFG', 2, None) --> C D E F G
        islice('ABCDEFG', 0, None, 2) --> A C E G
        ```

    Args:
        iterable: Iterable to slice
        args: Arguments passed to itertools.islice
    """
    return itertools.islice(iterable, *args)

natsort

natsort(
    val: Iterable[T],
    key: str | Callable[[T], Any] | None = None,
    reverse: bool = False,
    ignore_case: bool = True,
) -> Iterable[T]

Using the natsort package, sort a list naturally.

i.e. A1, B1, A2, A10 will sort A1, A2, A10, B1.

Parameters:

Name Type Description Default
val Iterable[T]

the iterable to sort

required
key str | Callable[[T], Any] | None

If str, sort by attribute with given name. If callable, use it as keygetter. If None, sort by objects itself

None
reverse bool

Whether to reverse the sort order

False
ignore_case bool

Whether to ignore case for sorting

True
Source code in src/jinjarope/iterfilters.py
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
def natsort(
    val: Iterable[T],
    key: str | Callable[[T], Any] | None = None,
    reverse: bool = False,
    ignore_case: bool = True,
) -> Iterable[T]:
    """Using the natsort package, sort a list naturally.

    i.e. A1, B1, A2, A10 will sort A1, A2, A10, B1.

    Args:
        val: the iterable to sort
        key: If str, sort by attribute with given name. If callable, use it as keygetter.
             If None, sort by objects itself
        reverse: Whether to reverse the sort order
        ignore_case: Whether to ignore case for sorting
    """
    from natsort import natsorted, ns

    alg = ns.IGNORECASE
    if not ignore_case:
        alg = ns.LOWERCASEFIRST
    key_fn = operator.attrgetter(key) if isinstance(key, str) else key
    return natsorted(val, key=key_fn, reverse=reverse, alg=alg)

pairwise

pairwise(items: Iterable[T]) -> pairwise[tuple[T, T]]

Return an iterator of overlapping pairs taken from the input iterator.

s -> (s0,s1), (s1,s2), (s2, s3), ...

Parameters:

Name Type Description Default
items Iterable[T]

The items to iter pair-wise

required
Source code in src/jinjarope/iterfilters.py
12
13
14
15
16
17
18
19
20
def pairwise(items: Iterable[T]) -> itertools.pairwise[tuple[T, T]]:
    """Return an iterator of overlapping pairs taken from the input iterator.

    s -> (s0,s1), (s1,s2), (s2, s3), ...

    Args:
        items: The items to iter pair-wise
    """
    return itertools.pairwise(items)

product

product(*iterables: Iterable[Any], repeat: int = 1) -> product[tuple[Any, ...]]

Cartesian product of input iterables.

Roughly equivalent to nested for-loops in a generator expression. For example, product(A, B) returns the same as ((x,y) for x in A for y in B).

The nested loops cycle like an odometer with the rightmost element advancing on every iteration. This pattern creates a lexicographic ordering so that if the input's iterables are sorted, the product tuples are emitted in sorted order.

To compute the product of an iterable with itself, specify the number of repetitions with the optional repeat keyword argument. For example, product(A, repeat=4) means the same as product(A, A, A, A).

Examples:

product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111

Parameters:

Name Type Description Default
iterables Iterable[Any]

The iterables to create a cartesian product from

()
repeat int

The amount of repititions

1
Source code in src/jinjarope/iterfilters.py
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
def product(
    *iterables: Iterable[Any],
    repeat: int = 1,
) -> itertools.product[tuple[Any, ...]]:
    """Cartesian product of input iterables.

    Roughly equivalent to nested for-loops in a generator expression.
    For example, product(A, B) returns the same as ((x,y) for x in A for y in B).

    The nested loops cycle like an odometer with the rightmost element advancing
    on every iteration. This pattern creates a lexicographic ordering so that if
    the input's iterables are sorted, the product tuples are emitted in sorted order.

    To compute the product of an iterable with itself, specify the number of repetitions
    with the optional repeat keyword argument. For example, product(A, repeat=4)
    means the same as product(A, A, A, A).

    Examples:
        ``` py
        product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
        product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
        ```

    Args:
        iterables: The iterables to create a cartesian product from
        repeat: The amount of repititions
    """
    return itertools.product(*iterables, repeat=repeat)

reduce_list

reduce_list(items: Iterable[T]) -> list[T]

Reduce duplicate items in a list and preserve order.

Parameters:

Name Type Description Default
items Iterable[T]

The iterable to recude to a unique-item list

required
Source code in src/jinjarope/iterfilters.py
148
149
150
151
152
153
154
def reduce_list(items: Iterable[T]) -> list[T]:
    """Reduce duplicate items in a list and preserve order.

    Args:
        items: The iterable to recude to a unique-item list
    """
    return list(dict.fromkeys(items))

repeat

repeat(obj: T, times: int | None = None) -> Iterable[T]

Make an iterator that returns object over and over again.

Runs indefinitely unless the times argument is specified.

Examples:

repeat(10, 3) --> 10 10 10

Parameters:

Name Type Description Default
obj T

The object to return over and over again

required
times int | None

The amount of times to return the object (None means infinite)

None
Source code in src/jinjarope/iterfilters.py
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
def repeat(obj: T, times: int | None = None) -> Iterable[T]:
    """Make an iterator that returns object over and over again.

    Runs indefinitely unless the times argument is specified.

    Examples:
        ``` py
        repeat(10, 3) --> 10 10 10
        ```

    Args:
        obj: The object to return over and over again
        times: The amount of times to return the object (None means infinite)
    """
    if times:
        return itertools.repeat(obj, times=times)
    return itertools.repeat(obj)

zip_longest

zip_longest(*iterables: Iterable[Any], fillvalue: Any = None) -> Iterable[Any]

Make an iterator that aggregates elements from each of the iterables.

If the iterables are of uneven length, missing values are filled-in with fillvalue. Iteration continues until the longest iterable is exhausted.

Examples:

zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-

Parameters:

Name Type Description Default
iterables Iterable[Any]

The iterables to zip

()
fillvalue Any

value to use for filling in case the iterables are of uneven length

None
Source code in src/jinjarope/iterfilters.py
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
def zip_longest(*iterables: Iterable[Any], fillvalue: Any = None) -> Iterable[Any]:
    """Make an iterator that aggregates elements from each of the iterables.

    If the iterables are of uneven length, missing values are filled-in with fillvalue.
    Iteration continues until the longest iterable is exhausted.

    Examples:
        ``` py
        zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-
        ```

    Args:
        iterables: The iterables to zip
        fillvalue: value to use for filling in case the iterables are of uneven length
    """
    return itertools.zip_longest(*iterables, fillvalue)