One function

backoff_iter in mahmoud/boltons

The author described this change as fix: backoff_iter with factor=1.0 and no count raised ZeroDivisionError. It counts as a record because the check below fails on the code as it stood at 57cb026b7 and passes on ead236e27, with nothing else changed between the two runs.

Fix saved2026-07-18
Sharing licenceBSD-2-Clause · LICENSE
Change size+8 2

What the code was meant to do, written into the code itself as a docstring

Generates a sequence of geometrically-increasing floats, suitable for usage with `exponential backoff`_. Starts with *start*, increasing by *factor* until *stop* is reached, optionally stopping iteration once *count* numbers are yielded. *factor* defaults to 2. In general retrying with properly-configured backoff creates a better-behaved component for a larger service ecosystem. .. _exponential backoff: https://en.wikipedia.org/wiki/Exponential_backoff A simplified usage example: .. code-block:: python for timeout in backoff_iter(0.25, 5.0): try: res = network_call() break except Exception as e: log(e) time.sleep(timeout) An enhancement for large-scale systems would be to add variation, or *jitter*, to timeout values. This is done to avoid a thundering herd on the receiving end of the network call. Finally, for *count*, the special value `'repeat'` can be passed to continue yielding indefinitely. Args: start (float): Positive number for baseline. stop (float): Positive number for maximum. count (int): Number of steps before stopping iteration. Defaults to the number of steps between *start* and *stop*. Pass the string, `'repeat'`, to continue iteration indefinitely. factor (float): Rate of exponential increase. Defaults to `2.0`, e.g., `[1, 2, 4, 8, 16]`. jitter (float): A factor between `-1.0` and `1.0`, used to uniformly randomize and thus spread out timeouts in a distributed system, avoiding rhythm effects. Positive values use the base backoff curve as a maximum, negative values use the curve as a minimum. Set to 1.0 or `True` for a jitter approximating Ethernet's time-tested backoff solution. Defaults to `False`.

The change

6666 raise ValueError('expected stop >= start, not %r' % stop)
6767 if count is None:
6868 denom = start if start else 1
69- count = 1 + math.ceil(math.log(stop/denom, factor))
70- count = count if start else count + 1
69+ if factor == 1.0:
70+ if start != stop:
71+ raise ValueError('expected factor > 1.0 when count is None'
72+ ' and start != stop, not %r' % factor)
73+ count = 1
74+ else:
75+ count = 1 + math.ceil(math.log(stop/denom, factor))
76+ count = count if start else count + 1
7177 if count != 'repeat' and count < 0:
7278 raise ValueError('count must be positive or "repeat", not %r' % count)
7379 if jitter:

The check that tells the two apart

failpass·tests/test_iterutils.py::test_backoff_constant_factor

Check file tests/test_iterutils.py, taken without changes from the fix and copied onto the older code, so the exact same check runs against both versions.

Origin and history

The code before it57cb026b7f47cd2765a0d5acdc83849ed5f1f6a3
Broken version dated2026-07-17
Moduleboltons.iterutils
Units changedbackoff_iter
Fingerprintcc318b27b9040117
Checked2026-08-18 by goldset/0.1

Every field above is generated by our program. None of it is written by hand.

Other bugs found in mahmoud/boltons