22
33import itertools
44import re
5- from collections .abc import Mapping
5+ from collections .abc import Iterable , Iterator , Mapping
66from dataclasses import dataclass
77from datetime import timedelta
8- from typing import Literal , cast
8+ from typing import Literal , TypeVar , cast
99
1010Compression = Literal ["zstd" ]
1111
@@ -92,7 +92,7 @@ def parse_timedelta(delta: str) -> timedelta:
9292 words = TIME_SPLIT .findall (delta )
9393 seconds = 0
9494
95- for num , unit in itertools . batched (words , n = 2 , strict = True ):
95+ for num , unit in itertools_batched (words , n = 2 , strict = True ):
9696 num = int (num )
9797 multiplier = 0
9898
@@ -110,3 +110,28 @@ def parse_timedelta(delta: str) -> timedelta:
110110 seconds += num * multiplier
111111
112112 return timedelta (seconds = seconds )
113+
114+
115+ T = TypeVar ("T" )
116+
117+
118+ def itertools_batched (
119+ iterable : Iterable [T ], n : int , strict : bool = False
120+ ) -> Iterator [tuple [T , ...]]:
121+ """
122+ Vendored version of `itertools.batched`, not available in Python 3.11.
123+ Batch data from the iterable into tuples of length n.
124+ The last batch may be shorter than n.
125+ If strict is true, will raise a ValueError if the final batch is shorter than n.
126+ Loops over the input iterable and accumulates data into tuples up to size n.
127+ The input is consumed lazily, just enough to fill a batch.
128+ The result is yielded as soon as the batch is full
129+ or when the input iterable is exhausted:
130+ """
131+ if n < 1 :
132+ raise ValueError ("n must be at least one" )
133+ iterator = iter (iterable )
134+ while batch := tuple (itertools .islice (iterator , n )):
135+ if strict and len (batch ) < n :
136+ raise ValueError ("final batch is shorter than n" )
137+ yield batch
0 commit comments