from typing import Any, List, Sequence, TypeVar T = TypeVar("T") def _whole(value: Any) -> bool: # bool is an int in Python; True would otherwise chunk by 1. return isinstance(value, int) and not isinstance(value, bool) def chunk(items: Sequence[T], size: int) -> List[List[T]]: """Split ``items`` into consecutive batches of at most ``size``, in order. An empty list gives no batches rather than one empty batch, so a loop over the result never sends an empty request. A size below 1 raises: it is always a bug upstream, and "no limit" is the outage batching prevents. """ if isinstance(items, (str, bytes)) or not isinstance(items, (list, tuple)): raise TypeError("chunk needs a list of items") if not _whole(size): raise TypeError("size must be a whole number, received %r" % (size,)) if size < 1: raise ValueError("size must be at least 1, received %d" % (size,)) return [list(items[start : start + size]) for start in range(0, len(items), size)]